[cairo-commit] 68 commits - boilerplate/cairo-boilerplate.c boilerplate/cairo-boilerplate-svg.c .gitignore .gitlab-ci.yml src/cairo-image-info.c src/cairo-image-info-private.h src/cairo-recording-surface.c src/cairo-svg-surface.c src/cairo-svg-surface-private.h test/bug-361.c test/bug-431.c test/cairo-test-runner.c test/Makefile.sources test/meson.build test/operator-www.c test/record-transform-paint.c test/reference test/shifted-operator.c

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Sun May 30 10:38:13 UTC 2021


 .gitignore                                                       |    3 
 .gitlab-ci.yml                                                   |   66 
 boilerplate/cairo-boilerplate-svg.c                              |   63 
 boilerplate/cairo-boilerplate.c                                  |   12 
 dev/null                                                         |binary
 src/cairo-image-info-private.h                                   |    2 
 src/cairo-image-info.c                                           |    2 
 src/cairo-recording-surface.c                                    |    4 
 src/cairo-svg-surface-private.h                                  |   40 
 src/cairo-svg-surface.c                                          | 4059 ++++++----
 test/Makefile.sources                                            |    5 
 test/bug-361.c                                                   |  111 
 test/bug-431.c                                                   |   64 
 test/cairo-test-runner.c                                         |   61 
 test/meson.build                                                 |    5 
 test/operator-www.c                                              |  179 
 test/record-transform-paint.c                                    |   64 
 test/reference/arc-looping-dash.svg.ref.png                      |binary
 test/reference/bug-361.image16.rgb24.ref.png                     |binary
 test/reference/bug-361.ref.png                                   |binary
 test/reference/bug-361.xcb-window&.rgb24.ref.png                 |binary
 test/reference/bug-361.xcb-window.rgb24.ref.png                  |binary
 test/reference/bug-361.xcb.argb32.ref.png                        |binary
 test/reference/bug-361.xcb.rgb24.ref.png                         |binary
 test/reference/bug-361.xlib-window.rgb24.ref.png                 |binary
 test/reference/bug-361.xlib.argb32.ref.png                       |binary
 test/reference/bug-361.xlib.rgb24.ref.png                        |binary
 test/reference/bug-431.image16.rgb24.ref.png                     |binary
 test/reference/bug-431.pdf.ref.png                               |binary
 test/reference/bug-431.pdf.rgb24.ref.png                         |binary
 test/reference/bug-431.ref.png                                   |binary
 test/reference/bug-431.svg.rgb24.ref.png                         |binary
 test/reference/bug-431.xlib-window.rgb24.ref.png                 |binary
 test/reference/bug-431.xlib.rgb24.ref.png                        |binary
 test/reference/bug-51910.svg.ref.png                             |binary
 test/reference/bug-84115.svg.ref.png                             |binary
 test/reference/bug-bo-ricotz.svg.rgb24.ref.png                   |binary
 test/reference/bug-image-compositor.svg.ref.png                  |binary
 test/reference/caps-05.svg.ref.png                               |binary
 test/reference/caps-1.svg.ref.png                                |binary
 test/reference/caps-2.svg.ref.png                                |binary
 test/reference/caps-joins-05.svg.ref.png                         |binary
 test/reference/caps-joins-1.svg.ref.png                          |binary
 test/reference/caps-joins-2.svg.ref.png                          |binary
 test/reference/caps-joins-curve.svg.ref.png                      |binary
 test/reference/caps-sub-paths.svg.ref.png                        |binary
 test/reference/caps-tails-curve.svg.ref.png                      |binary
 test/reference/caps.svg.ref.png                                  |binary
 test/reference/checkerboard.svg.ref.png                          |binary
 test/reference/clip-complex-bug61592.svg.ref.png                 |binary
 test/reference/clip-disjoint-quad.svg.ref.png                    |binary
 test/reference/clip-fill-eo-unbounded.svg.ref.png                |binary
 test/reference/clip-fill-nz-unbounded.svg.ref.png                |binary
 test/reference/clip-image.svg.ref.png                            |binary
 test/reference/clip-push-group.svg.ref.png                       |binary
 test/reference/clip-rotate-image-surface-paint.svg.ref.png       |binary
 test/reference/clip-stroke-unbounded.svg.ref.png                 |binary
 test/reference/clipped-group.svg.ref.png                         |binary
 test/reference/close-path-current-point.svg.ref.png              |binary
 test/reference/close-path.svg.ref.png                            |binary
 test/reference/copy-path.svg.ref.png                             |binary
 test/reference/dash-caps-joins.svg.ref.png                       |binary
 test/reference/dash-curve.svg.ref.png                            |binary
 test/reference/dash-infinite-loop.svg.ref.png                    |binary
 test/reference/dash-scale.svg.ref.png                            |binary
 test/reference/dash-state.svg.ref.png                            |binary
 test/reference/dash-zero-length.svg.ref.png                      |binary
 test/reference/degenerate-arcs.svg.ref.png                       |binary
 test/reference/degenerate-curve-to.svg.ref.png                   |binary
 test/reference/degenerate-linear-gradient.svg.ref.png            |binary
 test/reference/degenerate-path.svg.ref.png                       |binary
 test/reference/degenerate-pen.svg.ref.png                        |binary
 test/reference/degenerate-radial-gradient.svg.ref.png            |binary
 test/reference/degenerate-rel-curve-to.svg.ref.png               |binary
 test/reference/device-offset-fractional.svg.ref.png              |binary
 test/reference/extend-pad-border.svg.ref.png                     |binary
 test/reference/fallback-resolution.ppi144x144.pdf.ref.png        |binary
 test/reference/fallback-resolution.ppi144x144.svg.ref.png        |binary
 test/reference/fallback-resolution.ppi144x72.pdf.ref.png         |binary
 test/reference/fallback-resolution.ppi144x72.svg.ref.png         |binary
 test/reference/fallback-resolution.ppi288x288.pdf.ref.png        |binary
 test/reference/fallback-resolution.ppi288x288.svg.ref.png        |binary
 test/reference/fallback-resolution.ppi288x72.pdf.ref.png         |binary
 test/reference/fallback-resolution.ppi288x72.svg.ref.png         |binary
 test/reference/fallback-resolution.ppi576x576.pdf.ref.png        |binary
 test/reference/fallback-resolution.ppi576x576.svg.ref.png        |binary
 test/reference/fallback-resolution.ppi576x72.pdf.ref.png         |binary
 test/reference/fallback-resolution.ppi576x72.svg.ref.png         |binary
 test/reference/fallback-resolution.ppi72x144.pdf.ref.png         |binary
 test/reference/fallback-resolution.ppi72x144.svg.ref.png         |binary
 test/reference/fallback-resolution.ppi72x288.pdf.ref.png         |binary
 test/reference/fallback-resolution.ppi72x288.svg.ref.png         |binary
 test/reference/fallback-resolution.ppi72x576.pdf.ref.png         |binary
 test/reference/fallback-resolution.ppi72x576.svg.ref.png         |binary
 test/reference/fallback-resolution.ppi72x72.pdf.ref.png          |binary
 test/reference/fallback-resolution.ppi72x72.svg.ref.png          |binary
 test/reference/fallback.svg.ref.png                              |binary
 test/reference/fallback.svg.rgb24.ref.png                        |binary
 test/reference/fill-and-stroke-alpha-add.svg.ref.png             |binary
 test/reference/fill-and-stroke-alpha.svg.ref.png                 |binary
 test/reference/fill-and-stroke.svg.ref.png                       |binary
 test/reference/fill-missed-stop.svg.ref.png                      |binary
 test/reference/finer-grained-fallbacks.svg.ref.png               |binary
 test/reference/font-matrix-translation.svg.ref.png               |binary
 test/reference/ft-show-glyphs-table.svg.ref.png                  |binary
 test/reference/glyph-cache-pressure.svg.ref.png                  |binary
 test/reference/gradient-alpha.svg.ref.png                        |binary
 test/reference/gradient-constant-alpha.svg.ref.png               |binary
 test/reference/group-unaligned.svg.ref.png                       |binary
 test/reference/halo.svg.ref.png                                  |binary
 test/reference/huge-radial.svg.ref.png                           |binary
 test/reference/infinite-join.svg.ref.png                         |binary
 test/reference/inverse-text.svg.ref.png                          |binary
 test/reference/joins.svg.ref.png                                 |binary
 test/reference/large-font.svg.ref.png                            |binary
 test/reference/leaky-dashed-stroke.svg.ref.png                   |binary
 test/reference/leaky-polygon.svg.ref.png                         |binary
 test/reference/line-width-scale.svg.ref.png                      |binary
 test/reference/line-width-tolerance.svg.ref.png                  |binary
 test/reference/linear-gradient-extend.svg.ref.png                |binary
 test/reference/linear-gradient-subset.svg.ref.png                |binary
 test/reference/linear-gradient.svg.ref.png                       |binary
 test/reference/long-dashed-lines.svg.ref.png                     |binary
 test/reference/mask-transformed-image.svg.ref.png                |binary
 test/reference/mask-transformed-similar.svg.ref.png              |binary
 test/reference/mask.svg.ref.png                                  |binary
 test/reference/mesh-pattern-conical.svg.ref.png                  |binary
 test/reference/mesh-pattern-control-points.svg.ref.png           |binary
 test/reference/mesh-pattern-fold.svg.ref.png                     |binary
 test/reference/mesh-pattern-overlap.svg.ref.png                  |binary
 test/reference/mesh-pattern-transformed.svg.ref.png              |binary
 test/reference/mesh-pattern.svg.ref.png                          |binary
 test/reference/new-sub-path.svg.ref.png                          |binary
 test/reference/operator-clear.svg.ref.png                        |binary
 test/reference/operator-source.svg.ref.png                       |binary
 test/reference/operator-www.image16.rgb24.ref.png                |binary
 test/reference/operator-www.pdf.ref.png                          |binary
 test/reference/operator-www.ref.png                              |binary
 test/reference/operator-www.rgb24.ref.png                        |binary
 test/reference/operator-www.svg.ref.png                          |binary
 test/reference/operator-www.svg.rgb24.ref.png                    |binary
 test/reference/paint-with-alpha-solid-clip.svg.ref.png           |binary
 test/reference/partial-clip-text-bottom.svg.ref.png              |binary
 test/reference/partial-clip-text-left.svg.ref.png                |binary
 test/reference/partial-clip-text-right.svg.ref.png               |binary
 test/reference/partial-clip-text-top.svg.ref.png                 |binary
 test/reference/path-stroke-twice.svg.ref.png                     |binary
 test/reference/pixman-downscale-best-24.svg.ref.png              |binary
 test/reference/pixman-downscale-bilinear-24.svg.ref.png          |binary
 test/reference/pixman-downscale-fast-24.svg.ref.png              |binary
 test/reference/pixman-downscale-good-24.svg.ref.png              |binary
 test/reference/pixman-downscale-nearest-24.svg.ref.png           |binary
 test/reference/pixman-rotate.svg.ref.png                         |binary
 test/reference/pthread-same-source.svg.ref.png                   |binary
 test/reference/pthread-show-text.svg.ref.png                     |binary
 test/reference/pthread-similar.svg.ref.png                       |binary
 test/reference/push-group-color.svg.ref.png                      |binary
 test/reference/push-group.svg.ref.png                            |binary
 test/reference/radial-gradient-extend.svg.ref.png                |binary
 test/reference/radial-gradient-mask-source.svg.ref.png           |binary
 test/reference/radial-gradient-mask.svg.ref.png                  |binary
 test/reference/radial-gradient-one-stop.svg.ref.png              |binary
 test/reference/radial-gradient-source.ref.png                    |binary
 test/reference/radial-gradient-source.svg.ref.png                |binary
 test/reference/radial-gradient.svg.ref.png                       |binary
 test/reference/record-fill-alpha.svg.ref.png                     |binary
 test/reference/record-mesh.svg.ref.png                           |binary
 test/reference/record-neg-extents-bounded.svg.ref.png            |binary
 test/reference/record-neg-extents-unbounded.svg.ref.png          |binary
 test/reference/record-paint-alpha-solid-clip.svg.ref.png         |binary
 test/reference/record-replay-extend-pad.svg.ref.png              |binary
 test/reference/record-replay-extend-reflect.svg.ref.png          |binary
 test/reference/record-replay-extend-repeat.svg.ref.png           |binary
 test/reference/record-replay-extend-repeat.svg.rgb24.ref.png     |binary
 test/reference/record-select-font-face.svg.ref.png               |binary
 test/reference/record-text-transform.svg.ref.png                 |binary
 test/reference/record-transform-paint.image16.rgb24.ref.png      |binary
 test/reference/record-transform-paint.pdf.ref.png                |binary
 test/reference/record-transform-paint.ref.png                    |binary
 test/reference/record1414x-fill-alpha.svg.ref.png                |binary
 test/reference/record1414x-paint-alpha-solid-clip.svg.ref.png    |binary
 test/reference/record1414x-paint.svg.ref.png                     |binary
 test/reference/record1414x-self-intersecting.svg.ref.png         |binary
 test/reference/record2x-fill-alpha.svg.ref.png                   |binary
 test/reference/record2x-paint-alpha-solid-clip.svg.ref.png       |binary
 test/reference/record2x-select-font-face.svg.ref.png             |binary
 test/reference/record2x-text-transform.svg.ref.png               |binary
 test/reference/record90-fill-alpha.svg.ref.png                   |binary
 test/reference/record90-paint-alpha-solid-clip.svg.ref.png       |binary
 test/reference/record90-select-font-face.svg.ref.png             |binary
 test/reference/record90-self-intersecting.svg.ref.png            |binary
 test/reference/record90-text-transform.svg.ref.png               |binary
 test/reference/recordflip-fill-alpha.svg.ref.png                 |binary
 test/reference/recordflip-select-font-face.svg.ref.png           |binary
 test/reference/recordflip-text-transform.svg.ref.png             |binary
 test/reference/recordflip-whole-select-font-face.svg.ref.png     |binary
 test/reference/recordflip-whole-text-transform.svg.ref.png       |binary
 test/reference/recording-surface-extend-none.svg.ref.png         |binary
 test/reference/recording-surface-extend-reflect.svg.ref.png      |binary
 test/reference/recording-surface-extend-repeat.svg.ref.png       |binary
 test/reference/recording-surface-extend-repeat.svg.rgb24.ref.png |binary
 test/reference/recording-surface-over.svg.ref.png                |binary
 test/reference/recording-surface-source.svg.ref.png              |binary
 test/reference/rectilinear-dash-scale-unaligned.svg.ref.png      |binary
 test/reference/rectilinear-dash-scale.svg.ref.png                |binary
 test/reference/rectilinear-miter-limit.svg.ref.png               |binary
 test/reference/reflected-stroke.svg.ref.png                      |binary
 test/reference/rel-path.svg.ref.png                              |binary
 test/reference/rotate-clip-image-surface-paint.svg.ref.png       |binary
 test/reference/rotate-image-surface-paint.svg.ref.png            |binary
 test/reference/scale-offset-similar.svg.ref.png                  |binary
 test/reference/select-font-face.svg.ref.png                      |binary
 test/reference/set-source.svg.ref.png                            |binary
 test/reference/shape-sierpinski.svg.ref.png                      |binary
 test/reference/shifted-operator.ref.png                          |binary
 test/reference/shifted-operator.rgb24.ref.png                    |binary
 test/reference/show-text-current-point.svg.ref.png               |binary
 test/reference/smask-fill.svg.ref.png                            |binary
 test/reference/smask-image-mask.svg.ref.png                      |binary
 test/reference/smask-mask.svg.ref.png                            |binary
 test/reference/smask-paint.svg.ref.png                           |binary
 test/reference/smask-stroke.svg.ref.png                          |binary
 test/reference/smask-text.svg.ref.png                            |binary
 test/reference/smask.svg.ref.png                                 |binary
 test/reference/smp-glyph.svg.ref.png                             |binary
 test/reference/spline-decomposition.svg.ref.png                  |binary
 test/reference/stroke-ctm-caps.svg.ref.png                       |binary
 test/reference/stroke-pattern.svg.ref.png                        |binary
 test/reference/surface-pattern-scale-down.svg.ref.png            |binary
 test/reference/text-glyph-range.svg.ref.png                      |binary
 test/reference/text-transform.svg.ref.png                        |binary
 test/reference/tiger.svg.ref.png                                 |binary
 test/reference/transforms.svg.ref.png                            |binary
 test/reference/trap-clip.svg.ref.png                             |binary
 test/reference/twin.svg.ref.png                                  |binary
 test/reference/unclosed-strokes.svg.ref.png                      |binary
 test/reference/user-font-mask.svg.ref.png                        |binary
 test/reference/user-font-proxy.svg.ref.png                       |binary
 test/reference/user-font-rescale.svg.ref.png                     |binary
 test/reference/user-font.svg.ref.png                             |binary
 test/reference/world-map-fill.svg.ref.png                        |binary
 test/reference/world-map-stroke.svg.ref.png                      |binary
 test/reference/world-map.svg.ref.png                             |binary
 test/shifted-operator.c                                          |   58 
 244 files changed, 3252 insertions(+), 1546 deletions(-)

New commits:
commit 5ae89cf30ed8bf162a64d9626a105f4ec68265c1
Merge: 63f0d6268 9ab52c913
Author: Uli Schlachter <psychon at znc.in>
Date:   Sun May 30 10:38:09 2021 +0000

    Merge branch 'svg-backend-work' into 'master'
    
    Work on the SVG backend
    
    Closes #361, #431, #78, #4, poppler/poppler#761, poppler/poppler#619, #107, poppler/poppler#268, #73, and #478
    
    See merge request cairo/cairo!152

commit 9ab52c9131767486700e286a7732dab1ed2e48d5
Merge: ec2cf9ac3 63f0d6268
Author: afdw <afdw at yandex.ru>
Date:   Sat May 29 16:21:31 2021 +0000

    Merge branch 'master' into 'svg-backend-work'
    
    # Conflicts:
    #   .gitlab-ci.yml
    #   test/Makefile.sources
    #   test/meson.build

diff --cc .gitlab-ci.yml
index 8cd2e610c,ee44355fd..c05529df9
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@@ -278,7 -285,8 +288,7 @@@ meson macOS
      - meson setup -Dpixman:tests=disabled build
      - meson compile --verbose -C build
      # Test cairo-quartz. Other backends should be covered by other jobs
-     - export CAIRO_TEST_IGNORE_quartz_argb32=bug-361,bug-431,bug-image-compositor,clear,clip-operator,clip-text,coverage-rhombus,culled-glyphs,extended-blend-alpha,extended-blend-mask,extended-blend-alpha-mask,extended-blend-solid-alpha,fallback,font-matrix-translation,glyph-cache-pressure,halo,halo-transform,inverse-text,large-font,negative-stride-image,operator-clear,operator-source,operator-www,overlapping-glyphs,partial-clip-text-top,partial-clip-text-bottom,partial-clip-text-left,partial-clip-text-right,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,record-paint-alpha-clip-mask,record-fill-alpha,record-select-font-face,record-text-transform,record1414x-select-font-face,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-select-font-face,record2x-text-transform,record90-fill-alpha,record90-select-font-face,record90-text-transform,recordflip-whole-select-font-face,recordflip-whole-text-transform,recordflip-select-font-face,
 recordflip-text-transform,record-neg-extents-bounded,record-mesh,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,select-font-face,show-glyphs-advance,show-text-current-point,simple-edge,smask,smask-text,smp-glyph,subsurface,subsurface-outside-target,subsurface-scale,surface-pattern,text-antialias-gray,text-antialias-none,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,unbounded-operator,user-font-proxy,user-font-rescale,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3,ft-text-antialias-none
-     - export CAIRO_TEST_IGNORE_quartz_rgb24=bug-361,bug-431,bug-448,bug-image-compositor,clear,clip-operator,clip-text,coverage-rhombus,culled-glyphs,extended-blend,extended-blend-alpha,extended-blend-mask,extended-blend-alpha-mask,extended-blend-solid,extended-blend-solid-alpha,font-matrix-translation,glyph-cache-pressure,halo,halo-transform,inverse-text,large-font,negative-stride-image,operator-clear,operator-source,operator-www,overlapping-glyphs,partial-clip-text-top,partial-clip-text-bottom,partial-clip-text-left,partial-clip-text-right,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,record-paint-alpha-clip-mask,record-fill-alpha,record-select-font-face,record-text-transform,record1414x-select-font-face,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-select-font-face,record2x-text-transform,record90-fill-alpha,record90-select-font-face,record90-text-transform,recordflip-whole-select-font-face,recordflip-whole-text-tran
 sform,recordflip-select-font-face,recordflip-text-transform,record-neg-extents-unbounded,record-neg-extents-bounded,record-mesh,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,select-font-face,shifted-operator,show-glyphs-advance,show-text-current-point,simple-edge,smask,smask-text,smp-glyph,subsurface,subsurface-scale,text-antialias-gray,text-antialias-none,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,unbounded-operator,user-font-proxy,user-font-rescale,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3,ft-text-antialias-none
 -    - export CAIRO_TEST_UGLY_HACK_TO_IGNORE_QUARTZ_COVERAGE_COLUMN_TRIANGLES=1
 -    - export CAIRO_TEST_IGNORE_quartz_argb32=bug-image-compositor,clip-operator,coverage-rhombus,culled-glyphs,extended-blend-alpha,extended-blend-mask,extended-blend-alpha-mask,extended-blend-solid-alpha,fallback,negative-stride-image,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,record-paint-alpha-clip-mask,record-fill-alpha,record-select-font-face,record-text-transform,record1414x-select-font-face,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-select-font-face,record2x-text-transform,record90-fill-alpha,record90-select-font-face,record90-text-transform,recordflip-whole-select-font-face,recordflip-whole-text-transform,recordflip-select-font-face,recordflip-text-transform,record-neg-extents-bounded,record-mesh,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,simple-edge,subsurface,subsurface-outside-target,subsurface-scale,surface-pattern,text-antialias-subpixel,text-antialias-subpixel-r
 gb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-unhinted-metrics,user-font-proxy,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
 -    - export CAIRO_TEST_IGNORE_quartz_rgb24=bug-448,bug-image-compositor,coverage-rhombus,culled-glyphs,extended-blend,extended-blend-alpha,extended-blend-mask,extended-blend-alpha-mask,extended-blend-solid,extended-blend-solid-alpha,negative-stride-image,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,record-paint-alpha-clip-mask,record-fill-alpha,record-select-font-face,record-text-transform,record1414x-select-font-face,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-select-font-face,record2x-text-transform,record90-fill-alpha,record90-select-font-face,record90-text-transform,recordflip-whole-select-font-face,recordflip-whole-text-transform,recordflip-select-font-face,recordflip-text-transform,record-neg-extents-unbounded,record-neg-extents-bounded,record-mesh,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,simple-edge,subsurface,subsurface-scale,text-antialias-subpixel,text-antialias-sub
 pixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-unhinted-metrics,user-font-proxy,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
++    - export CAIRO_TEST_IGNORE_quartz_argb32=bug-361,bug-431,bug-image-compositor,clip-operator,coverage-rhombus,culled-glyphs,extended-blend-alpha,extended-blend-mask,extended-blend-alpha-mask,extended-blend-solid-alpha,fallback,negative-stride-image,operator-www,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,record-paint-alpha-clip-mask,record-fill-alpha,record-select-font-face,record-text-transform,record1414x-select-font-face,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-select-font-face,record2x-text-transform,record90-fill-alpha,record90-select-font-face,record90-text-transform,recordflip-whole-select-font-face,recordflip-whole-text-transform,recordflip-select-font-face,recordflip-text-transform,record-neg-extents-bounded,record-mesh,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,simple-edge,subsurface,subsurface-outside-target,subsurface-scale,surface-pattern,text-antialias-subpi
 xel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-unhinted-metrics,user-font-proxy,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
++    - export CAIRO_TEST_IGNORE_quartz_rgb24=bug-361,bug-431,bug-448,bug-image-compositor,coverage-rhombus,culled-glyphs,extended-blend,extended-blend-alpha,extended-blend-mask,extended-blend-alpha-mask,extended-blend-solid,extended-blend-solid-alpha,negative-stride-image,operator-www,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,record-paint-alpha-clip-mask,record-fill-alpha,record-select-font-face,record-text-transform,record1414x-select-font-face,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-select-font-face,record2x-text-transform,record90-fill-alpha,record90-select-font-face,record90-text-transform,recordflip-whole-select-font-face,recordflip-whole-text-transform,recordflip-select-font-face,recordflip-text-transform,record-neg-extents-unbounded,record-neg-extents-bounded,record-mesh,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,shifted-operator,simple-edge,subsurface,subsurface-sc
 ale,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-unhinted-metrics,user-font-proxy,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
      - export CAIRO_TEST_TARGET=quartz
      - (cd build/test && srcdir=../../test ./cairo-test-suite)
diff --cc test/Makefile.sources
index 0e68ccb7d,6ec9b3da9..493141203
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@@ -282,7 -279,7 +282,8 @@@ test_sources = 
  	record-neg-extents.c                            \
  	record-mesh.c					\
  	record-replay-extend.c                          \
 +	record-transform-paint.c                          \
+ 	record-write-png.c					\
  	recording-ink-extents.c                         \
  	recording-surface-pattern.c			\
  	recording-surface-extend.c			\
diff --cc test/meson.build
index b4562adb8,70082f94a..143d2f09c
--- a/test/meson.build
+++ b/test/meson.build
@@@ -282,7 -279,7 +282,8 @@@ test_sources = 
    'record-neg-extents.c',
    'record-mesh.c',
    'record-replay-extend.c',
 +  'record-transform-paint.c',
+   'record-write-png.c',
    'recording-ink-extents.c',
    'recording-surface-pattern.c',
    'recording-surface-extend.c',
commit ec2cf9ac35c24495c60fff4e2fd8668bcc9ed612
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sat May 29 18:13:30 2021 +0200

    Ignore build instead of builddir

diff --git a/.gitignore b/.gitignore
index 23017d16f..794b542e2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,4 +38,4 @@ compile_commands.json
 *-uninstalled.pc
 .vimrc
 gtk-doc.m4
-/build
+/builddir
commit 1e27ca7d453099adcfa9e31966eee42a2a26b604
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sat May 29 18:04:45 2021 +0200

    Remove unused _cairo_hash_table_size

diff --git a/src/cairo-hash-private.h b/src/cairo-hash-private.h
index b30126b20..30e51ffe6 100644
--- a/src/cairo-hash-private.h
+++ b/src/cairo-hash-private.h
@@ -84,7 +84,4 @@ _cairo_hash_table_foreach (cairo_hash_table_t	      *hash_table,
 			   cairo_hash_callback_func_t  hash_callback,
 			   void			      *closure);
 
-cairo_private unsigned long
-_cairo_hash_table_size (cairo_hash_table_t *hash_table);
-
 #endif
diff --git a/src/cairo-hash.c b/src/cairo-hash.c
index 6dc978bd4..151842eb6 100644
--- a/src/cairo-hash.c
+++ b/src/cairo-hash.c
@@ -576,17 +576,3 @@ _cairo_hash_table_foreach (cairo_hash_table_t	      *hash_table,
 	_cairo_hash_table_manage (hash_table);
     }
 }
-
-/**
- * _cairo_hash_table_size:
- * @hash_table: a hash table
- *
- * Gets the size of the hash table.
- *
- * Return value: the size of the hash table.
- **/
-unsigned long
-_cairo_hash_table_size (cairo_hash_table_t *hash_table)
-{
-    return hash_table->live_entries;
-}
commit c2bf6e8ae418debc97b0ca65b7e452fc650d4655
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Mon May 3 23:41:41 2021 +0200

    Fix remaining tests

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 67c93ad7b..8cd2e610c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -7,8 +7,8 @@ include:
 
 variables:
   FDO_UPSTREAM_REPO: 'cairo/cairo'
-  FDO_DISTRIBUTION_VERSION: '32'
-  FDO_DISTRIBUTION_TAG: '2021-04-25.0'
+  FDO_DISTRIBUTION_VERSION: '34'
+  FDO_DISTRIBUTION_TAG: '2021-05-04.2'
 
   # TODO: should probably get its own image at some point instead of reusing the GStreamer one.
   WINDOWS_IMAGE:             "registry.freedesktop.org/gstreamer/gst-ci/amd64/windows:v16-master"
@@ -82,6 +82,7 @@ fedora image:
       mesa-libgbm
       mesa-libgbm-devel
       mesa-libglapi
+      expat-devel
       autoconf
       automake
       make
@@ -89,6 +90,9 @@ fedora image:
       libtool
       diffutils
       xorg-x11-server-Xvfb
+      dejavu-sans-fonts
+      dejavu-sans-mono-fonts
+      dejavu-serif-fonts
 
 fedora autotools build:
   extends:
@@ -98,35 +102,34 @@ fedora autotools build:
   script:
     - ./autogen.sh
     # Current test failures that we ignore for now
-    - export CAIRO_TEST_UGLY_HACK_TO_IGNORE_FALLBACK_RESOLUTION=1
-    - export CAIRO_TEST_UGLY_HACK_TO_IGNORE_SCRIPT_XCB_HUGE_IMAGE_SHM=1
-    - export CAIRO_TEST_UGLY_HACK_TO_IGNORE_SVG_ARGB32_SELF_COPIES=1
+    - export CAIRO_TEST_UGLY_HACK_TO_SOMETIMES_IGNORE_SCRIPT_XCB_HUGE_IMAGE_SHM=1
     - export CAIRO_TEST_UGLY_HACK_TO_IGNORE_CREATE_FOR_STREAM=1
-    - export CAIRO_TEST_IGNORE_pdf_argb32=bug-image-compositor,clear-source,clip-operator,clip-text,culled-glyphs,extended-blend,extended-blend-solid,fallback,filter-bilinear-extents,filter-nearest-offset,filter-nearest-transformed,font-matrix-translation,glyph-cache-pressure,halo,halo-transform,inverse-text,large-font,linear-gradient-reflect,mask,operator-alpha-alpha,overlapping-glyphs,paint-with-alpha-clip,partial-clip-text-bottom,partial-clip-text-left,pixman-downscale-fast-95,pixman-downscale-fast-24,pixman-downscale-good-24,pixman-downscale-best-95,pixman-downscale-best-24,pixman-downscale-nearest-95,pixman-downscale-nearest-24,pixman-downscale-bilinear-24,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,radial-gradient-one-stop,record-select-font-face,record1414x-select-font-face,record1414x-text-transform,record2x-select-font-face,record2x-text-transform,record90-select-font-face,recordflip-whole-select-font-face,recordflip-select-font-f
 ace,record-replay-extend-repeat,record-replay-extend-reflect,recording-surface-over,recording-surface-extend-repeat,recording-surface-extend-reflect,rectilinear-miter-limit,rectilinear-dash,rectilinear-stroke,rotate-image-surface-paint,rotate-clip-image-surface-paint,select-font-face,self-copy,show-glyphs-advance,show-text-current-point,smask-text,smp-glyph,surface-pattern,surface-pattern-operator,surface-pattern-scale-down,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,thin-lines,trap-clip,twin,user-font-proxy,user-font-rescale,pthread-same-source,pthread-show-text,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
+    - export CAIRO_TEST_IGNORE_pdf_argb32=bug-image-compositor,clear-source,clip-operator,clip-text,culled-glyphs,extended-blend,extended-blend-solid,fallback,filter-bilinear-extents,filter-nearest-offset,filter-nearest-transformed,font-matrix-translation,glyph-cache-pressure,halo,halo-transform,inverse-text,large-font,linear-gradient-reflect,mask,operator-alpha-alpha,overlapping-glyphs,paint-with-alpha-clip,partial-clip-text-bottom,partial-clip-text-left,pixman-downscale-fast-95,pixman-downscale-fast-24,pixman-downscale-good-24,pixman-downscale-best-95,pixman-downscale-best-24,pixman-downscale-nearest-95,pixman-downscale-nearest-24,pixman-downscale-bilinear-24,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,radial-gradient-one-stop,record1414x-select-font-face,record1414x-text-transform,record2x-text-transform,record-replay-extend-repeat,record-replay-extend-reflect,recording-surface-over,recording-surface-extend-repeat,recording-surface-exte
 nd-reflect,rectilinear-miter-limit,rectilinear-dash,rectilinear-stroke,rotate-image-surface-paint,rotate-clip-image-surface-paint,select-font-face,self-copy,show-glyphs-advance,show-text-current-point,smask-text,smp-glyph,surface-pattern,surface-pattern-operator,surface-pattern-scale-down,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,thin-lines,trap-clip,twin,user-font-proxy,user-font-rescale,pthread-same-source,pthread-show-text,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
     - export CAIRO_TEST_IGNORE_pdf_rgb24=bug-image-compositor,clear-source,clip-text,culled-glyphs,extended-blend-alpha-mask,extended-blend-solid,filter-bilinear-extents,filter-nearest-offset,filter-nearest-transformed,font-matrix-translation,glyph-cache-pressure,halo,halo-transform,inverse-text,large-font,linear-gradient-reflect,mask,operator-alpha-alpha,overlapping-glyphs,paint-with-alpha-clip,partial-clip-text-bottom,partial-clip-text-left,pixman-downscale-fast-95,pixman-downscale-fast-24,pixman-downscale-good-24,pixman-downscale-best-95,pixman-downscale-best-24,pixman-downscale-nearest-95,pixman-downscale-nearest-24,pixman-downscale-bilinear-24,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,radial-gradient-one-stop,random-intersections-curves-eo,random-intersections-curves-nz,record-paint-alpha-clip,record-select-font-face,record-text-transform,record1414x-paint-alpha,record1414x-paint-alpha-clip,record1414x-paint-alpha-clip-mask,record14
 14x-select-font-face,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-select-font-face,record2x-text-transform,record90-paint-alpha-clip,record90-paint-alpha-clip-mask,record90-select-font-face,record90-text-transform,recordflip-whole-select-font-face,recordflip-whole-self-intersecting,recordflip-whole-text-transform,recordflip-select-font-face,recordflip-text-transform,record-replay-extend-repeat,record-replay-extend-reflect,recording-surface-over,recording-surface-extend-repeat,rectilinear-miter-limit,rectilinear-dash,rectilinear-stroke,rel-path,rotate-image-surface-paint,rotate-clip-image-surface-paint,select-font-face,self-copy,show-glyphs-advance,show-text-current-point,smask-text,smp-glyph,surface-pattern,surface-pattern-scale-down,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,trap-clip,twin,user-font-proxy,user-font-rescale,pthread-same-source,pthread-show-text,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-
 layout-type1,ft-text-vertical-layout-type3
-    - export CAIRO_TEST_IGNORE_script_argb32=xcb-huge-image-shm
-    - export CAIRO_TEST_IGNORE_script_argb32=a1-bug,a1-fill,arc-looping-dash,bilevel-image,bug-51910,bug-84115,bug-seams,caps,caps-2,caps-1,caps-05,checkerboard,caps-joins-2,caps-joins-1,caps-joins-05,caps-joins-curve,caps-tails-curve,caps-sub-paths,clear-source,clip-disjoint-quad,clip-device-offset,clip-image,clip-mixed-antialias,clip-push-group,clip-polygons,clip-text,close-path,close-path-current-point,composite-integer-translate-over-repeat,copy-path,coverage-rectangles,coverage-intersecting-quads,coverage-intersecting-triangles,coverage-abutting,culled-glyphs,dash-caps-joins,dash-curve,dash-infinite-loop,dash-scale,dash-state,degenerate-curve-to,degenerate-linear-gradient,degenerate-pen,degenerate-radial-gradient,degenerate-rel-curve-to,device-offset-scale,extend-pad-border,fill-and-stroke-alpha,fill-and-stroke-alpha-add,filter-bilinear-extents,font-matrix-translation,glyph-cache-pressure,halo,halo-transform,huge-radial,image-surface-source,xcb-surface-source,xlib-surface-sourc
 e,infinite-join,inverse-text,joins,large-font,large-source,large-twin-antialias-mixed,leaky-dashed-rectangle,leaky-dashed-stroke,leaky-polygon,line-width-scale,line-width-tolerance,linear-gradient-extend,linear-gradient-reflect,long-dashed-lines,map-all-to-image,map-bit-to-image,map-to-image-fill,mask-transformed-image,mask-transformed-similar,mesh-pattern,mesh-pattern-conical,mesh-pattern-control-points,mesh-pattern-fold,mesh-pattern-overlap,mesh-pattern-transformed,negative-stride-image,operator-alpha-alpha,overlapping-glyphs,paint-source-alpha,paint-with-alpha,paint-with-alpha-solid-clip,paint-with-alpha-clip,partial-clip-text-bottom,partial-clip-text-left,partial-coverage-reference,partial-coverage-three-quarter-reference,partial-coverage-half-reference,path-stroke-twice,push-group-color,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,radial-gradient-one-stop,radial-gradient-extend,record-paint-alpha-solid-clip,record-paint-alpha-clip,reco
 rd-select-font-face,record-text-transform,record1414x-paint-alpha,record1414x-paint-alpha-solid-clip,record1414x-paint-alpha-clip,record1414x-select-font-face,record1414x-text-transform,record2x-paint-alpha,record2x-paint-alpha-solid-clip,record2x-paint-alpha-clip,record2x-select-font-face,record2x-text-transform,record90-paint-alpha-clip-mask,record90-select-font-face,record90-text-transform,recordflip-whole-select-font-face,recordflip-whole-text-transform,recordflip-select-font-face,recordflip-text-transform,record-neg-extents-bounded,record-mesh,record-replay-extend-none,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,rectilinear-miter-limit,reflected-stroke,scale-offset-image,scale-offset-similar,stroke-ctm-caps,select-font-face,self-copy,show-glyphs-advance,show-text-current-point,shape-sierpinski,smask,
 smask-image-mask,smask-mask,smask-paint,smask-text,stride-12-image,subsurface,subsurface-scale,surface-pattern,surface-pattern-scale-up,text-antialias-gray,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,transforms,twin,twin-antialias-gray,twin-antialias-mixed,twin-antialias-none,twin-antialias-subpixel,unclosed-strokes,user-font,user-font-proxy,user-font-rescale,world-map,world-map-stroke,world-map-fill,xcb-stress-cache,xcomposite-projection,pthread-show-text,bitmap-font,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3,ft-text-antialias-none,pdf-surface-source,ps-surface-source,svg-surface-source
-    - export CAIRO_TEST_IGNORE_image_argb32=clip-text,culled-glyphs,halo-transform,inverse-text,overlapping-glyphs,radial-gradient-source,record-select-font-face,record1414x-select-font-face,record1414x-text-transform,record2x-select-font-face,record90-select-font-face,recordflip-whole-select-font-face,recordflip-select-font-face,select-font-face,show-glyphs-advance,subsurface,subsurface-scale,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-pattern,text-rotate,text-unhinted-metrics,user-font-rescale,pthread-show-text,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
-    - export CAIRO_TEST_IGNORE_image_rgb24=clip-text,culled-glyphs,extended-blend-alpha-mask,halo-transform,inverse-text,overlapping-glyphs,radial-gradient-source,record-select-font-face,record1414x-select-font-face,record1414x-text-transform,record2x-select-font-face,record90-select-font-face,recordflip-whole-select-font-face,recordflip-select-font-face,select-font-face,show-glyphs-advance,subsurface,subsurface-scale,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-pattern,text-rotate,text-unhinted-metrics,user-font-rescale,pthread-show-text,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
-    - export CAIRO_TEST_IGNORE_image16_rgb24=a1-bug,aliasing,arc-direction,arc-looping-dash,big-line,bug-spline,bug-84115,bug-bo-ricotz,bug-source-cu,bug-extents,bug-seams,bug-image-compositor,caps,caps-2,caps-05,caps-joins-2,caps-joins-alpha,caps-joins-curve,caps-tails-curve,clear-source,clip-disjoint,clip-disjoint-quad,clip-stroke-unbounded,clip-fill-nz-unbounded,clip-fill-eo-unbounded,clip-fill,clip-image,clip-intersect,clip-operator,clip-push-group,clip-shape,clip-stroke,clip-text,clip-twice,close-path-current-point,copy-path,coverage-rectangles,coverage-rhombus,coverage-intersecting-quads,coverage-intersecting-triangles,coverage-row-triangles,coverage-column-triangles,coverage-triangles,coverage-abutting,culled-glyphs,dash-caps-joins,dash-curve,dash-scale,dash-state,dash-zero-length,degenerate-arc,degenerate-curve-to,degenerate-path,degenerate-pen,degenerate-rel-curve-to,drunkard-tails,extend-pad-border,extended-blend,extended-blend-alpha,extended-blend-mask,extended-blend-alph
 a-mask,extended-blend-solid,extended-blend-solid-alpha,fallback,fill-alpha,fill-alpha-pattern,fill-and-stroke,fill-and-stroke-alpha,fill-and-stroke-alpha-add,fill-degenerate-sort-order,fill-image,fill-missed-stop,fill-rule,filter-bilinear-extents,finer-grained-fallbacks,font-matrix-translation,glyph-cache-pressure,gradient-alpha,gradient-constant-alpha,group-unaligned,halo,halo-transform,hatchings,huge-linear,huge-radial,inverse-text,joins,joins-loop,joins-star,joins-retrace,large-font,large-twin-antialias-mixed,leaky-dashed-stroke,line-width-overlap-offset,line-width-scale,linear-gradient,linear-gradient-reflect,linear-gradient-subset,long-dashed-lines,mask,mask-alpha,mask-ctm,mask-surface-ctm,mask-transformed-image,mask-transformed-similar,mesh-pattern,mesh-pattern-conical,mesh-pattern-control-points,mesh-pattern-fold,mesh-pattern-overlap,mesh-pattern-transformed,new-sub-path,operator-source,over-around-source,overlapping-boxes,overlapping-glyphs,overlapping-dash-caps,paint-source
 -alpha,paint-with-alpha,paint-with-alpha-clip,paint-with-alpha-clip-mask,partial-coverage-reference,partial-coverage-three-quarter-reference,pass-through,path-append,path-stroke-twice,pdf-isolated-group,pixman-downscale-fast-96,pixman-downscale-good-96,pixman-downscale-best-96,pixman-downscale-best-24,pixman-downscale-nearest-96,pixman-downscale-bilinear-96,pixman-rotate,push-group,push-group-color,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,random-clip,random-intersections-eo,random-intersections-nonzero,random-intersections-curves-eo,random-intersections-curves-nz,raster-source,record-paint-alpha,record-paint-alpha-clip,record-paint-alpha-clip-mask,record-fill-alpha,record-select-font-face,record-text-transform,record1414x-paint-alpha,record1414x-paint-alpha-clip,record1414x-paint-alpha-clip-mask,record1414x-fill-alpha,record1414x-select-font-face,record1414x-text-transform,record2x-paint-alpha,record2x-paint-alpha-clip,record2x-paint-al
 pha-clip-mask,record2x-fill-alpha,record2x-select-font-face,record2x-text-transform,record90-paint-alpha,record90-paint-alpha-clip,record90-paint-alpha-clip-mask,record90-fill-alpha,record90-select-font-face,record90-text-transform,recordflip-whole-paint-alpha,recordflip-whole-paint-alpha-clip,recordflip-whole-paint-alpha-clip-mask,recordflip-whole-fill-alpha,recordflip-whole-select-font-face,recordflip-whole-text-transform,recordflip-paint-alpha,recordflip-paint-alpha-clip,recordflip-paint-alpha-clip-mask,recordflip-fill-alpha,recordflip-select-font-face,recordflip-text-transform,record-neg-extents-unbounded,record-neg-extents-bounded,record-mesh,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,rectilinear-dash-scale-unaligned,reflected-stroke,rel-path,rotate-clip-image-surface-paint,rotated-clip,rounded-rect
 angle-fill,rounded-rectangle-stroke,scale-offset-image,scale-offset-similar,stroke-ctm-caps,stroke-image,select-font-face,set-source,show-glyphs-advance,show-text-current-point,shape-general-convex,shape-sierpinski,simple-edge,smask,smask-fill,smask-mask,smask-paint,smask-stroke,smask-text,spline-decomposition,stroke-pattern,subsurface,subsurface-scale,surface-pattern,surface-pattern-operator,surface-pattern-scale-down,surface-pattern-scale-up,text-antialias-gray,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,tighten-bounds,tiger,a1-tiger,transforms,trap-clip,twin,twin-antialias-gray,twin-antialias-mixed,twin-antialias-subpixel,unbounded-operator,unclosed-strokes,user-font,user-font-mask,user-font-proxy,user-font-rescale,world-map,world-map-stroke,world-map-fill,xcb-huge-image-shm,xcb-huge-subimage,xcomposite-projec
 tion,pthread-same-source,pthread-show-text,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
-    - export CAIRO_TEST_IGNORE_recording_argb32=bug-source-cu,clear-source,clip-text,coverage-rectangles,culled-glyphs,finer-grained-fallbacks,halo-transform,inverse-text,overlapping-glyphs,radial-gradient-source,record-select-font-face,record1414x-fill-alpha,record1414x-select-font-face,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-fill-alpha,record2x-select-font-face,record2x-text-transform,record90-select-font-face,recordflip-whole-select-font-face,recordflip-select-font-face,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,scale-offset-similar,select-font-face,show-glyphs-advance,subsurface,subsurface-scale,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-pattern,text-rotate,text-unhinted-metrics,user-font-rescale,pthread-same-source,pthread-show-text,ft-show-glyphs-positio
 ning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
-    - export CAIRO_TEST_IGNORE_recording_rgb24=bug-source-cu,clear-source,clip-text,coverage-rectangles,culled-glyphs,extended-blend-alpha-mask,finer-grained-fallbacks,halo-transform,inverse-text,overlapping-glyphs,radial-gradient-source,record-select-font-face,record1414x-fill-alpha,record1414x-select-font-face,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-fill-alpha,record2x-select-font-face,record2x-text-transform,record90-select-font-face,recordflip-whole-select-font-face,recordflip-select-font-face,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,scale-offset-similar,select-font-face,show-glyphs-advance,subsurface,subsurface-scale,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-pattern,text-rotate,text-unhinted-metrics,user-font-rescale,pthread-same-source,pthread-show-te
 xt,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
-    - export CAIRO_TEST_IGNORE_svg11_argb32=a8-clear,arc-looping-dash,bug-51910,bug-84115,bug-source-cu,caps,caps-2,caps-1,caps-05,checkerboard,caps-joins-2,caps-joins-1,caps-joins-05,caps-joins-curve,caps-tails-curve,caps-sub-paths,clear-source,clip-complex-bug61592,clip-disjoint-quad,clip-fill-rule,clip-image,clip-push-group,clip-text,clipped-group,close-path,close-path-current-point,copy-path,culled-glyphs,dash-caps-joins,dash-curve,dash-infinite-loop,dash-scale,dash-state,degenerate-arcs,degenerate-curve-to,degenerate-linear-gradient,degenerate-pen,degenerate-radial-gradient,degenerate-rel-curve-to,device-offset-fractional,device-offset-scale,extend-pad-border,fallback,fill-and-stroke-alpha,fill-and-stroke-alpha-add,filter-bilinear-extents,filter-nearest-offset,filter-nearest-transformed,finer-grained-fallbacks,font-matrix-translation,glyph-cache-pressure,group-unaligned,halo,halo-transform,huge-radial,infinite-join,inverse-text,joins,large-font,leaky-dashed-stroke,leaky-polygon
 ,line-width-scale,line-width-tolerance,linear-gradient,linear-gradient-extend,linear-gradient-reflect,linear-gradient-subset,long-dashed-lines,mask-transformed-image,mask-transformed-similar,mesh-pattern,mesh-pattern-conical,mesh-pattern-control-points,mesh-pattern-fold,mesh-pattern-overlap,mesh-pattern-transformed,overlapping-glyphs,paint-source-alpha,paint-with-alpha,paint-with-alpha-solid-clip,paint-with-alpha-clip,paint-with-alpha-clip-mask,partial-clip-text-top,partial-clip-text-bottom,partial-clip-text-left,partial-clip-text-right,path-stroke-twice,pixman-downscale-fast-24,pixman-downscale-good-24,pixman-downscale-best-24,pixman-downscale-nearest-24,pixman-downscale-bilinear-24,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,radial-gradient-one-stop,radial-gradient-extend,record-paint,record-paint-alpha,record-paint-alpha-solid-clip,record-paint-alpha-clip,record-paint-alpha-clip-mask,record-fill-alpha,record-select-font-face,record-self
 -intersecting,record-text-transform,record1414x-paint,record1414x-paint-alpha,record1414x-paint-alpha-solid-clip,record1414x-paint-alpha-clip,record1414x-paint-alpha-clip-mask,record1414x-fill-alpha,record1414x-select-font-face,record1414x-self-intersecting,record1414x-text-transform,record2x-paint,record2x-paint-alpha,record2x-paint-alpha-solid-clip,record2x-paint-alpha-clip,record2x-paint-alpha-clip-mask,record2x-fill-alpha,record2x-select-font-face,record2x-self-intersecting,record2x-text-transform,record90-paint,record90-paint-alpha,record90-paint-alpha-solid-clip,record90-paint-alpha-clip,record90-paint-alpha-clip-mask,record90-fill-alpha,record90-select-font-face,record90-self-intersecting,record90-text-transform,recordflip-whole-paint,recordflip-whole-paint-alpha,recordflip-whole-paint-alpha-solid-clip,recordflip-whole-paint-alpha-clip,recordflip-whole-paint-alpha-clip-mask,recordflip-whole-fill-alpha,recordflip-whole-select-font-face,recordflip-whole-self-intersecting,record
 flip-whole-text-transform,recordflip-paint,recordflip-paint-alpha,recordflip-paint-alpha-solid-clip,recordflip-paint-alpha-clip,recordflip-paint-alpha-clip-mask,recordflip-fill-alpha,recordflip-select-font-face,recordflip-self-intersecting,recordflip-text-transform,record-extend-none,record-extend-pad,record-extend-repeat,record-extend-reflect,record-extend-none-similar,record-extend-pad-similar,record-extend-repeat-similar,record-extend-reflect-similar,record-neg-extents-unbounded,record-neg-extents-bounded,record-mesh,record-replay-extend-none,record-replay-extend-repeat,record-replay-extend-pad,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,rectilinear-miter-limit,reflected-stroke,rotate-image-surface-paint,clip-rotate-image-surface-paint,rotate-clip-image-surface-paint,scale-offset-image,scale-offset-similar,scale-source-surface-paint,stroke-ctm-caps,select-font-face,show-glyphs-advan
 ce,show-text-current-point,shape-sierpinski,smask,smask-image-mask,smask-mask,smask-paint,smask-stroke,smask-text,smp-glyph,spline-decomposition,surface-pattern,surface-pattern-scale-down,surface-pattern-scale-down-extend-pad,surface-pattern-scale-up,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,tiger,transforms,twin,unclosed-strokes,user-font,user-font-proxy,user-font-rescale,world-map,world-map-stroke,world-map-fill,pthread-same-source,pthread-show-text,pthread-similar,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
-    - export CAIRO_TEST_IGNORE_svg11_rgb24=a8-clear,arc-looping-dash,bug-51910,bug-84115,bug-bo-ricotz,bug-source-cu,caps,caps-2,caps-1,caps-05,checkerboard,caps-joins-2,caps-joins-1,caps-joins-05,caps-joins-curve,caps-tails-curve,caps-sub-paths,clear-source,clip-complex-bug61592,clip-disjoint-quad,clip-fill-rule,clip-image,clip-push-group,clip-text,clipped-group,close-path,close-path-current-point,copy-path,culled-glyphs,dash-caps-joins,dash-curve,dash-infinite-loop,dash-scale,dash-state,dash-zero-length,degenerate-arcs,degenerate-curve-to,degenerate-linear-gradient,degenerate-path,degenerate-pen,degenerate-radial-gradient,degenerate-rel-curve-to,device-offset-fractional,device-offset-scale,extend-pad-border,extended-blend-alpha-mask,fill-and-stroke,fill-and-stroke-alpha,fill-and-stroke-alpha-add,fill-missed-stop,filter-bilinear-extents,filter-nearest-offset,filter-nearest-transformed,finer-grained-fallbacks,font-matrix-translation,glyph-cache-pressure,gradient-alpha,gradient-const
 ant-alpha,group-unaligned,halo,halo-transform,huge-radial,infinite-join,inverse-text,joins,large-font,leaky-dashed-stroke,leaky-polygon,line-width-scale,line-width-tolerance,linear-gradient,linear-gradient-extend,linear-gradient-reflect,linear-gradient-subset,long-dashed-lines,mask,mask-transformed-image,mask-transformed-similar,mesh-pattern,mesh-pattern-conical,mesh-pattern-control-points,mesh-pattern-fold,mesh-pattern-overlap,mesh-pattern-transformed,new-sub-path,overlapping-glyphs,paint-source-alpha,paint-with-alpha,paint-with-alpha-solid-clip,paint-with-alpha-clip,paint-with-alpha-clip-mask,partial-clip-text-top,partial-clip-text-bottom,partial-clip-text-left,partial-clip-text-right,path-stroke-twice,pixman-downscale-fast-24,pixman-downscale-good-24,pixman-downscale-best-24,pixman-downscale-nearest-24,pixman-downscale-bilinear-24,push-group,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,radial-gradient-one-stop,radial-gradient-extend,reco
 rd-paint,record-paint-alpha,record-paint-alpha-solid-clip,record-paint-alpha-clip,record-paint-alpha-clip-mask,record-fill-alpha,record-select-font-face,record-self-intersecting,record-text-transform,record1414x-paint,record1414x-paint-alpha,record1414x-paint-alpha-solid-clip,record1414x-paint-alpha-clip,record1414x-paint-alpha-clip-mask,record1414x-fill-alpha,record1414x-select-font-face,record1414x-self-intersecting,record1414x-text-transform,record2x-paint,record2x-paint-alpha,record2x-paint-alpha-solid-clip,record2x-paint-alpha-clip,record2x-paint-alpha-clip-mask,record2x-fill-alpha,record2x-select-font-face,record2x-self-intersecting,record2x-text-transform,record90-paint,record90-paint-alpha,record90-paint-alpha-solid-clip,record90-paint-alpha-clip,record90-paint-alpha-clip-mask,record90-fill-alpha,record90-select-font-face,record90-self-intersecting,record90-text-transform,recordflip-whole-paint,recordflip-whole-paint-alpha,recordflip-whole-paint-alpha-solid-clip,recordflip-w
 hole-paint-alpha-clip,recordflip-whole-paint-alpha-clip-mask,recordflip-whole-fill-alpha,recordflip-whole-select-font-face,recordflip-whole-self-intersecting,recordflip-whole-text-transform,recordflip-paint,recordflip-paint-alpha,recordflip-paint-alpha-solid-clip,recordflip-paint-alpha-clip,recordflip-paint-alpha-clip-mask,recordflip-fill-alpha,recordflip-select-font-face,recordflip-self-intersecting,recordflip-text-transform,record-extend-none,record-extend-pad,record-extend-repeat,record-extend-reflect,record-extend-none-similar,record-extend-pad-similar,record-extend-repeat-similar,record-extend-reflect-similar,record-neg-extents-unbounded,record-neg-extents-bounded,record-mesh,record-replay-extend-none,record-replay-extend-repeat,record-replay-extend-pad,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,rectilinear-miter-limit,reflected-stroke,rel-path,rotate-image-surface-paint,clip-rot
 ate-image-surface-paint,rotate-clip-image-surface-paint,scale-offset-image,scale-offset-similar,scale-source-surface-paint,stroke-ctm-caps,select-font-face,self-copy,show-glyphs-advance,show-text-current-point,shape-sierpinski,smask,smask-image-mask,smask-mask,smask-paint,smask-stroke,smask-text,smp-glyph,spline-decomposition,surface-pattern,surface-pattern-scale-down,surface-pattern-scale-down-extend-pad,surface-pattern-scale-up,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,tiger,transforms,twin,unclosed-strokes,user-font,user-font-proxy,user-font-rescale,world-map,world-map-stroke,world-map-fill,pthread-same-source,pthread-show-text,pthread-similar,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
-    - export CAIRO_TEST_IGNORE_svg12_argb32=a8-clear,arc-looping-dash,big-empty-box,big-empty-triangle,big-little-box,big-little-triangle,bug-51910,bug-84115,bug-source-cu,bug-image-compositor,caps,caps-2,caps-1,caps-05,checkerboard,caps-joins-2,caps-joins-1,caps-joins-05,caps-joins-curve,caps-tails-curve,caps-sub-paths,clear,clear-source,clip-complex-bug61592,clip-disjoint-quad,clip-stroke-unbounded,clip-fill-nz-unbounded,clip-fill-eo-unbounded,clip-fill-rule,clip-image,clip-operator,clip-push-group,clip-text,clip-unbounded,clipped-group,close-path,close-path-current-point,copy-path,culled-glyphs,dash-caps-joins,dash-curve,dash-infinite-loop,dash-scale,dash-state,degenerate-arcs,degenerate-curve-to,degenerate-linear-gradient,degenerate-pen,degenerate-radial-gradient,degenerate-rel-curve-to,device-offset-fractional,device-offset-scale,extend-pad-border,extended-blend,extended-blend-alpha,extended-blend-mask,extended-blend-alpha-mask,extended-blend-solid,extended-blend-solid-alpha,fa
 llback,fill-and-stroke-alpha,fill-and-stroke-alpha-add,fill-empty,filter-bilinear-extents,filter-nearest-offset,filter-nearest-transformed,finer-grained-fallbacks,font-matrix-translation,glyph-cache-pressure,group-unaligned,halo,halo-transform,huge-radial,infinite-join,inverse-text,joins,large-font,leaky-dashed-stroke,leaky-polygon,line-width-scale,line-width-tolerance,linear-gradient,linear-gradient-extend,linear-gradient-reflect,linear-gradient-subset,long-dashed-lines,mask-transformed-image,mask-transformed-similar,mesh-pattern,mesh-pattern-conical,mesh-pattern-control-points,mesh-pattern-fold,mesh-pattern-overlap,mesh-pattern-transformed,operator,operator-alpha,operator-clear,operator-source,over-around-source,over-below-source,over-between-source,overlapping-boxes,overlapping-glyphs,paint-source-alpha,paint-with-alpha,paint-with-alpha-solid-clip,paint-with-alpha-clip,paint-with-alpha-clip-mask,partial-clip-text-top,partial-clip-text-bottom,partial-clip-text-left,partial-clip-te
 xt-right,path-stroke-twice,pdf-isolated-group,pixman-downscale-fast-24,pixman-downscale-good-24,pixman-downscale-best-24,pixman-downscale-nearest-24,pixman-downscale-bilinear-24,push-group-color,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,radial-gradient-one-stop,radial-gradient-extend,record-paint,record-paint-alpha,record-paint-alpha-solid-clip,record-paint-alpha-clip,record-paint-alpha-clip-mask,record-fill-alpha,record-select-font-face,record-self-intersecting,record-text-transform,record1414x-paint,record1414x-paint-alpha,record1414x-paint-alpha-solid-clip,record1414x-paint-alpha-clip,record1414x-paint-alpha-clip-mask,record1414x-fill-alpha,record1414x-select-font-face,record1414x-self-intersecting,record1414x-text-transform,record2x-paint,record2x-paint-alpha,record2x-paint-alpha-solid-clip,record2x-paint-alpha-clip,record2x-paint-alpha-clip-mask,record2x-fill-alpha,record2x-select-font-face,record2x-self-intersecting,record2x-text-t
 ransform,record90-paint,record90-paint-alpha,record90-paint-alpha-solid-clip,record90-paint-alpha-clip,record90-paint-alpha-clip-mask,record90-fill-alpha,record90-select-font-face,record90-self-intersecting,record90-text-transform,recordflip-whole-paint,recordflip-whole-paint-alpha,recordflip-whole-paint-alpha-solid-clip,recordflip-whole-paint-alpha-clip,recordflip-whole-paint-alpha-clip-mask,recordflip-whole-fill-alpha,recordflip-whole-select-font-face,recordflip-whole-self-intersecting,recordflip-whole-text-transform,recordflip-paint,recordflip-paint-alpha,recordflip-paint-alpha-solid-clip,recordflip-paint-alpha-clip,recordflip-paint-alpha-clip-mask,recordflip-fill-alpha,recordflip-select-font-face,recordflip-self-intersecting,recordflip-text-transform,record-extend-none,record-extend-pad,record-extend-repeat,record-extend-reflect,record-extend-none-similar,record-extend-pad-similar,record-extend-repeat-similar,record-extend-reflect-similar,record-neg-extents-unbounded,record-neg-
 extents-bounded,record-mesh,record-replay-extend-none,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,rectilinear-miter-limit,reflected-stroke,rotate-image-surface-paint,clip-rotate-image-surface-paint,rotate-clip-image-surface-paint,scale-offset-image,scale-offset-similar,scale-source-surface-paint,stroke-ctm-caps,select-font-face,show-glyphs-advance,show-text-current-point,shape-sierpinski,smask,smask-image-mask,smask-mask,smask-paint,smask-stroke,smask-text,smp-glyph,spline-decomposition,surface-pattern,surface-pattern-operator,surface-pattern-scale-down,surface-pattern-scale-down-extend-pad,surface-pattern-scale-up,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,tighten-bounds,tiger,transforms,twin,unbounded-operator,unclosed-strokes,user-font,user-font-proxy,user-font-resca
 le,world-map,world-map-stroke,world-map-fill,xlib-expose-event,pthread-same-source,pthread-show-text,pthread-similar,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
-    - export CAIRO_TEST_IGNORE_svg12_rgb24=a8-clear,arc-looping-dash,big-empty-box,big-empty-triangle,big-little-box,big-little-triangle,bug-51910,bug-84115,bug-bo-ricotz,bug-source-cu,bug-image-compositor,caps,caps-2,caps-1,caps-05,checkerboard,caps-joins-2,caps-joins-1,caps-joins-05,caps-joins-curve,caps-tails-curve,caps-sub-paths,clear,clear-source,clip-complex-bug61592,clip-disjoint-quad,clip-stroke-unbounded,clip-fill-nz-unbounded,clip-fill-eo-unbounded,clip-fill-rule,clip-image,clip-operator,clip-push-group,clip-text,clip-unbounded,clipped-group,close-path,close-path-current-point,copy-path,culled-glyphs,dash-caps-joins,dash-curve,dash-infinite-loop,dash-scale,dash-state,dash-zero-length,degenerate-arcs,degenerate-curve-to,degenerate-linear-gradient,degenerate-path,degenerate-pen,degenerate-radial-gradient,degenerate-rel-curve-to,device-offset-fractional,device-offset-scale,extend-pad-border,extended-blend,extended-blend-alpha,extended-blend-mask,extended-blend-alpha-mask,exte
 nded-blend-solid,extended-blend-solid-alpha,fallback,fill-and-stroke,fill-and-stroke-alpha,fill-and-stroke-alpha-add,fill-empty,fill-missed-stop,filter-bilinear-extents,filter-nearest-offset,filter-nearest-transformed,finer-grained-fallbacks,font-matrix-translation,glyph-cache-pressure,gradient-alpha,gradient-constant-alpha,group-unaligned,halo,halo-transform,huge-radial,infinite-join,inverse-text,joins,large-font,leaky-dashed-stroke,leaky-polygon,line-width-scale,line-width-tolerance,linear-gradient,linear-gradient-extend,linear-gradient-reflect,linear-gradient-subset,long-dashed-lines,mask,mask-transformed-image,mask-transformed-similar,mesh-pattern,mesh-pattern-conical,mesh-pattern-control-points,mesh-pattern-fold,mesh-pattern-overlap,mesh-pattern-transformed,new-sub-path,operator,operator-alpha,operator-clear,operator-source,over-around-source,over-below-source,over-between-source,overlapping-boxes,overlapping-glyphs,paint-source-alpha,paint-with-alpha,paint-with-alpha-solid-cli
 p,paint-with-alpha-clip,paint-with-alpha-clip-mask,partial-clip-text-top,partial-clip-text-bottom,partial-clip-text-left,partial-clip-text-right,path-stroke-twice,pdf-isolated-group,pixman-downscale-fast-24,pixman-downscale-good-24,pixman-downscale-best-24,pixman-downscale-nearest-24,pixman-downscale-bilinear-24,push-group,push-group-color,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,radial-gradient-one-stop,radial-gradient-extend,record-paint,record-paint-alpha,record-paint-alpha-solid-clip,record-paint-alpha-clip,record-paint-alpha-clip-mask,record-fill-alpha,record-select-font-face,record-self-intersecting,record-text-transform,record1414x-paint,record1414x-paint-alpha,record1414x-paint-alpha-solid-clip,record1414x-paint-alpha-clip,record1414x-paint-alpha-clip-mask,record1414x-fill-alpha,record1414x-select-font-face,record1414x-self-intersecting,record1414x-text-transform,record2x-paint,record2x-paint-alpha,record2x-paint-alpha-solid-cli
 p,record2x-paint-alpha-clip,record2x-paint-alpha-clip-mask,record2x-fill-alpha,record2x-select-font-face,record2x-self-intersecting,record2x-text-transform,record90-paint,record90-paint-alpha,record90-paint-alpha-solid-clip,record90-paint-alpha-clip,record90-paint-alpha-clip-mask,record90-fill-alpha,record90-select-font-face,record90-self-intersecting,record90-text-transform,recordflip-whole-paint,recordflip-whole-paint-alpha,recordflip-whole-paint-alpha-solid-clip,recordflip-whole-paint-alpha-clip,recordflip-whole-paint-alpha-clip-mask,recordflip-whole-fill-alpha,recordflip-whole-select-font-face,recordflip-whole-self-intersecting,recordflip-whole-text-transform,recordflip-paint,recordflip-paint-alpha,recordflip-paint-alpha-solid-clip,recordflip-paint-alpha-clip,recordflip-paint-alpha-clip-mask,recordflip-fill-alpha,recordflip-select-font-face,recordflip-self-intersecting,recordflip-text-transform,record-extend-none,record-extend-pad,record-extend-repeat,record-extend-reflect,recor
 d-extend-none-similar,record-extend-pad-similar,record-extend-repeat-similar,record-extend-reflect-similar,record-neg-extents-unbounded,record-neg-extents-bounded,record-mesh,record-replay-extend-none,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,rectilinear-miter-limit,reflected-stroke,rel-path,rotate-image-surface-paint,clip-rotate-image-surface-paint,rotate-clip-image-surface-paint,scale-offset-image,scale-offset-similar,scale-source-surface-paint,stroke-ctm-caps,select-font-face,self-copy,show-glyphs-advance,show-text-current-point,shape-sierpinski,smask,smask-image-mask,smask-mask,smask-paint,smask-stroke,smask-text,smp-glyph,spline-decomposition,surface-pattern,surface-pattern-operator,surface-pattern-scale-down,surface-pattern-scale-down-extend-pad,surface-pattern-scale-up,text-glyph-range,text-patte
 rn,text-rotate,text-transform,text-unhinted-metrics,tighten-bounds,tiger,transforms,twin,unbounded-operator,unclosed-strokes,user-font,user-font-proxy,user-font-rescale,world-map,world-map-stroke,world-map-fill,xlib-expose-event,pthread-same-source,pthread-show-text,pthread-similar,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
-    - export CAIRO_TEST_IGNORE_xcb_argb32=bug-spline,clip-operator,coverage-rectangles,coverage-rhombus,coverage-intersecting-quads,coverage-intersecting-triangles,coverage-row-triangles,coverage-column-triangles,coverage-triangles,culled-glyphs,fill-image,halo,halo-transform,hatchings,inverse-text,operator-source,overlapping-boxes,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,radial-outer-focus,random-clip,record-select-font-face,record-self-intersecting,record1414x-fill-alpha,record1414x-select-font-face,record1414x-self-intersecting,record2x-paint-alpha-clip-mask,record2x-fill-alpha,record2x-select-font-face,record90-paint-alpha-solid-clip,record90-paint-alpha-clip,record90-select-font-face,record90-self-intersecting,recordflip-whole-paint-alpha-clip-mask,recordflip-whole-fill-alpha,recordflip-whole-select-font-face,recordflip-whole-self-intersecting,recordflip-paint-alpha-clip-mask,recordflip-select-font-face,recordflip-self-intersecting
 ,record-neg-extents-unbounded,record-neg-extents-bounded,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,recording-surface-extend-repeat,recording-surface-extend-pad,rotated-clip,stroke-clipped,stroke-image,select-font-face,simple-edge,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-rotate,tighten-bounds,a1-tiger,twin-antialias-none,unantialiased-shapes,user-font,user-font-proxy,user-font-rescale,pthread-show-text,ft-text-vertical-layout-type1
-    - export CAIRO_TEST_IGNORE_xcb_rgb24=arc-looping-dash,bug-spline,bug-51910,bug-84115,bug-source-cu,bug-image-compositor,caps-2,caps-1,caps-05,caps-joins-2,caps-joins-1,caps-joins-05,clear-source,clip-operator,clip-text,coverage-rectangles,coverage-rhombus,coverage-intersecting-quads,coverage-intersecting-triangles,coverage-row-triangles,coverage-column-triangles,coverage-triangles,coverage-abutting,culled-glyphs,dash-curve,extended-blend-alpha-mask,fallback,fill-image,filter-bilinear-extents,font-matrix-translation,glyph-cache-pressure,halo,halo-transform,hatchings,inverse-text,large-font,linear-gradient,linear-gradient-subset,mask,mask-transformed-image,mask-transformed-similar,operator-alpha-alpha,operator-clear,operator-source,overlapping-boxes,overlapping-glyphs,overlapping-dash-caps,partial-clip-text-bottom,partial-clip-text-left,partial-coverage-reference,partial-coverage-three-quarter-reference,push-group,push-group-color,radial-gradient,radial-gradient-mask,radial-gradie
 nt-source,radial-gradient-mask-source,radial-outer-focus,random-clip,record-select-font-face,record-self-intersecting,record1414x-fill-alpha,record1414x-select-font-face,record1414x-self-intersecting,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-fill-alpha,record2x-select-font-face,record90-paint-alpha-solid-clip,record90-paint-alpha-clip,record90-fill-alpha,record90-select-font-face,record90-self-intersecting,recordflip-whole-paint-alpha-clip-mask,recordflip-whole-fill-alpha,recordflip-whole-select-font-face,recordflip-whole-self-intersecting,recordflip-paint-alpha-clip-mask,recordflip-fill-alpha,recordflip-select-font-face,recordflip-self-intersecting,record-neg-extents-unbounded,record-neg-extents-bounded,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,recording-surface-extend-pad,refl
 ected-stroke,rotated-clip,stroke-clipped,stroke-image,select-font-face,show-glyphs-advance,show-text-current-point,simple-edge,smask,smask-fill,smask-image-mask,smask-mask,smask-paint,smask-stroke,smp-glyph,subsurface,subsurface-scale,surface-pattern-operator,surface-pattern-scale-up,text-antialias-gray,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-rotate,text-transform,tighten-bounds,a1-tiger,trap-clip,twin,twin-antialias-gray,twin-antialias-none,twin-antialias-subpixel,unantialiased-shapes,unbounded-operator,user-font,user-font-proxy,user-font-rescale,world-map,world-map-fill,xcomposite-projection,pthread-show-text,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
-    - export CAIRO_TEST_IGNORE_xcb_window_rgb24=arc-looping-dash,bug-spline,bug-51910,caps-2,caps-1,caps-05,caps-joins-2,caps-joins-1,caps-joins-05,clear-source,clip-operator,clip-text,coverage-rectangles,coverage-intersecting-quads,coverage-intersecting-triangles,coverage-row-triangles,coverage-column-triangles,coverage-triangles,coverage-abutting,culled-glyphs,extended-blend-alpha-mask,fallback,fill-image,filter-bilinear-extents,font-matrix-translation,glyph-cache-pressure,halo,halo-transform,inverse-text,linear-gradient,linear-gradient-subset,mask,mask-transformed-image,mask-transformed-similar,operator-alpha-alpha,operator-clear,operator-source,overlapping-boxes,overlapping-glyphs,overlapping-dash-caps,partial-clip-text-bottom,partial-clip-text-left,partial-coverage-reference,partial-coverage-three-quarter-reference,push-group,push-group-color,radial-outer-focus,record-select-font-face,record-self-intersecting,record1414x-fill-alpha,record1414x-select-font-face,record1414x-self-
 intersecting,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-fill-alpha,record2x-select-font-face,record90-paint-alpha-solid-clip,record90-paint-alpha-clip,record90-fill-alpha,record90-select-font-face,record90-self-intersecting,recordflip-whole-paint-alpha-clip-mask,recordflip-whole-fill-alpha,recordflip-whole-select-font-face,recordflip-whole-self-intersecting,recordflip-paint-alpha-clip-mask,recordflip-fill-alpha,recordflip-select-font-face,recordflip-self-intersecting,record-neg-extents-unbounded,record-neg-extents-bounded,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,recording-surface-extend-pad,reflected-stroke,rotated-clip,stroke-clipped,stroke-image,select-font-face,show-glyphs-advance,show-text-current-point,simple-edge,smask,smask-fill,smask-image-mask,smask-mask,smask-paint,sma
 sk-stroke,smp-glyph,subsurface,subsurface-scale,surface-pattern-operator,surface-pattern-scale-up,text-antialias-gray,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-rotate,text-transform,tighten-bounds,trap-clip,twin,twin-antialias-gray,twin-antialias-none,twin-antialias-subpixel,unantialiased-shapes,unbounded-operator,user-font-rescale,xcomposite-projection,pthread-show-text,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
-    - export CAIRO_TEST_IGNORE_xcb_window__rgb24=arc-looping-dash,bug-spline,bug-51910,caps-2,caps-1,caps-05,caps-joins-2,caps-joins-1,caps-joins-05,clear-source,clip-operator,clip-text,coverage-rectangles,coverage-intersecting-quads,coverage-intersecting-triangles,coverage-row-triangles,coverage-column-triangles,coverage-triangles,coverage-abutting,culled-glyphs,extended-blend-alpha-mask,fallback,fill-image,filter-bilinear-extents,font-matrix-translation,glyph-cache-pressure,halo,halo-transform,inverse-text,linear-gradient,linear-gradient-subset,mask,mask-transformed-image,mask-transformed-similar,operator-alpha-alpha,operator-clear,operator-source,overlapping-boxes,overlapping-glyphs,overlapping-dash-caps,partial-clip-text-bottom,partial-clip-text-left,partial-coverage-reference,partial-coverage-three-quarter-reference,push-group,push-group-color,radial-outer-focus,record-select-font-face,record-self-intersecting,record1414x-fill-alpha,record1414x-select-font-face,record1414x-self
 -intersecting,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-fill-alpha,record2x-select-font-face,record90-paint-alpha-solid-clip,record90-paint-alpha-clip,record90-fill-alpha,record90-select-font-face,record90-self-intersecting,recordflip-whole-paint-alpha-clip-mask,recordflip-whole-fill-alpha,recordflip-whole-select-font-face,recordflip-whole-self-intersecting,recordflip-paint-alpha-clip-mask,recordflip-fill-alpha,recordflip-select-font-face,recordflip-self-intersecting,record-neg-extents-unbounded,record-neg-extents-bounded,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,recording-surface-extend-pad,reflected-stroke,rotated-clip,stroke-clipped,stroke-image,select-font-face,show-glyphs-advance,show-text-current-point,simple-edge,smask,smask-fill,smask-image-mask,smask-mask,smask-paint,sm
 ask-stroke,smp-glyph,subsurface,subsurface-scale,surface-pattern-operator,surface-pattern-scale-up,text-antialias-gray,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-rotate,text-transform,tighten-bounds,trap-clip,twin,twin-antialias-gray,twin-antialias-none,twin-antialias-subpixel,unantialiased-shapes,unbounded-operator,user-font-rescale,xcomposite-projection,pthread-show-text,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
-    - export CAIRO_TEST_IGNORE_xcb_render_0_0_argb32=clip-disjoint-hatching,clip-stroke-unbounded,clip-fill-nz-unbounded,clip-fill-eo-unbounded,clip-operator,clip-polygons,clip-shape,clip-twice,coverage-intersecting-triangles,culled-glyphs,hatchings,inverse-text,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,random-clip,record-paint-alpha-solid-clip,record-select-font-face,record1414x-select-font-face,record1414x-text-transform,record2x-select-font-face,record90-select-font-face,recordflip-whole-select-font-face,recordflip-select-font-face,record-neg-extents-bounded,record-replay-extend-repeat,record-replay-extend-reflect,rotated-clip,select-font-face,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,trap-clip,user-font-rescale,pthread-show-text,ft-text-vertical-layout-type1
-    - export CAIRO_TEST_IGNORE_xcb_render_0_0_rgb24=clip-disjoint-hatching,clip-stroke-unbounded,clip-fill-nz-unbounded,clip-fill-eo-unbounded,clip-operator,clip-polygons,clip-shape,clip-twice,coverage-intersecting-triangles,culled-glyphs,extended-blend-alpha-mask,fallback,hatchings,inverse-text,mask,operator-source,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,random-clip,record-paint-alpha-solid-clip,record-select-font-face,record1414x-select-font-face,record1414x-text-transform,record2x-select-font-face,record90-select-font-face,recordflip-whole-select-font-face,recordflip-select-font-face,record-neg-extents-bounded,record-replay-extend-repeat,record-replay-extend-reflect,recording-surface-over,recording-surface-extend-none,rotated-clip,select-font-face,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,trap-clip,user-font-rescale,pthread-show-text,ft-t
 ext-vertical-layout-type1
-    - export CAIRO_TEST_IGNORE_xcb_fallback_rgb24=clip-text,coverage-intersecting-triangles,culled-glyphs,extended-blend-alpha-mask,fallback,halo-transform,inverse-text,overlapping-glyphs,record-select-font-face,record1414x-select-font-face,record1414x-text-transform,record2x-select-font-face,record90-select-font-face,recordflip-whole-select-font-face,recordflip-select-font-face,select-font-face,show-glyphs-advance,subsurface,subsurface-scale,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-pattern,text-rotate,text-unhinted-metrics,user-font-rescale,pthread-show-text,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
-    - export CAIRO_TEST_IGNORE_xlib_argb32=aliasing,arc-looping-dash,bug-spline,bug-84115,bug-extents,bug-image-compositor,caps-joins-curve,clip-disjoint,clip-stroke-unbounded,clip-operator,clip-shape,clip-stroke,clip-text,close-path-current-point,coverage-rhombus,coverage-column-triangles,culled-glyphs,dash-caps-joins,dash-curve,dash-scale,degenerate-curve-to,degenerate-pen,degenerate-rel-curve-to,drunkard-tails,extended-blend-alpha-mask,fill-and-stroke,fill-and-stroke-alpha,fill-and-stroke-alpha-add,fill-image,halo,halo-transform,hatchings,inverse-text,joins,joins-loop,joins-retrace,large-twin-antialias-mixed,leaky-dashed-stroke,line-width-scale,line-width-tolerance,long-dashed-lines,new-sub-path,operator-source,overlapping-boxes,overlapping-glyphs,overlapping-dash-caps,path-stroke-twice,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,radial-outer-focus,random-clip,random-intersections-eo,random-intersections-nonzero,random-intersections-cur
 ves-eo,random-intersections-curves-nz,record-select-font-face,record-self-intersecting,record-text-transform,record1414x-fill-alpha,record1414x-select-font-face,record1414x-self-intersecting,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-fill-alpha,record2x-select-font-face,record2x-text-transform,record90-paint-alpha-solid-clip,record90-paint-alpha-clip,record90-select-font-face,record90-self-intersecting,record90-text-transform,recordflip-whole-paint-alpha-clip-mask,recordflip-whole-fill-alpha,recordflip-whole-select-font-face,recordflip-whole-self-intersecting,recordflip-whole-text-transform,recordflip-paint-alpha-clip-mask,recordflip-select-font-face,recordflip-self-intersecting,recordflip-text-transform,record-neg-extents-unbounded,record-neg-extents-bounded,record-replay-extend-none,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,recording-surface-extend-repeat,recording-surface-extend-pad,reflected-stroke,rel-path,rounded-
 rectangle-stroke,scale-offset-image,scale-offset-similar,stroke-clipped,stroke-image,select-font-face,show-glyphs-advance,shape-general-convex,shape-sierpinski,simple-edge,smask,smask-stroke,smask-text,spline-decomposition,stroke-pattern,subsurface,subsurface-scale,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-pattern,text-rotate,text-unhinted-metrics,tighten-bounds,twin,twin-antialias-gray,twin-antialias-mixed,twin-antialias-none,twin-antialias-subpixel,unclosed-strokes,user-font,user-font-proxy,user-font-rescale,world-map,world-map-stroke,pthread-show-text,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
-    - export CAIRO_TEST_IGNORE_xlib_rgb24=aliasing,arc-looping-dash,bug-spline,bug-51910,bug-84115,bug-source-cu,bug-extents,bug-image-compositor,caps-joins-05,caps-joins-curve,caps-tails-curve,clear-source,clip-disjoint,clip-stroke-unbounded,clip-operator,clip-shape,clip-stroke,clip-text,close-path-current-point,coverage-rhombus,coverage-column-triangles,coverage-abutting,culled-glyphs,dash-caps-joins,dash-curve,dash-scale,degenerate-curve-to,degenerate-pen,degenerate-rel-curve-to,drunkard-tails,extended-blend-mask,extended-blend-alpha-mask,fallback,fill-and-stroke,fill-and-stroke-alpha,fill-and-stroke-alpha-add,fill-image,filter-bilinear-extents,font-matrix-translation,glyph-cache-pressure,halo,halo-transform,hatchings,infinite-join,inverse-text,joins,joins-loop,joins-star,joins-retrace,large-font,large-twin-antialias-mixed,leaky-dashed-stroke,line-width-scale,line-width-tolerance,linear-gradient,linear-gradient-subset,long-dashed-lines,mask,mask-transformed-image,mask-transformed
 -similar,miter-precision,new-sub-path,operator-alpha-alpha,operator-clear,operator-source,overlapping-boxes,overlapping-glyphs,overlapping-dash-caps,partial-clip-text-bottom,partial-clip-text-left,partial-coverage-reference,partial-coverage-three-quarter-reference,path-stroke-twice,push-group,push-group-color,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,radial-outer-focus,random-clip,random-intersections-eo,random-intersections-nonzero,random-intersections-curves-eo,random-intersections-curves-nz,record-select-font-face,record-self-intersecting,record-text-transform,record1414x-fill-alpha,record1414x-select-font-face,record1414x-self-intersecting,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-fill-alpha,record2x-select-font-face,record2x-text-transform,record90-paint-alpha-solid-clip,record90-paint-alpha-clip,record90-fill-alpha,record90-select-font-face,record90-self-intersecting,record90-text-transform,recordflip-whole
 -paint-alpha-clip-mask,recordflip-whole-fill-alpha,recordflip-whole-select-font-face,recordflip-whole-self-intersecting,recordflip-whole-text-transform,recordflip-paint-alpha-clip-mask,recordflip-fill-alpha,recordflip-select-font-face,recordflip-self-intersecting,recordflip-text-transform,record-neg-extents-unbounded,record-neg-extents-bounded,record-replay-extend-none,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,recording-surface-extend-pad,reflected-stroke,rel-path,rotated-clip,rounded-rectangle-stroke,scale-offset-image,scale-offset-similar,stroke-ctm-caps,stroke-clipped,stroke-image,select-font-face,show-glyphs-advance,show-text-current-point,shape-general-convex,shape-sierpinski,simple-edge,smask,smask-fill,smask-image-mask,smask-mask,smask-paint,smask-stroke,smask-text,smp-glyph,spline-decomposition,
 stroke-pattern,subsurface,subsurface-scale,surface-pattern-operator,surface-pattern-scale-up,text-antialias-gray,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,tighten-bounds,trap-clip,twin,twin-antialias-gray,twin-antialias-mixed,twin-antialias-none,twin-antialias-subpixel,unbounded-operator,unclosed-strokes,user-font,user-font-proxy,user-font-rescale,world-map,world-map-stroke,world-map-fill,xcomposite-projection,pthread-show-text,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
-    - export CAIRO_TEST_IGNORE_xlib_window_rgb24=aliasing,arc-looping-dash,bug-spline,bug-51910,bug-extents,caps-joins-05,caps-joins-curve,clear-source,clip-disjoint,clip-stroke-unbounded,clip-operator,clip-shape,clip-stroke,clip-text,close-path-current-point,coverage-rectangles,coverage-intersecting-quads,coverage-intersecting-triangles,coverage-row-triangles,coverage-column-triangles,coverage-triangles,coverage-abutting,culled-glyphs,dash-caps-joins,dash-scale,degenerate-curve-to,degenerate-pen,degenerate-rel-curve-to,drunkard-tails,extended-blend-mask,extended-blend-alpha-mask,fallback,fill-and-stroke,fill-and-stroke-alpha,fill-and-stroke-alpha-add,fill-image,filter-bilinear-extents,font-matrix-translation,glyph-cache-pressure,halo,halo-transform,infinite-join,inverse-text,joins,joins-loop,joins-star,joins-retrace,large-twin-antialias-mixed,leaky-dashed-stroke,line-width-scale,line-width-tolerance,linear-gradient,linear-gradient-subset,long-dashed-lines,mask,mask-transformed-imag
 e,mask-transformed-similar,miter-precision,new-sub-path,operator-alpha-alpha,operator-clear,operator-source,overlapping-boxes,overlapping-glyphs,overlapping-dash-caps,partial-clip-text-bottom,partial-clip-text-left,partial-coverage-reference,partial-coverage-three-quarter-reference,path-stroke-twice,push-group,push-group-color,radial-outer-focus,record-select-font-face,record-self-intersecting,record-text-transform,record1414x-fill-alpha,record1414x-select-font-face,record1414x-self-intersecting,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-fill-alpha,record2x-select-font-face,record2x-text-transform,record90-paint-alpha-solid-clip,record90-paint-alpha-clip,record90-fill-alpha,record90-select-font-face,record90-self-intersecting,record90-text-transform,recordflip-whole-paint-alpha-clip-mask,recordflip-whole-fill-alpha,recordflip-whole-select-font-face,recordflip-whole-self-intersecting,recordflip-whole-text-transform,recordflip-paint-alpha-clip-mask,recordflip-f
 ill-alpha,recordflip-select-font-face,recordflip-self-intersecting,recordflip-text-transform,record-neg-extents-unbounded,record-neg-extents-bounded,record-replay-extend-none,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,recording-surface-extend-pad,reflected-stroke,rel-path,rotated-clip,rounded-rectangle-stroke,scale-offset-image,scale-offset-similar,stroke-ctm-caps,stroke-clipped,stroke-image,select-font-face,show-glyphs-advance,show-text-current-point,shape-general-convex,simple-edge,smask,smask-fill,smask-image-mask,smask-mask,smask-paint,smask-stroke,smask-text,smp-glyph,spline-decomposition,stroke-pattern,subsurface,subsurface-scale,surface-pattern-operator,surface-pattern-scale-up,text-antialias-gray,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpix
 el-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,tighten-bounds,trap-clip,twin,twin-antialias-gray,twin-antialias-mixed,twin-antialias-none,twin-antialias-subpixel,unbounded-operator,unclosed-strokes,user-font-rescale,xcomposite-projection,pthread-show-text,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
-    - export CAIRO_TEST_IGNORE_xlib_render_0_0_rgb24=caps-sub-paths,clear-source,clip-operator,clip-push-group,clip-text,clipped-group,coverage-intersecting-triangles,culled-glyphs,curve-to-as-line-to,extended-blend-alpha-mask,fallback,fill-and-stroke,fill-and-stroke-alpha,fill-and-stroke-alpha-add,finer-grained-fallbacks,halo-transform,horizontal-clip,infinite-join,inverse-text,large-twin-antialias-mixed,leaky-polygon,mask,operator-clear,operator-source,overlapping-glyphs,radial-outer-focus,record-select-font-face,record1414x-select-font-face,record1414x-text-transform,record2x-select-font-face,record90-select-font-face,recordflip-whole-select-font-face,recordflip-select-font-face,rectilinear-miter-limit,rectilinear-stroke,rel-path,select-font-face,show-glyphs-advance,smask,smask-text,subsurface,subsurface-scale,surface-pattern-operator,text-antialias-gray,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-sub
 pixel-vbgr,text-pattern,text-rotate,text-unhinted-metrics,twin-antialias-gray,twin-antialias-mixed,twin-antialias-none,twin-antialias-subpixel,unbounded-operator,user-font-rescale,pthread-show-text,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
-    - export CAIRO_TEST_IGNORE_xlib_fallback_rgb24=arc-looping-dash,bug-51910,bug-seams,caps,caps-2,caps-1,caps-05,caps-joins-2,caps-joins-1,caps-joins-05,caps-joins-curve,caps-sub-paths,clear-source,clip-disjoint-quad,clip-image,clip-mixed-antialias,clip-push-group,clip-polygons,clip-text,close-path,close-path-current-point,copy-path,coverage-intersecting-quads,coverage-abutting,culled-glyphs,dash-caps-joins,dash-infinite-loop,dash-scale,dash-zero-length,degenerate-curve-to,degenerate-pen,degenerate-rel-curve-to,extended-blend-alpha-mask,fallback,filter-bilinear-extents,finer-grained-fallbacks,font-matrix-translation,glyph-cache-pressure,halo-transform,infinite-join,inverse-text,joins,large-twin-antialias-mixed,leaky-dashed-stroke,leaky-polygon,line-width-scale,line-width-tolerance,long-dashed-lines,mask-transformed-image,mask-transformed-similar,operator-alpha-alpha,over-above-source,over-around-source,over-between-source,overlapping-glyphs,partial-clip-text-bottom,partial-clip-te
 xt-left,partial-coverage-reference,partial-coverage-three-quarter-reference,path-stroke-twice,push-group-color,record-select-font-face,record1414x-select-font-face,record1414x-text-transform,record2x-select-font-face,record90-select-font-face,recordflip-whole-select-font-face,recordflip-select-font-face,recording-surface-over,recording-surface-extend-none,rectilinear-miter-limit,reflected-stroke,stroke-ctm-caps,select-font-face,self-copy,show-glyphs-advance,show-text-current-point,smask,smask-image-mask,smask-mask,smask-paint,smask-text,smp-glyph,subsurface,subsurface-scale,surface-pattern-scale-down-extend-none,surface-pattern-scale-up,text-antialias-gray,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,transforms,twin,twin-antialias-gray,twin-antialias-mixed,twin-antialias-none,twin-antialias-subpixel,unclosed-strok
 es,user-font-rescale,xcomposite-projection,pthread-show-text,pthread-similar,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
+    - export CAIRO_TEST_IGNORE_script_argb32=a1-bug,a1-fill,arc-looping-dash,bilevel-image,bug-51910,bug-84115,bug-seams,caps,caps-2,caps-1,caps-05,checkerboard,caps-joins-2,caps-joins-1,caps-joins-05,caps-joins-curve,caps-tails-curve,caps-sub-paths,clear-source,clip-disjoint-quad,clip-device-offset,clip-image,clip-mixed-antialias,clip-push-group,clip-polygons,clip-text,close-path,close-path-current-point,composite-integer-translate-over-repeat,copy-path,coverage-rectangles,coverage-intersecting-quads,coverage-intersecting-triangles,coverage-abutting,culled-glyphs,dash-caps-joins,dash-curve,dash-infinite-loop,dash-scale,dash-state,degenerate-curve-to,degenerate-linear-gradient,degenerate-pen,degenerate-radial-gradient,degenerate-rel-curve-to,device-offset-scale,extend-pad-border,fill-and-stroke-alpha,fill-and-stroke-alpha-add,filter-bilinear-extents,font-matrix-translation,glyph-cache-pressure,halo,halo-transform,huge-radial,image-surface-source,xcb-surface-source,xlib-surface-sourc
 e,infinite-join,inverse-text,joins,large-font,large-source,large-twin-antialias-mixed,leaky-dashed-rectangle,leaky-dashed-stroke,leaky-polygon,line-width-scale,line-width-tolerance,linear-gradient-extend,linear-gradient-reflect,long-dashed-lines,map-all-to-image,map-bit-to-image,map-to-image-fill,mask-transformed-image,mask-transformed-similar,mesh-pattern,mesh-pattern-conical,mesh-pattern-control-points,mesh-pattern-fold,mesh-pattern-overlap,mesh-pattern-transformed,negative-stride-image,operator-alpha-alpha,overlapping-glyphs,paint-source-alpha,paint-with-alpha,paint-with-alpha-solid-clip,paint-with-alpha-clip,partial-clip-text-bottom,partial-clip-text-left,partial-coverage-reference,partial-coverage-three-quarter-reference,partial-coverage-half-reference,path-stroke-twice,push-group-color,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,radial-gradient-one-stop,radial-gradient-extend,record-paint-alpha-solid-clip,record-paint-alpha-clip,reco
 rd-select-font-face,record-text-transform,record1414x-paint-alpha,record1414x-paint-alpha-solid-clip,record1414x-paint-alpha-clip,record1414x-select-font-face,record1414x-text-transform,record2x-paint-alpha,record2x-paint-alpha-solid-clip,record2x-paint-alpha-clip,record2x-select-font-face,record2x-text-transform,record90-paint-alpha-clip-mask,record90-select-font-face,record90-text-transform,recordflip-whole-select-font-face,recordflip-whole-text-transform,recordflip-select-font-face,recordflip-text-transform,record-neg-extents-bounded,record-mesh,record-replay-extend-none,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,rectilinear-miter-limit,reflected-stroke,scale-offset-image,scale-offset-similar,stroke-ctm-caps,select-font-face,self-copy,show-glyphs-advance,show-text-current-point,shape-sierpinski,smask,
 smask-image-mask,smask-mask,smask-paint,smask-text,stride-12-image,subsurface,subsurface-scale,surface-pattern,surface-pattern-scale-up,text-antialias-gray,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,transforms,twin,twin-antialias-gray,twin-antialias-mixed,twin-antialias-none,twin-antialias-subpixel,unclosed-strokes,user-font,user-font-proxy,user-font-rescale,world-map,world-map-stroke,world-map-fill,xcb-stress-cache,xcomposite-projection,pthread-show-text,bitmap-font,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3,ft-text-antialias-none,pdf-surface-source,ps-surface-source
+    - export CAIRO_TEST_IGNORE_image_argb32=clip-text,culled-glyphs,halo-transform,overlapping-glyphs,record1414x-select-font-face,record1414x-text-transform,show-glyphs-advance,subsurface,subsurface-scale,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-pattern,text-rotate,text-unhinted-metrics,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
+    - export CAIRO_TEST_IGNORE_image_rgb24=clip-text,culled-glyphs,extended-blend-alpha-mask,halo-transform,overlapping-glyphs,record1414x-select-font-face,record1414x-text-transform,shifted-operator,show-glyphs-advance,subsurface,subsurface-scale,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-pattern,text-rotate,text-unhinted-metrics,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
+    - export CAIRO_TEST_IGNORE_image16_rgb24=a1-bug,aliasing,arc-direction,arc-looping-dash,big-line,bug-spline,bug-84115,bug-bo-ricotz,bug-source-cu,bug-extents,bug-seams,bug-image-compositor,caps,caps-2,caps-05,caps-joins-2,caps-joins-alpha,caps-joins-curve,caps-tails-curve,clear-source,clip-disjoint,clip-disjoint-quad,clip-stroke-unbounded,clip-fill-nz-unbounded,clip-fill-eo-unbounded,clip-fill,clip-image,clip-intersect,clip-operator,clip-push-group,clip-shape,clip-stroke,clip-text,clip-twice,close-path-current-point,copy-path,coverage-rectangles,coverage-rhombus,coverage-intersecting-quads,coverage-intersecting-triangles,coverage-row-triangles,coverage-column-triangles,coverage-triangles,coverage-abutting,culled-glyphs,dash-caps-joins,dash-curve,dash-scale,dash-state,dash-zero-length,degenerate-arc,degenerate-curve-to,degenerate-path,degenerate-pen,degenerate-rel-curve-to,drunkard-tails,extend-pad-border,extended-blend,extended-blend-alpha,extended-blend-mask,extended-blend-alph
 a-mask,extended-blend-solid,extended-blend-solid-alpha,fallback,fill-alpha,fill-alpha-pattern,fill-and-stroke,fill-and-stroke-alpha,fill-and-stroke-alpha-add,fill-degenerate-sort-order,fill-image,fill-missed-stop,fill-rule,filter-bilinear-extents,finer-grained-fallbacks,font-matrix-translation,glyph-cache-pressure,gradient-alpha,gradient-constant-alpha,group-unaligned,halo,halo-transform,hatchings,huge-linear,huge-radial,inverse-text,joins,joins-loop,joins-star,joins-retrace,large-font,large-twin-antialias-mixed,leaky-dashed-stroke,line-width-overlap-offset,line-width-scale,linear-gradient,linear-gradient-reflect,linear-gradient-subset,long-dashed-lines,mask,mask-alpha,mask-ctm,mask-surface-ctm,mask-transformed-image,mask-transformed-similar,mesh-pattern,mesh-pattern-conical,mesh-pattern-control-points,mesh-pattern-fold,mesh-pattern-overlap,mesh-pattern-transformed,new-sub-path,operator-source,over-around-source,overlapping-boxes,overlapping-glyphs,overlapping-dash-caps,paint-source
 -alpha,paint-with-alpha,paint-with-alpha-clip,paint-with-alpha-clip-mask,partial-coverage-reference,partial-coverage-three-quarter-reference,pass-through,path-append,path-stroke-twice,pdf-isolated-group,pixman-downscale-fast-96,pixman-downscale-good-96,pixman-downscale-best-96,pixman-downscale-best-24,pixman-downscale-nearest-96,pixman-downscale-bilinear-96,pixman-rotate,push-group,push-group-color,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,random-clip,random-intersections-eo,random-intersections-nonzero,random-intersections-curves-eo,random-intersections-curves-nz,raster-source,record-paint-alpha,record-paint-alpha-clip,record-paint-alpha-clip-mask,record-fill-alpha,record-select-font-face,record-text-transform,record1414x-paint-alpha,record1414x-paint-alpha-clip,record1414x-paint-alpha-clip-mask,record1414x-fill-alpha,record1414x-select-font-face,record1414x-text-transform,record2x-paint-alpha,record2x-paint-alpha-clip,record2x-paint-al
 pha-clip-mask,record2x-fill-alpha,record2x-select-font-face,record2x-text-transform,record90-paint-alpha,record90-paint-alpha-clip,record90-paint-alpha-clip-mask,record90-fill-alpha,record90-select-font-face,record90-text-transform,recordflip-whole-paint-alpha,recordflip-whole-paint-alpha-clip,recordflip-whole-paint-alpha-clip-mask,recordflip-whole-fill-alpha,recordflip-whole-select-font-face,recordflip-whole-text-transform,recordflip-paint-alpha,recordflip-paint-alpha-clip,recordflip-paint-alpha-clip-mask,recordflip-fill-alpha,recordflip-select-font-face,recordflip-text-transform,record-neg-extents-unbounded,record-neg-extents-bounded,record-mesh,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,rectilinear-dash-scale-unaligned,reflected-stroke,rel-path,rotate-clip-image-surface-paint,rotated-clip,rounded-rect
 angle-fill,rounded-rectangle-stroke,scale-offset-image,scale-offset-similar,stroke-ctm-caps,stroke-image,select-font-face,set-source,shifted-operator,show-glyphs-advance,show-text-current-point,shape-general-convex,shape-sierpinski,simple-edge,smask,smask-fill,smask-mask,smask-paint,smask-stroke,smask-text,spline-decomposition,stroke-pattern,subsurface,subsurface-scale,surface-pattern,surface-pattern-operator,surface-pattern-scale-down,surface-pattern-scale-up,text-antialias-gray,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,tighten-bounds,tiger,a1-tiger,transforms,trap-clip,twin,twin-antialias-gray,twin-antialias-mixed,twin-antialias-subpixel,unbounded-operator,unclosed-strokes,user-font,user-font-mask,user-font-proxy,user-font-rescale,world-map,world-map-stroke,world-map-fill,xcb-huge-image-shm,xcb-huge-subimage,
 xcomposite-projection,pthread-same-source,pthread-show-text,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
+    - export CAIRO_TEST_IGNORE_recording_argb32=bug-source-cu,clear-source,clip-text,coverage-rectangles,culled-glyphs,finer-grained-fallbacks,halo-transform,overlapping-glyphs,record1414x-fill-alpha,record1414x-select-font-face,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-fill-alpha,record2x-text-transform,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,scale-offset-similar,show-glyphs-advance,subsurface,subsurface-scale,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-pattern,text-rotate,text-unhinted-metrics,pthread-same-source,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
+    - export CAIRO_TEST_IGNORE_recording_rgb24=bug-source-cu,clear-source,clip-text,coverage-rectangles,culled-glyphs,extended-blend-alpha-mask,finer-grained-fallbacks,halo-transform,overlapping-glyphs,record1414x-fill-alpha,record1414x-select-font-face,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-fill-alpha,record2x-text-transform,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,scale-offset-similar,show-glyphs-advance,subsurface,subsurface-scale,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-pattern,text-rotate,text-unhinted-metrics,pthread-same-source,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
+    - export CAIRO_TEST_IGNORE_svg11_argb32=alpha-similar,clear-source,clip-operator,clip-text,culled-glyphs,extended-blend-solid,extended-blend-solid-alpha,filter-bilinear-extents,filter-nearest-offset,filter-nearest-transformed,halo-transform,linear-gradient-reflect,mask-transformed-image,operator-alpha-alpha,overlapping-glyphs,paint-source-alpha,paint-with-alpha,paint-with-alpha-clip,paint-with-alpha-clip-mask,radial-gradient,radial-gradient-mask,record-paint-alpha,record-paint-alpha-clip,record-paint-alpha-clip-mask,record1414x-paint-alpha,record1414x-paint-alpha-clip,record1414x-paint-alpha-clip-mask,record1414x-fill-alpha,record1414x-select-font-face,record1414x-text-transform,record2x-paint-alpha,record2x-paint-alpha-clip,record2x-paint-alpha-clip-mask,record90-paint-alpha-clip,record90-paint-alpha-clip-mask,recordflip-whole-paint-alpha,recordflip-whole-paint-alpha-clip,recordflip-whole-paint-alpha-clip-mask,recordflip-paint-alpha,recordflip-paint-alpha-clip,recordflip-paint-
 alpha-clip-mask,scale-offset-image,scale-source-surface-paint,self-copy,show-glyphs-advance,smask,smask-image-mask,smask-mask,smask-paint,smask-stroke,smask-text,surface-pattern,surface-pattern-operator,surface-pattern-scale-up,text-pattern,text-rotate,text-unhinted-metrics,tighten-bounds,unbounded-operator,pthread-similar,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
+    - export CAIRO_TEST_IGNORE_svg11_rgb24=alpha-similar,clear-source,clip-operator,clip-text,culled-glyphs,extended-blend-alpha-mask,extended-blend-solid,extended-blend-solid-alpha,filter-bilinear-extents,filter-nearest-offset,filter-nearest-transformed,gradient-alpha,gradient-constant-alpha,halo-transform,linear-gradient-reflect,mask,mask-transformed-image,operator-alpha-alpha,overlapping-glyphs,paint-source-alpha,paint-with-alpha,paint-with-alpha-clip,paint-with-alpha-clip-mask,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,record-paint-alpha,record-paint-alpha-clip,record-paint-alpha-clip-mask,record1414x-paint-alpha,record1414x-paint-alpha-clip,record1414x-paint-alpha-clip-mask,record1414x-fill-alpha,record1414x-select-font-face,record1414x-text-transform,record2x-paint-alpha,record2x-paint-alpha-clip,record2x-paint-alpha-clip-mask,record90-paint-alpha-clip,record90-paint-alpha-clip-mask,recordflip-whole-paint-alpha,recordflip-whole-pain
 t-alpha-clip,recordflip-whole-paint-alpha-clip-mask,recordflip-paint-alpha,recordflip-paint-alpha-clip,recordflip-paint-alpha-clip-mask,scale-offset-image,scale-source-surface-paint,self-copy,show-glyphs-advance,smask,smask-image-mask,smask-mask,smask-paint,smask-stroke,smask-text,surface-pattern,surface-pattern-operator,surface-pattern-scale-up,text-pattern,text-rotate,text-unhinted-metrics,tighten-bounds,unbounded-operator,pthread-similar,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
+    - export CAIRO_TEST_IGNORE_xcb_argb32=bug-spline,clip-operator,coverage-rectangles,coverage-rhombus,coverage-intersecting-quads,coverage-intersecting-triangles,coverage-row-triangles,coverage-column-triangles,coverage-triangles,culled-glyphs,fill-image,halo,halo-transform,hatchings,operator-source,overlapping-boxes,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,radial-outer-focus,random-clip,record-self-intersecting,record1414x-fill-alpha,record1414x-self-intersecting,record2x-paint-alpha-clip-mask,record2x-fill-alpha,record90-paint-alpha-solid-clip,record90-paint-alpha-clip,record90-self-intersecting,recordflip-whole-paint-alpha-clip-mask,recordflip-whole-fill-alpha,recordflip-whole-self-intersecting,recordflip-paint-alpha-clip-mask,recordflip-self-intersecting,record-neg-extents-unbounded,record-neg-extents-bounded,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,recording-surface-extend-repeat,recording
 -surface-extend-pad,rotated-clip,stroke-clipped,stroke-image,simple-edge,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-rotate,tighten-bounds,a1-tiger,twin-antialias-none,unantialiased-shapes,user-font,user-font-proxy,ft-text-vertical-layout-type1
+    - export CAIRO_TEST_IGNORE_xcb_rgb24=arc-looping-dash,bug-spline,bug-51910,bug-84115,bug-source-cu,bug-image-compositor,caps-2,caps-1,caps-05,caps-joins-2,caps-joins-1,caps-joins-05,clear-source,clip-operator,clip-text,coverage-rectangles,coverage-rhombus,coverage-intersecting-quads,coverage-intersecting-triangles,coverage-row-triangles,coverage-column-triangles,coverage-triangles,coverage-abutting,culled-glyphs,dash-curve,extended-blend-alpha-mask,fallback,fill-image,filter-bilinear-extents,font-matrix-translation,glyph-cache-pressure,halo,halo-transform,hatchings,inverse-text,large-font,linear-gradient,linear-gradient-subset,mask,mask-transformed-image,mask-transformed-similar,operator-alpha-alpha,operator-clear,operator-source,overlapping-boxes,overlapping-glyphs,overlapping-dash-caps,partial-clip-text-bottom,partial-clip-text-left,partial-coverage-reference,partial-coverage-three-quarter-reference,push-group,push-group-color,radial-gradient,radial-gradient-mask,radial-gradie
 nt-source,radial-gradient-mask-source,radial-outer-focus,random-clip,record-self-intersecting,record1414x-fill-alpha,record1414x-self-intersecting,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-fill-alpha,record90-paint-alpha-solid-clip,record90-paint-alpha-clip,record90-fill-alpha,record90-self-intersecting,recordflip-whole-paint-alpha-clip-mask,recordflip-whole-fill-alpha,recordflip-whole-self-intersecting,recordflip-paint-alpha-clip-mask,recordflip-fill-alpha,recordflip-self-intersecting,record-neg-extents-unbounded,record-neg-extents-bounded,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,recording-surface-extend-pad,reflected-stroke,rotated-clip,select-font-face,stroke-clipped,stroke-image,show-glyphs-advance,show-text-current-point,simple-edge,smask,smask-fill,smask-image-mask,smask-
 mask,smask-paint,smask-stroke,smp-glyph,subsurface,subsurface-scale,surface-pattern-operator,surface-pattern-scale-up,text-antialias-gray,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-rotate,text-transform,tighten-bounds,a1-tiger,trap-clip,twin,twin-antialias-gray,twin-antialias-none,twin-antialias-subpixel,unantialiased-shapes,unbounded-operator,user-font,user-font-proxy,world-map,world-map-fill,xcomposite-projection,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
+    - export CAIRO_TEST_IGNORE_xcb_window_rgb24=arc-looping-dash,bug-spline,bug-51910,caps-2,caps-1,caps-05,caps-joins-2,caps-joins-1,caps-joins-05,clear-source,clip-operator,clip-text,coverage-rectangles,coverage-intersecting-quads,coverage-intersecting-triangles,coverage-row-triangles,coverage-column-triangles,coverage-triangles,coverage-abutting,culled-glyphs,extended-blend-alpha-mask,fallback,fill-image,filter-bilinear-extents,font-matrix-translation,glyph-cache-pressure,halo,halo-transform,inverse-text,linear-gradient,linear-gradient-subset,mask,mask-transformed-image,mask-transformed-similar,operator-alpha-alpha,operator-clear,operator-source,overlapping-boxes,overlapping-glyphs,overlapping-dash-caps,partial-clip-text-bottom,partial-clip-text-left,partial-coverage-reference,partial-coverage-three-quarter-reference,push-group,push-group-color,radial-outer-focus,record-self-intersecting,record1414x-fill-alpha,record1414x-self-intersecting,record1414x-text-transform,record2x-pain
 t-alpha-clip-mask,record2x-fill-alpha,record90-paint-alpha-solid-clip,record90-paint-alpha-clip,record90-fill-alpha,record90-self-intersecting,recordflip-whole-paint-alpha-clip-mask,recordflip-whole-fill-alpha,recordflip-whole-self-intersecting,recordflip-paint-alpha-clip-mask,recordflip-fill-alpha,recordflip-self-intersecting,record-neg-extents-unbounded,record-neg-extents-bounded,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,recording-surface-extend-pad,reflected-stroke,rotated-clip,select-font-face,stroke-clipped,stroke-image,show-glyphs-advance,show-text-current-point,simple-edge,smask,smask-fill,smask-image-mask,smask-mask,smask-paint,smask-stroke,smp-glyph,subsurface,subsurface-scale,surface-pattern-operator,surface-pattern-scale-up,text-antialias-gray,text-antialias-subpixel,text-antialias-subpixel-r
 gb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-rotate,text-transform,tighten-bounds,trap-clip,twin,twin-antialias-gray,twin-antialias-none,twin-antialias-subpixel,unantialiased-shapes,unbounded-operator,xcomposite-projection,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
+    - export CAIRO_TEST_IGNORE_xcb_window__rgb24=arc-looping-dash,bug-spline,bug-51910,caps-2,caps-1,caps-05,caps-joins-2,caps-joins-1,caps-joins-05,clear-source,clip-operator,clip-text,coverage-rectangles,coverage-intersecting-quads,coverage-intersecting-triangles,coverage-row-triangles,coverage-column-triangles,coverage-triangles,coverage-abutting,culled-glyphs,extended-blend-alpha-mask,fallback,fill-image,filter-bilinear-extents,font-matrix-translation,glyph-cache-pressure,halo,halo-transform,inverse-text,linear-gradient,linear-gradient-subset,mask,mask-transformed-image,mask-transformed-similar,operator-alpha-alpha,operator-clear,operator-source,overlapping-boxes,overlapping-glyphs,overlapping-dash-caps,partial-clip-text-bottom,partial-clip-text-left,partial-coverage-reference,partial-coverage-three-quarter-reference,push-group,push-group-color,radial-outer-focus,record-self-intersecting,record1414x-fill-alpha,record1414x-self-intersecting,record1414x-text-transform,record2x-pai
 nt-alpha-clip-mask,record2x-fill-alpha,record90-paint-alpha-solid-clip,record90-paint-alpha-clip,record90-fill-alpha,record90-self-intersecting,recordflip-whole-paint-alpha-clip-mask,recordflip-whole-fill-alpha,recordflip-whole-self-intersecting,recordflip-paint-alpha-clip-mask,recordflip-fill-alpha,recordflip-self-intersecting,record-neg-extents-unbounded,record-neg-extents-bounded,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,recording-surface-extend-pad,reflected-stroke,rotated-clip,select-font-face,stroke-clipped,stroke-image,show-glyphs-advance,show-text-current-point,simple-edge,smask,smask-fill,smask-image-mask,smask-mask,smask-paint,smask-stroke,smp-glyph,subsurface,subsurface-scale,surface-pattern-operator,surface-pattern-scale-up,text-antialias-gray,text-antialias-subpixel,text-antialias-subpixel-
 rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-rotate,text-transform,tighten-bounds,trap-clip,twin,twin-antialias-gray,twin-antialias-none,twin-antialias-subpixel,unantialiased-shapes,unbounded-operator,xcomposite-projection,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
+    - export CAIRO_TEST_IGNORE_xcb_render_0_0_argb32=clip-disjoint-hatching,clip-stroke-unbounded,clip-fill-nz-unbounded,clip-fill-eo-unbounded,clip-operator,clip-polygons,clip-shape,clip-twice,coverage-intersecting-triangles,culled-glyphs,hatchings,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,random-clip,record-paint-alpha-solid-clip,record1414x-select-font-face,record1414x-text-transform,record-neg-extents-bounded,record-replay-extend-repeat,record-replay-extend-reflect,rotated-clip,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,trap-clip,ft-text-vertical-layout-type1
+    - export CAIRO_TEST_IGNORE_xcb_render_0_0_rgb24=clip-disjoint-hatching,clip-stroke-unbounded,clip-fill-nz-unbounded,clip-fill-eo-unbounded,clip-operator,clip-polygons,clip-shape,clip-twice,coverage-intersecting-triangles,culled-glyphs,extended-blend-alpha-mask,fallback,hatchings,mask,operator-source,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,random-clip,record-paint-alpha-solid-clip,record1414x-select-font-face,record1414x-text-transform,record-neg-extents-bounded,record-replay-extend-repeat,record-replay-extend-reflect,recording-surface-over,recording-surface-extend-none,rotated-clip,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,trap-clip,ft-text-vertical-layout-type1
+    - export CAIRO_TEST_IGNORE_xcb_fallback_rgb24=clip-text,coverage-intersecting-triangles,culled-glyphs,extended-blend-alpha-mask,fallback,halo-transform,overlapping-glyphs,record1414x-select-font-face,record1414x-text-transform,show-glyphs-advance,subsurface,subsurface-scale,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-pattern,text-rotate,text-unhinted-metrics,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
+    - export CAIRO_TEST_IGNORE_xlib_argb32=aliasing,arc-looping-dash,bug-spline,bug-84115,bug-extents,bug-image-compositor,caps-joins-curve,clip-disjoint,clip-stroke-unbounded,clip-operator,clip-shape,clip-stroke,clip-text,close-path-current-point,coverage-rhombus,coverage-column-triangles,culled-glyphs,dash-caps-joins,dash-curve,dash-scale,degenerate-curve-to,degenerate-pen,degenerate-rel-curve-to,drunkard-tails,extended-blend-alpha-mask,fill-and-stroke,fill-and-stroke-alpha,fill-and-stroke-alpha-add,fill-image,halo,halo-transform,hatchings,joins,joins-loop,joins-retrace,large-twin-antialias-mixed,leaky-dashed-stroke,line-width-scale,line-width-tolerance,long-dashed-lines,new-sub-path,operator-source,overlapping-boxes,overlapping-glyphs,overlapping-dash-caps,path-stroke-twice,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,radial-outer-focus,random-clip,random-intersections-eo,random-intersections-nonzero,random-intersections-curves-eo,random
 -intersections-curves-nz,record-select-font-face,record-self-intersecting,record-text-transform,record1414x-fill-alpha,record1414x-select-font-face,record1414x-self-intersecting,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-fill-alpha,record2x-select-font-face,record2x-text-transform,record90-paint-alpha-solid-clip,record90-paint-alpha-clip,record90-select-font-face,record90-self-intersecting,record90-text-transform,recordflip-whole-paint-alpha-clip-mask,recordflip-whole-fill-alpha,recordflip-whole-select-font-face,recordflip-whole-self-intersecting,recordflip-whole-text-transform,recordflip-paint-alpha-clip-mask,recordflip-select-font-face,recordflip-self-intersecting,recordflip-text-transform,record-neg-extents-unbounded,record-neg-extents-bounded,record-replay-extend-none,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,recording-surface-extend-repeat,recording-surface-extend-pad,reflected-stroke,rel-path,rounded-rectangle-str
 oke,scale-offset-image,scale-offset-similar,stroke-clipped,stroke-image,show-glyphs-advance,shape-general-convex,shape-sierpinski,simple-edge,smask,smask-stroke,smask-text,spline-decomposition,stroke-pattern,subsurface,subsurface-scale,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-pattern,text-rotate,text-unhinted-metrics,tighten-bounds,twin,twin-antialias-gray,twin-antialias-mixed,twin-antialias-none,twin-antialias-subpixel,unclosed-strokes,user-font,user-font-proxy,world-map,world-map-stroke,pthread-show-text,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
+    - export CAIRO_TEST_IGNORE_xlib_rgb24=aliasing,arc-looping-dash,bug-spline,bug-51910,bug-84115,bug-source-cu,bug-extents,bug-image-compositor,caps-joins-05,caps-joins-curve,caps-tails-curve,clear-source,clip-disjoint,clip-stroke-unbounded,clip-operator,clip-shape,clip-stroke,clip-text,close-path-current-point,coverage-rhombus,coverage-column-triangles,coverage-abutting,culled-glyphs,dash-caps-joins,dash-curve,dash-scale,degenerate-curve-to,degenerate-pen,degenerate-rel-curve-to,drunkard-tails,extended-blend-mask,extended-blend-alpha-mask,fallback,fill-and-stroke,fill-and-stroke-alpha,fill-and-stroke-alpha-add,fill-image,filter-bilinear-extents,font-matrix-translation,glyph-cache-pressure,halo,halo-transform,hatchings,infinite-join,inverse-text,joins,joins-loop,joins-star,joins-retrace,large-font,large-twin-antialias-mixed,leaky-dashed-stroke,line-width-scale,line-width-tolerance,linear-gradient,linear-gradient-subset,long-dashed-lines,mask,mask-transformed-image,mask-transformed
 -similar,miter-precision,new-sub-path,operator-alpha-alpha,operator-clear,operator-source,overlapping-boxes,overlapping-glyphs,overlapping-dash-caps,partial-clip-text-bottom,partial-clip-text-left,partial-coverage-reference,partial-coverage-three-quarter-reference,path-stroke-twice,push-group,push-group-color,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,radial-outer-focus,random-clip,random-intersections-eo,random-intersections-nonzero,random-intersections-curves-eo,random-intersections-curves-nz,record-select-font-face,record-self-intersecting,record-text-transform,record1414x-fill-alpha,record1414x-select-font-face,record1414x-self-intersecting,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-fill-alpha,record2x-select-font-face,record2x-text-transform,record90-paint-alpha-solid-clip,record90-paint-alpha-clip,record90-fill-alpha,record90-select-font-face,record90-self-intersecting,record90-text-transform,recordflip-whole
 -paint-alpha-clip-mask,recordflip-whole-fill-alpha,recordflip-whole-select-font-face,recordflip-whole-self-intersecting,recordflip-whole-text-transform,recordflip-paint-alpha-clip-mask,recordflip-fill-alpha,recordflip-select-font-face,recordflip-self-intersecting,recordflip-text-transform,record-neg-extents-unbounded,record-neg-extents-bounded,record-replay-extend-none,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,recording-surface-extend-pad,reflected-stroke,rel-path,rotated-clip,rounded-rectangle-stroke,scale-offset-image,scale-offset-similar,stroke-ctm-caps,stroke-clipped,stroke-image,select-font-face,shifted-operator,show-glyphs-advance,show-text-current-point,shape-general-convex,shape-sierpinski,simple-edge,smask,smask-fill,smask-image-mask,smask-mask,smask-paint,smask-stroke,smask-text,smp-glyph,spli
 ne-decomposition,stroke-pattern,subsurface,subsurface-scale,surface-pattern-operator,surface-pattern-scale-up,text-antialias-gray,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,tighten-bounds,trap-clip,twin,twin-antialias-gray,twin-antialias-mixed,twin-antialias-none,twin-antialias-subpixel,unbounded-operator,unclosed-strokes,user-font,user-font-proxy,world-map,world-map-stroke,world-map-fill,xcomposite-projection,pthread-show-text,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
+    - export CAIRO_TEST_IGNORE_xlib_window_rgb24=aliasing,arc-looping-dash,bug-spline,bug-51910,bug-extents,caps-joins-05,caps-joins-curve,clear-source,clip-disjoint,clip-stroke-unbounded,clip-operator,clip-shape,clip-stroke,clip-text,close-path-current-point,coverage-rectangles,coverage-intersecting-quads,coverage-intersecting-triangles,coverage-row-triangles,coverage-column-triangles,coverage-triangles,coverage-abutting,culled-glyphs,dash-caps-joins,dash-scale,degenerate-curve-to,degenerate-pen,degenerate-rel-curve-to,drunkard-tails,extended-blend-mask,extended-blend-alpha-mask,fallback,fill-and-stroke,fill-and-stroke-alpha,fill-and-stroke-alpha-add,fill-image,filter-bilinear-extents,font-matrix-translation,glyph-cache-pressure,halo,halo-transform,infinite-join,inverse-text,joins,joins-loop,joins-star,joins-retrace,large-twin-antialias-mixed,leaky-dashed-stroke,line-width-scale,line-width-tolerance,linear-gradient,linear-gradient-subset,long-dashed-lines,mask,mask-transformed-imag
 e,mask-transformed-similar,miter-precision,new-sub-path,operator-alpha-alpha,operator-clear,operator-source,overlapping-boxes,overlapping-glyphs,overlapping-dash-caps,partial-clip-text-bottom,partial-clip-text-left,partial-coverage-reference,partial-coverage-three-quarter-reference,path-stroke-twice,push-group,push-group-color,radial-outer-focus,record-select-font-face,record-self-intersecting,record-text-transform,record1414x-fill-alpha,record1414x-select-font-face,record1414x-self-intersecting,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-fill-alpha,record2x-select-font-face,record2x-text-transform,record90-paint-alpha-solid-clip,record90-paint-alpha-clip,record90-fill-alpha,record90-select-font-face,record90-self-intersecting,record90-text-transform,recordflip-whole-paint-alpha-clip-mask,recordflip-whole-fill-alpha,recordflip-whole-select-font-face,recordflip-whole-self-intersecting,recordflip-whole-text-transform,recordflip-paint-alpha-clip-mask,recordflip-f
 ill-alpha,recordflip-select-font-face,recordflip-self-intersecting,recordflip-text-transform,record-neg-extents-unbounded,record-neg-extents-bounded,record-replay-extend-none,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,recording-surface-over,recording-surface-source,recording-surface-extend-none,recording-surface-extend-repeat,recording-surface-extend-reflect,recording-surface-extend-pad,reflected-stroke,rel-path,rotated-clip,rounded-rectangle-stroke,scale-offset-image,scale-offset-similar,stroke-ctm-caps,stroke-clipped,stroke-image,select-font-face,shifted-operator,show-glyphs-advance,show-text-current-point,shape-general-convex,simple-edge,smask,smask-fill,smask-image-mask,smask-mask,smask-paint,smask-stroke,smask-text,smp-glyph,spline-decomposition,stroke-pattern,subsurface,subsurface-scale,surface-pattern-operator,surface-pattern-scale-up,text-antialias-gray,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text
 -antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,tighten-bounds,trap-clip,twin,twin-antialias-gray,twin-antialias-mixed,twin-antialias-none,twin-antialias-subpixel,unbounded-operator,unclosed-strokes,xcomposite-projection,pthread-show-text,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
+    - export CAIRO_TEST_IGNORE_xlib_render_0_0_rgb24=caps-sub-paths,clear-source,clip-operator,clip-push-group,clip-text,clipped-group,coverage-intersecting-triangles,culled-glyphs,curve-to-as-line-to,extended-blend-alpha-mask,fallback,fill-and-stroke,fill-and-stroke-alpha,fill-and-stroke-alpha-add,finer-grained-fallbacks,halo-transform,horizontal-clip,infinite-join,large-twin-antialias-mixed,leaky-polygon,mask,operator-clear,operator-source,overlapping-glyphs,radial-outer-focus,record1414x-select-font-face,record1414x-text-transform,rectilinear-miter-limit,rectilinear-stroke,rel-path,show-glyphs-advance,smask,smask-text,subsurface,subsurface-scale,surface-pattern-operator,text-antialias-gray,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-pattern,text-rotate,text-unhinted-metrics,twin-antialias-gray,twin-antialias-mixed,twin-antialias-none,twin-antialias-subpixel,unbounded-operator,pthrea
 d-show-text,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3
+    - export CAIRO_TEST_IGNORE_xlib_fallback_rgb24=arc-looping-dash,bug-51910,bug-seams,caps,caps-2,caps-1,caps-05,caps-joins-2,caps-joins-1,caps-joins-05,caps-joins-curve,caps-sub-paths,clear-source,clip-disjoint-quad,clip-image,clip-mixed-antialias,clip-push-group,clip-polygons,clip-text,close-path,close-path-current-point,copy-path,coverage-intersecting-quads,coverage-abutting,culled-glyphs,dash-caps-joins,dash-infinite-loop,dash-scale,dash-zero-length,degenerate-curve-to,degenerate-pen,degenerate-rel-curve-to,extended-blend-alpha-mask,fallback,filter-bilinear-extents,finer-grained-fallbacks,font-matrix-translation,glyph-cache-pressure,halo-transform,infinite-join,inverse-text,joins,large-twin-antialias-mixed,leaky-dashed-stroke,leaky-polygon,line-width-scale,line-width-tolerance,long-dashed-lines,mask-transformed-image,mask-transformed-similar,operator-alpha-alpha,over-above-source,over-around-source,over-between-source,overlapping-glyphs,partial-clip-text-bottom,partial-clip-te
 xt-left,partial-coverage-reference,partial-coverage-three-quarter-reference,path-stroke-twice,push-group-color,record1414x-select-font-face,record1414x-text-transform,recording-surface-over,recording-surface-extend-none,rectilinear-miter-limit,reflected-stroke,stroke-ctm-caps,select-font-face,self-copy,shifted-operator,show-glyphs-advance,show-text-current-point,smask,smask-image-mask,smask-mask,smask-paint,smask-text,smp-glyph,subsurface,subsurface-scale,surface-pattern-scale-down-extend-none,surface-pattern-scale-up,text-antialias-gray,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,transforms,twin,twin-antialias-gray,twin-antialias-mixed,twin-antialias-none,twin-antialias-subpixel,unclosed-strokes,xcomposite-projection,pthread-show-text,pthread-similar,ft-show-glyphs-positioning,ft-show-glyphs-table,ft-text-vertic
 al-layout-type1,ft-text-vertical-layout-type3
+    - export CAIRO_BOILERPLATE_OPEN_NO_DAEMON=1
+    - export CAIRO_BOILERPLATE_DO_NOT_CRASH_ON_ANY2PPM_ERROR=1
+    - export ANY2PPM="timeout 3m ./any2ppm"
+    - ulimit -S -s 131072
     - xvfb-run make check V=1 VERBOSE=1
   artifacts:
     when: 'always'
@@ -275,8 +278,7 @@ meson macOS:
     - meson setup -Dpixman:tests=disabled build
     - meson compile --verbose -C build
     # Test cairo-quartz. Other backends should be covered by other jobs
-    - export CAIRO_TEST_UGLY_HACK_TO_IGNORE_QUARTZ_COVERAGE_COLUMN_TRIANGLES=1
-    - export CAIRO_TEST_IGNORE_quartz_argb32=bug-image-compositor,clear,clip-operator,clip-text,coverage-rhombus,culled-glyphs,extended-blend-alpha,extended-blend-mask,extended-blend-alpha-mask,extended-blend-solid-alpha,fallback,font-matrix-translation,glyph-cache-pressure,halo,halo-transform,inverse-text,large-font,negative-stride-image,operator-clear,operator-source,overlapping-glyphs,partial-clip-text-top,partial-clip-text-bottom,partial-clip-text-left,partial-clip-text-right,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,record-paint-alpha-clip-mask,record-fill-alpha,record-select-font-face,record-text-transform,record1414x-select-font-face,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-select-font-face,record2x-text-transform,record90-fill-alpha,record90-select-font-face,record90-text-transform,recordflip-whole-select-font-face,recordflip-whole-text-transform,recordflip-select-font-face,recordflip-text-transform,reco
 rd-neg-extents-bounded,record-mesh,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,select-font-face,show-glyphs-advance,show-text-current-point,simple-edge,smask,smask-text,smp-glyph,subsurface,subsurface-outside-target,subsurface-scale,surface-pattern,text-antialias-gray,text-antialias-none,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,unbounded-operator,user-font-proxy,user-font-rescale,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3,ft-text-antialias-none
-    - export CAIRO_TEST_IGNORE_quartz_rgb24=bug-448,bug-image-compositor,clear,clip-operator,clip-text,coverage-rhombus,culled-glyphs,extended-blend,extended-blend-alpha,extended-blend-mask,extended-blend-alpha-mask,extended-blend-solid,extended-blend-solid-alpha,font-matrix-translation,glyph-cache-pressure,halo,halo-transform,inverse-text,large-font,negative-stride-image,operator-clear,operator-source,overlapping-glyphs,partial-clip-text-top,partial-clip-text-bottom,partial-clip-text-left,partial-clip-text-right,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,record-paint-alpha-clip-mask,record-fill-alpha,record-select-font-face,record-text-transform,record1414x-select-font-face,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-select-font-face,record2x-text-transform,record90-fill-alpha,record90-select-font-face,record90-text-transform,recordflip-whole-select-font-face,recordflip-whole-text-transform,recordflip-select-font-f
 ace,recordflip-text-transform,record-neg-extents-unbounded,record-neg-extents-bounded,record-mesh,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,select-font-face,show-glyphs-advance,show-text-current-point,simple-edge,smask,smask-text,smp-glyph,subsurface,subsurface-scale,text-antialias-gray,text-antialias-none,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,unbounded-operator,user-font-proxy,user-font-rescale,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3,ft-text-antialias-none
+    - export CAIRO_TEST_IGNORE_quartz_argb32=bug-361,bug-431,bug-image-compositor,clear,clip-operator,clip-text,coverage-rhombus,culled-glyphs,extended-blend-alpha,extended-blend-mask,extended-blend-alpha-mask,extended-blend-solid-alpha,fallback,font-matrix-translation,glyph-cache-pressure,halo,halo-transform,inverse-text,large-font,negative-stride-image,operator-clear,operator-source,operator-www,overlapping-glyphs,partial-clip-text-top,partial-clip-text-bottom,partial-clip-text-left,partial-clip-text-right,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,record-paint-alpha-clip-mask,record-fill-alpha,record-select-font-face,record-text-transform,record1414x-select-font-face,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-select-font-face,record2x-text-transform,record90-fill-alpha,record90-select-font-face,record90-text-transform,recordflip-whole-select-font-face,recordflip-whole-text-transform,recordflip-select-font-face,r
 ecordflip-text-transform,record-neg-extents-bounded,record-mesh,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,select-font-face,show-glyphs-advance,show-text-current-point,simple-edge,smask,smask-text,smp-glyph,subsurface,subsurface-outside-target,subsurface-scale,surface-pattern,text-antialias-gray,text-antialias-none,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,unbounded-operator,user-font-proxy,user-font-rescale,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3,ft-text-antialias-none
+    - export CAIRO_TEST_IGNORE_quartz_rgb24=bug-361,bug-431,bug-448,bug-image-compositor,clear,clip-operator,clip-text,coverage-rhombus,culled-glyphs,extended-blend,extended-blend-alpha,extended-blend-mask,extended-blend-alpha-mask,extended-blend-solid,extended-blend-solid-alpha,font-matrix-translation,glyph-cache-pressure,halo,halo-transform,inverse-text,large-font,negative-stride-image,operator-clear,operator-source,operator-www,overlapping-glyphs,partial-clip-text-top,partial-clip-text-bottom,partial-clip-text-left,partial-clip-text-right,radial-gradient,radial-gradient-mask,radial-gradient-source,radial-gradient-mask-source,record-paint-alpha-clip-mask,record-fill-alpha,record-select-font-face,record-text-transform,record1414x-select-font-face,record1414x-text-transform,record2x-paint-alpha-clip-mask,record2x-select-font-face,record2x-text-transform,record90-fill-alpha,record90-select-font-face,record90-text-transform,recordflip-whole-select-font-face,recordflip-whole-text-trans
 form,recordflip-select-font-face,recordflip-text-transform,record-neg-extents-unbounded,record-neg-extents-bounded,record-mesh,record-replay-extend-repeat,record-replay-extend-reflect,record-replay-extend-pad,select-font-face,shifted-operator,show-glyphs-advance,show-text-current-point,simple-edge,smask,smask-text,smp-glyph,subsurface,subsurface-scale,text-antialias-gray,text-antialias-none,text-antialias-subpixel,text-antialias-subpixel-rgb,text-antialias-subpixel-bgr,text-antialias-subpixel-vrgb,text-antialias-subpixel-vbgr,text-glyph-range,text-pattern,text-rotate,text-transform,text-unhinted-metrics,unbounded-operator,user-font-proxy,user-font-rescale,ft-show-glyphs-positioning,ft-text-vertical-layout-type1,ft-text-vertical-layout-type3,ft-text-antialias-none
     - export CAIRO_TEST_TARGET=quartz
     - (cd build/test && srcdir=../../test ./cairo-test-suite)
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 079a6d0b4..8baeecfc2 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -196,7 +196,7 @@ typedef struct _cairo_svg_stream {
     cairo_array_t elements;
 } cairo_svg_stream_t;
 
-cairo_svg_stream_t
+static cairo_svg_stream_t
 _cairo_svg_stream_create ()
 {
     cairo_svg_stream_t svg_stream;
@@ -205,7 +205,7 @@ _cairo_svg_stream_create ()
     return svg_stream;
 }
 
-void
+static void
 _cairo_svg_stream_write (cairo_svg_stream_t *svg_stream,
 			 const void *data,
 			 size_t length)
@@ -236,7 +236,7 @@ _cairo_svg_stream_write (cairo_svg_stream_t *svg_stream,
     _cairo_output_stream_write (last_element->text.output_stream, data, length);
 }
 
-void CAIRO_PRINTF_FORMAT (2, 0)
+static void CAIRO_PRINTF_FORMAT (2, 0)
 _cairo_svg_stream_printf (cairo_svg_stream_t *svg_stream,
 			  const char *fmt,
 			  ...)
@@ -270,7 +270,7 @@ _cairo_svg_stream_printf (cairo_svg_stream_t *svg_stream,
     va_end (ap);
 }
 
-void
+static void
 _cairo_svg_stream_append_paint_dependent (cairo_svg_stream_t *svg_stream,
 					  unsigned int source_id,
 					  enum cairo_svg_stream_paint_dependent_element_type type)
@@ -287,7 +287,7 @@ _cairo_svg_stream_append_paint_dependent (cairo_svg_stream_t *svg_stream,
     }
 }
 
-void
+static void
 _cairo_svg_stream_copy (cairo_svg_stream_t *from,
 			cairo_svg_stream_t *to)
 {
@@ -320,7 +320,7 @@ _cairo_svg_stream_copy (cairo_svg_stream_t *from,
     }
 }
 
-void
+static void
 _cairo_svg_stream_copy_to_output_stream (cairo_svg_stream_t *from,
 					 cairo_output_stream_t *to,
 					 cairo_hash_table_t *paints)
@@ -378,7 +378,7 @@ _cairo_svg_stream_copy_to_output_stream (cairo_svg_stream_t *from,
     }
 }
 
-cairo_status_t
+static cairo_status_t
 _cairo_svg_stream_destroy (cairo_svg_stream_t *svg_stream)
 {
     cairo_status_t status = svg_stream->status;
@@ -1686,10 +1686,11 @@ _cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cair
 	    _cairo_svg_stream_printf (&document->xml_node_filters,
 				      "<filter id=\"filter-remove-color\" "
 				      "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
-				      "<feColorMatrix values=\"0 0 0 0 1 "
-				      /*                   */ "0 0 0 0 1 "
-				      /*                   */ "0 0 0 0 1 "
-				      /*                   */ "0 0 0 1 0\"/>\n"
+				      "<feColorMatrix color-interpolation-filters=\"sRGB\" "
+	                              "values=\"0 0 0 0 1 "
+				      /*    */ "0 0 0 0 1 "
+				      /*    */ "0 0 0 0 1 "
+				      /*    */ "0 0 0 1 0\" />\n"
 				      "</filter>\n");
 	    break;
 	case CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA:
@@ -1697,10 +1698,11 @@ _cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cair
 	    _cairo_svg_stream_printf (&document->xml_node_filters,
 				      "<filter id=\"filter-remove-color-and-invert-alpha\" "
 				      "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
-				      "<feColorMatrix values=\"0 0 0 0 1 "
-				      /*                   */ "0 0 0 0 1 "
-				      /*                   */ "0 0 0 0 1 "
-				      /*                   */ "0 0 0 -1 1\"/>\n"
+				      "<feColorMatrix color-interpolation-filters=\"sRGB\" "
+				      "values=\"0 0 0 0 1 "
+				      /*    */ "0 0 0 0 1 "
+				      /*    */ "0 0 0 0 1 "
+				      /*    */ "0 0 0 -1 1\"/>\n"
 				      "</filter>\n");
 	    break;
 	case CAIRO_SVG_FILTER_COLOR_TO_ALPHA:
@@ -1708,10 +1710,11 @@ _cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cair
 	    _cairo_svg_stream_printf (&document->xml_node_filters,
 				      "<filter id=\"filter-color-to-alpha\" "
 				      "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
-				      "<feColorMatrix values=\"0 0 0 0 1 "
-				      /*                   */ "0 0 0 0 1 "
-				      /*                   */ "0 0 0 0 1 "
-				      /*                   */ "0.2126 0.7152 0.0722 0 0\"/>\n"
+				      "<feColorMatrix color-interpolation-filters=\"sRGB\" "
+				      "values=\"0 0 0 0 1 "
+				      /*    */ "0 0 0 0 1 "
+				      /*    */ "0 0 0 0 1 "
+				      /*    */ "0.2126 0.7152 0.0722 0 0\"/>\n"
 				      "</filter>\n");
 	    break;
 	default:
diff --git a/test/cairo-test-runner.c b/test/cairo-test-runner.c
index e76c75f35..07240a4ec 100644
--- a/test/cairo-test-runner.c
+++ b/test/cairo-test-runner.c
@@ -638,8 +638,8 @@ expect_fail_due_to_env_var (cairo_test_context_t *ctx,
 
     /* Look for the test name in the env var (comma separated) */
     if (env) {
-	while (1) {
-	   char *match = strstr (env, ctx->test_name);
+	for (size_t start = 0;; start += strlen (ctx->test_name)) {
+	   char *match = strstr (env + start, ctx->test_name);
 	   if (!match)
 	       break;
 
@@ -653,7 +653,6 @@ expect_fail_due_to_env_var (cairo_test_context_t *ctx,
 		   break;
 	       }
 	   }
-	   env = match + strlen (ctx->test_name);
 	}
     }
     if (result)
@@ -951,19 +950,7 @@ main (int argc, char **argv)
 		    status = CAIRO_TEST_XFAILURE;
 		} else {
 		    fprintf (stderr, "Test was expected to fail due to an environment variable, but did not!\n");
-		    fprintf (stderr, "Please remove the hack to ignore fallback-resolution failures.\n");
-		    status = CAIRO_TEST_ERROR;
-		}
-	    }
-	    if (getenv ("CAIRO_TEST_UGLY_HACK_TO_IGNORE_FALLBACK_RESOLUTION") && strcmp (ctx.test_name, "fallback-resolution") == 0) {
-		if (status == CAIRO_TEST_FAILURE) {
-		    cairo_test_log (&ctx, "Turning FAIL into XFAIL due to env\n");
-		    fprintf (stderr, "Turning FAIL into XFAIL due to env\n");
-		    runner.num_ignored_via_env++;
-		    status = CAIRO_TEST_XFAILURE;
-		} else {
-		    fprintf (stderr, "Test was expected to fail due to an environment variable, but did not!\n");
-		    fprintf (stderr, "Please remove the hack to ignore fallback-resolution failures.\n");
+		    fprintf (stderr, "Please remove the hack to ignore create-for-stream failures.\n");
 		    status = CAIRO_TEST_ERROR;
 		}
 	    }
@@ -1045,48 +1032,20 @@ main (int argc, char **argv)
 				status = CAIRO_TEST_ERROR;
 			    }
 			}
-			if (getenv ("CAIRO_TEST_UGLY_HACK_TO_IGNORE_SVG_ARGB32_SELF_COPIES")) {
-			    if ((strcmp (target->name, "svg11") == 0 || strcmp (target->name, "svg12") == 0) &&
-					target->content == CAIRO_CONTENT_COLOR_ALPHA &&
-					(strcmp (ctx.test_name, "self-copy") == 0 || strcmp (ctx.test_name, "self-copy-overlap") == 0)) {
-				if (status == CAIRO_TEST_CRASHED) {
-				    cairo_test_log (&ctx, "Turning CRASH into XFAIL due to env\n");
-				    fprintf (stderr, "Turning CRASH into XFAIL due to env\n");
-				    runner.num_ignored_via_env++;
-				    status = CAIRO_TEST_XFAILURE;
-				} else {
-				    fprintf (stderr, "Test was expected to crash due to an environment variable, but did not!\n");
-				    fprintf (stderr, "Please remove the hack to ignore self-copy* crashes for the svg backend.\n");
-				    status = CAIRO_TEST_ERROR;
-				}
-			    }
-			}
-			if (getenv ("CAIRO_TEST_UGLY_HACK_TO_IGNORE_SCRIPT_XCB_HUGE_IMAGE_SHM")) {
+			if (getenv ("CAIRO_TEST_UGLY_HACK_TO_SOMETIMES_IGNORE_SCRIPT_XCB_HUGE_IMAGE_SHM")) {
 			    if (strcmp (target->name, "script") == 0 && strcmp (ctx.test_name, "xcb-huge-image-shm") == 0) {
 				if (status == CAIRO_TEST_FAILURE) {
+				    fprintf (stderr, "This time the xcb-huge-image-shm test on script surface failed.\n");
 				    cairo_test_log (&ctx, "Turning FAIL into XFAIL due to env\n");
 				    fprintf (stderr, "Turning FAIL into XFAIL due to env\n");
 				    runner.num_ignored_via_env++;
-				    status = CAIRO_TEST_XFAILURE;
-				} else {
-				    fprintf (stderr, "Test was expected to fail due to an environment variable, but did not!\n");
-				    fprintf (stderr, "Please remove the hack to ignore xcb-huge-image-shm errors for the script backend.\n");
-				    status = CAIRO_TEST_ERROR;
-				}
-			    }
-			}
-			if (getenv ("CAIRO_TEST_UGLY_HACK_TO_IGNORE_QUARTZ_COVERAGE_COLUMN_TRIANGLES")) {
-			    if (strcmp (target->name, "quartz") == 0 && target->content == CAIRO_CONTENT_COLOR_ALPHA && strcmp (ctx.test_name, "coverage-column-triangles") == 0) {
-				if (status == CAIRO_TEST_FAILURE) {
-				    cairo_test_log (&ctx, "Turning FAIL into XFAIL due to env\n");
-				    fprintf (stderr, "Turning FAIL into XFAIL due to env\n");
-				    runner.num_ignored_via_env++;
-				    status = CAIRO_TEST_XFAILURE;
 				} else {
-				    fprintf (stderr, "Test was expected to fail due to an environment variable, but did not!\n");
-				    fprintf (stderr, "Please remove the hack to ignore xcb-huge-image-shm errors for the script backend.\n");
-				    status = CAIRO_TEST_ERROR;
+				    fprintf (stderr, "This time the xcb-huge-image-shm test on script surface did not fail.\n");
+				    cairo_test_log (&ctx, "Turning the status into XFAIL due to env\n");
+				    fprintf (stderr, "Turning the status into XFAIL due to env\n");
 				}
+				status = CAIRO_TEST_XFAILURE;
+				fprintf (stderr, "If you are were getting one of the outcomes for some time, please update this code.\n");
 			    }
 			}
 			switch (status) {
diff --git a/test/reference/bug-361.image16.rgb24.ref.png b/test/reference/bug-361.image16.rgb24.ref.png
new file mode 100644
index 000000000..1597fd93b
Binary files /dev/null and b/test/reference/bug-361.image16.rgb24.ref.png differ
diff --git a/test/reference/bug-361.xcb-window&.rgb24.ref.png b/test/reference/bug-361.xcb-window&.rgb24.ref.png
new file mode 100644
index 000000000..fc04eda56
Binary files /dev/null and b/test/reference/bug-361.xcb-window&.rgb24.ref.png differ
diff --git a/test/reference/bug-361.xcb-window.rgb24.ref.png b/test/reference/bug-361.xcb-window.rgb24.ref.png
new file mode 100644
index 000000000..fc04eda56
Binary files /dev/null and b/test/reference/bug-361.xcb-window.rgb24.ref.png differ
diff --git a/test/reference/bug-361.xcb.argb32.ref.png b/test/reference/bug-361.xcb.argb32.ref.png
new file mode 100644
index 000000000..79ae2ce18
Binary files /dev/null and b/test/reference/bug-361.xcb.argb32.ref.png differ
diff --git a/test/reference/bug-361.xcb.rgb24.ref.png b/test/reference/bug-361.xcb.rgb24.ref.png
new file mode 100644
index 000000000..fc04eda56
Binary files /dev/null and b/test/reference/bug-361.xcb.rgb24.ref.png differ
diff --git a/test/reference/bug-361.xlib-window.rgb24.ref.png b/test/reference/bug-361.xlib-window.rgb24.ref.png
new file mode 100644
index 000000000..75e405cce
Binary files /dev/null and b/test/reference/bug-361.xlib-window.rgb24.ref.png differ
diff --git a/test/reference/bug-361.xlib.argb32.ref.png b/test/reference/bug-361.xlib.argb32.ref.png
new file mode 100644
index 000000000..2e64e088b
Binary files /dev/null and b/test/reference/bug-361.xlib.argb32.ref.png differ
diff --git a/test/reference/bug-361.xlib.rgb24.ref.png b/test/reference/bug-361.xlib.rgb24.ref.png
new file mode 100644
index 000000000..75e405cce
Binary files /dev/null and b/test/reference/bug-361.xlib.rgb24.ref.png differ
diff --git a/test/reference/bug-431.image16.rgb24.ref.png b/test/reference/bug-431.image16.rgb24.ref.png
new file mode 100644
index 000000000..10ebf3e62
Binary files /dev/null and b/test/reference/bug-431.image16.rgb24.ref.png differ
diff --git a/test/reference/bug-431.pdf.ref.png b/test/reference/bug-431.pdf.ref.png
new file mode 100644
index 000000000..2ff4b3759
Binary files /dev/null and b/test/reference/bug-431.pdf.ref.png differ
diff --git a/test/reference/bug-431.pdf.rgb24.ref.png b/test/reference/bug-431.pdf.rgb24.ref.png
new file mode 100644
index 000000000..57145ce32
Binary files /dev/null and b/test/reference/bug-431.pdf.rgb24.ref.png differ
diff --git a/test/reference/bug-431.xlib-window.rgb24.ref.png b/test/reference/bug-431.xlib-window.rgb24.ref.png
new file mode 100644
index 000000000..208bcfd39
Binary files /dev/null and b/test/reference/bug-431.xlib-window.rgb24.ref.png differ
diff --git a/test/reference/bug-431.xlib.rgb24.ref.png b/test/reference/bug-431.xlib.rgb24.ref.png
new file mode 100644
index 000000000..208bcfd39
Binary files /dev/null and b/test/reference/bug-431.xlib.rgb24.ref.png differ
diff --git a/test/reference/fallback-resolution.ppi144x144.pdf.ref.png b/test/reference/fallback-resolution.ppi144x144.pdf.ref.png
new file mode 100644
index 000000000..df706cdd2
Binary files /dev/null and b/test/reference/fallback-resolution.ppi144x144.pdf.ref.png differ
diff --git a/test/reference/fallback-resolution.ppi144x144.svg.ref.png b/test/reference/fallback-resolution.ppi144x144.svg.ref.png
new file mode 100644
index 000000000..df706cdd2
Binary files /dev/null and b/test/reference/fallback-resolution.ppi144x144.svg.ref.png differ
diff --git a/test/reference/fallback-resolution.ppi144x72.pdf.ref.png b/test/reference/fallback-resolution.ppi144x72.pdf.ref.png
new file mode 100644
index 000000000..ef92955b2
Binary files /dev/null and b/test/reference/fallback-resolution.ppi144x72.pdf.ref.png differ
diff --git a/test/reference/fallback-resolution.ppi144x72.svg.ref.png b/test/reference/fallback-resolution.ppi144x72.svg.ref.png
new file mode 100644
index 000000000..ef92955b2
Binary files /dev/null and b/test/reference/fallback-resolution.ppi144x72.svg.ref.png differ
diff --git a/test/reference/fallback-resolution.ppi288x288.pdf.ref.png b/test/reference/fallback-resolution.ppi288x288.pdf.ref.png
index 181e110fe..94af2cea1 100644
Binary files a/test/reference/fallback-resolution.ppi288x288.pdf.ref.png and b/test/reference/fallback-resolution.ppi288x288.pdf.ref.png differ
diff --git a/test/reference/fallback-resolution.ppi288x288.svg.ref.png b/test/reference/fallback-resolution.ppi288x288.svg.ref.png
new file mode 100644
index 000000000..94af2cea1
Binary files /dev/null and b/test/reference/fallback-resolution.ppi288x288.svg.ref.png differ
diff --git a/test/reference/fallback-resolution.ppi288x72.pdf.ref.png b/test/reference/fallback-resolution.ppi288x72.pdf.ref.png
new file mode 100644
index 000000000..9bb224e98
Binary files /dev/null and b/test/reference/fallback-resolution.ppi288x72.pdf.ref.png differ
diff --git a/test/reference/fallback-resolution.ppi288x72.svg.ref.png b/test/reference/fallback-resolution.ppi288x72.svg.ref.png
new file mode 100644
index 000000000..9bb224e98
Binary files /dev/null and b/test/reference/fallback-resolution.ppi288x72.svg.ref.png differ
diff --git a/test/reference/fallback-resolution.ppi576x576.pdf.ref.png b/test/reference/fallback-resolution.ppi576x576.pdf.ref.png
index 5b376199b..306527634 100644
Binary files a/test/reference/fallback-resolution.ppi576x576.pdf.ref.png and b/test/reference/fallback-resolution.ppi576x576.pdf.ref.png differ
diff --git a/test/reference/fallback-resolution.ppi576x576.svg.ref.png b/test/reference/fallback-resolution.ppi576x576.svg.ref.png
new file mode 100644
index 000000000..306527634
Binary files /dev/null and b/test/reference/fallback-resolution.ppi576x576.svg.ref.png differ
diff --git a/test/reference/fallback-resolution.ppi576x72.pdf.ref.png b/test/reference/fallback-resolution.ppi576x72.pdf.ref.png
new file mode 100644
index 000000000..7d541d8c9
Binary files /dev/null and b/test/reference/fallback-resolution.ppi576x72.pdf.ref.png differ
diff --git a/test/reference/fallback-resolution.ppi576x72.svg.ref.png b/test/reference/fallback-resolution.ppi576x72.svg.ref.png
new file mode 100644
index 000000000..7d541d8c9
Binary files /dev/null and b/test/reference/fallback-resolution.ppi576x72.svg.ref.png differ
diff --git a/test/reference/fallback-resolution.ppi72x144.pdf.ref.png b/test/reference/fallback-resolution.ppi72x144.pdf.ref.png
new file mode 100644
index 000000000..48c7f5b68
Binary files /dev/null and b/test/reference/fallback-resolution.ppi72x144.pdf.ref.png differ
diff --git a/test/reference/fallback-resolution.ppi72x144.svg.ref.png b/test/reference/fallback-resolution.ppi72x144.svg.ref.png
new file mode 100644
index 000000000..48c7f5b68
Binary files /dev/null and b/test/reference/fallback-resolution.ppi72x144.svg.ref.png differ
diff --git a/test/reference/fallback-resolution.ppi72x288.pdf.ref.png b/test/reference/fallback-resolution.ppi72x288.pdf.ref.png
new file mode 100644
index 000000000..8c6b95693
Binary files /dev/null and b/test/reference/fallback-resolution.ppi72x288.pdf.ref.png differ
diff --git a/test/reference/fallback-resolution.ppi72x288.svg.ref.png b/test/reference/fallback-resolution.ppi72x288.svg.ref.png
new file mode 100644
index 000000000..8c6b95693
Binary files /dev/null and b/test/reference/fallback-resolution.ppi72x288.svg.ref.png differ
diff --git a/test/reference/fallback-resolution.ppi72x576.pdf.ref.png b/test/reference/fallback-resolution.ppi72x576.pdf.ref.png
new file mode 100644
index 000000000..c1fac1dc9
Binary files /dev/null and b/test/reference/fallback-resolution.ppi72x576.pdf.ref.png differ
diff --git a/test/reference/fallback-resolution.ppi72x576.svg.ref.png b/test/reference/fallback-resolution.ppi72x576.svg.ref.png
new file mode 100644
index 000000000..c1fac1dc9
Binary files /dev/null and b/test/reference/fallback-resolution.ppi72x576.svg.ref.png differ
diff --git a/test/reference/fallback-resolution.ppi72x72.pdf.ref.png b/test/reference/fallback-resolution.ppi72x72.pdf.ref.png
new file mode 100644
index 000000000..18be8df0c
Binary files /dev/null and b/test/reference/fallback-resolution.ppi72x72.pdf.ref.png differ
diff --git a/test/reference/fallback-resolution.ppi72x72.svg.ref.png b/test/reference/fallback-resolution.ppi72x72.svg.ref.png
new file mode 100644
index 000000000..18be8df0c
Binary files /dev/null and b/test/reference/fallback-resolution.ppi72x72.svg.ref.png differ
diff --git a/test/reference/mime-data.svg.ref.png b/test/reference/mime-data.svg.ref.png
new file mode 100644
index 000000000..1889c6e8d
Binary files /dev/null and b/test/reference/mime-data.svg.ref.png differ
diff --git a/test/reference/operator-www.image16.rgb24.ref.png b/test/reference/operator-www.image16.rgb24.ref.png
new file mode 100644
index 000000000..f62070c94
Binary files /dev/null and b/test/reference/operator-www.image16.rgb24.ref.png differ
diff --git a/test/reference/operator-www.pdf.ref.png b/test/reference/operator-www.pdf.ref.png
new file mode 100644
index 000000000..a8cad4e4c
Binary files /dev/null and b/test/reference/operator-www.pdf.ref.png differ
diff --git a/test/reference/pixman-downscale-best-24.svg.ref.png b/test/reference/pixman-downscale-best-24.svg.ref.png
new file mode 100644
index 000000000..d21ea5a2e
Binary files /dev/null and b/test/reference/pixman-downscale-best-24.svg.ref.png differ
diff --git a/test/reference/pthread-same-source.svg.ref.png b/test/reference/pthread-same-source.svg.ref.png
new file mode 100644
index 000000000..a48886e6c
Binary files /dev/null and b/test/reference/pthread-same-source.svg.ref.png differ
diff --git a/test/reference/pthread-show-text.svg.ref.png b/test/reference/pthread-show-text.svg.ref.png
new file mode 100644
index 000000000..c6b2c3a64
Binary files /dev/null and b/test/reference/pthread-show-text.svg.ref.png differ
diff --git a/test/reference/pthread-similar.svg.ref.png b/test/reference/pthread-similar.svg.ref.png
new file mode 100644
index 000000000..401b1fee7
Binary files /dev/null and b/test/reference/pthread-similar.svg.ref.png differ
diff --git a/test/reference/record-transform-paint.image16.rgb24.ref.png b/test/reference/record-transform-paint.image16.rgb24.ref.png
new file mode 100644
index 000000000..f7f580539
Binary files /dev/null and b/test/reference/record-transform-paint.image16.rgb24.ref.png differ
diff --git a/test/reference/record-transform-paint.pdf.ref.png b/test/reference/record-transform-paint.pdf.ref.png
new file mode 100644
index 000000000..51526e929
Binary files /dev/null and b/test/reference/record-transform-paint.pdf.ref.png differ
diff --git a/test/reference/user-font-mask.svg.ref.png b/test/reference/user-font-mask.svg.ref.png
new file mode 100644
index 000000000..714d1dbc9
Binary files /dev/null and b/test/reference/user-font-mask.svg.ref.png differ
diff --git a/test/shifted-operator.c b/test/shifted-operator.c
index c8b7cc737..70eb15b39 100644
--- a/test/shifted-operator.c
+++ b/test/shifted-operator.c
@@ -37,8 +37,10 @@ draw (cairo_t *cr, int width, int height)
     cairo_rectangle (cr2, 40, 30, 120, 90);
     cairo_set_source_rgba (cr2, 0, 0, 0.9, 0.4);
     cairo_fill (cr2);
+    cairo_destroy (cr2);
 
     cairo_pattern_t *pattern = cairo_pattern_create_for_surface (recording_surface);
+    cairo_surface_destroy(recording_surface);
     cairo_matrix_t matrix;
     cairo_matrix_init_translate (&matrix, -30, -30);
     cairo_pattern_set_matrix (pattern, &matrix);
commit 9e497a3cb82a429a04dbbce8debeba5e0e37cf29
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Mon May 3 23:38:28 2021 +0200

    Introduce CAIRO_BOILERPLATE_OPEN_NO_DAEMON and CAIRO_BOILERPLATE_DO_NOT_CRASH_ON_ANY2PPM_ERROR

diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c
index 383606177..024870a83 100644
--- a/boilerplate/cairo-boilerplate.c
+++ b/boilerplate/cairo-boilerplate.c
@@ -944,7 +944,7 @@ POPEN:
 
     *close_cb = pclose;
     sprintf (command, "%s %s %d", any2ppm, filename, page);
-    return popen (command, "rb");
+    return popen (command, "r");
 }
 
 static cairo_bool_t
@@ -1040,6 +1040,10 @@ cairo_boilerplate_convert_to_image (const char *filename,
     int (*close_cb) (FILE *);
     int ret;
 
+    if (getenv ("CAIRO_BOILERPLATE_OPEN_NO_DAEMON") != NULL) {
+	flags |= CAIRO_BOILERPLATE_OPEN_NO_DAEMON;
+    }
+
   RETRY:
     file = cairo_boilerplate_open_any2ppm (filename, page, flags, &close_cb);
     if (file == NULL) {
@@ -1056,7 +1060,11 @@ cairo_boilerplate_convert_to_image (const char *filename,
     /* check for fatal errors from the interpreter */
     if (ret) { /* any2pmm should never die... */
 	cairo_surface_destroy (image);
-	return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_INVALID_STATUS);
+	if (getenv ("CAIRO_BOILERPLATE_DO_NOT_CRASH_ON_ANY2PPM_ERROR") != NULL) {
+	    return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_WRITE_ERROR);
+	} else {
+	    return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_INVALID_STATUS);
+	}
     }
 
     if (ret == 0 && cairo_surface_status (image) == CAIRO_STATUS_READ_ERROR) {
commit 42128f1742050428dbe9f4570c1d57d64e7975c0
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Mon May 3 22:13:16 2021 +0200

    Fix reference images

diff --git a/test/reference/alpha-similar.svg.argb32.xfail.png b/test/reference/alpha-similar.svg.argb32.xfail.png
deleted file mode 100644
index 2ade632d6..000000000
Binary files a/test/reference/alpha-similar.svg.argb32.xfail.png and /dev/null differ
diff --git a/test/reference/alpha-similar.svg.rgb24.xfail.png b/test/reference/alpha-similar.svg.rgb24.xfail.png
deleted file mode 100644
index c23689855..000000000
Binary files a/test/reference/alpha-similar.svg.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/arc-looping-dash.svg.ref.png b/test/reference/arc-looping-dash.svg.ref.png
new file mode 100644
index 000000000..5195b075e
Binary files /dev/null and b/test/reference/arc-looping-dash.svg.ref.png differ
diff --git a/test/reference/bug-431.svg.rgb24.ref.png b/test/reference/bug-431.svg.rgb24.ref.png
new file mode 100644
index 000000000..9360ee2f8
Binary files /dev/null and b/test/reference/bug-431.svg.rgb24.ref.png differ
diff --git a/test/reference/bug-51910.svg.ref.png b/test/reference/bug-51910.svg.ref.png
new file mode 100644
index 000000000..20df15368
Binary files /dev/null and b/test/reference/bug-51910.svg.ref.png differ
diff --git a/test/reference/bug-84115.svg.ref.png b/test/reference/bug-84115.svg.ref.png
new file mode 100644
index 000000000..26778856a
Binary files /dev/null and b/test/reference/bug-84115.svg.ref.png differ
diff --git a/test/reference/bug-bo-ricotz.svg.rgb24.ref.png b/test/reference/bug-bo-ricotz.svg.rgb24.ref.png
new file mode 100644
index 000000000..1f7346928
Binary files /dev/null and b/test/reference/bug-bo-ricotz.svg.rgb24.ref.png differ
diff --git a/test/reference/bug-image-compositor.svg.ref.png b/test/reference/bug-image-compositor.svg.ref.png
new file mode 100644
index 000000000..8c1c30ab3
Binary files /dev/null and b/test/reference/bug-image-compositor.svg.ref.png differ
diff --git a/test/reference/caps-05.svg.ref.png b/test/reference/caps-05.svg.ref.png
new file mode 100644
index 000000000..8ce8a2d2e
Binary files /dev/null and b/test/reference/caps-05.svg.ref.png differ
diff --git a/test/reference/caps-1.svg.ref.png b/test/reference/caps-1.svg.ref.png
new file mode 100644
index 000000000..91a49f7c6
Binary files /dev/null and b/test/reference/caps-1.svg.ref.png differ
diff --git a/test/reference/caps-2.svg.ref.png b/test/reference/caps-2.svg.ref.png
new file mode 100644
index 000000000..43821fe0f
Binary files /dev/null and b/test/reference/caps-2.svg.ref.png differ
diff --git a/test/reference/caps-joins-05.svg.ref.png b/test/reference/caps-joins-05.svg.ref.png
new file mode 100644
index 000000000..4da2b13c1
Binary files /dev/null and b/test/reference/caps-joins-05.svg.ref.png differ
diff --git a/test/reference/caps-joins-1.svg.ref.png b/test/reference/caps-joins-1.svg.ref.png
new file mode 100644
index 000000000..159ff0e25
Binary files /dev/null and b/test/reference/caps-joins-1.svg.ref.png differ
diff --git a/test/reference/caps-joins-2.svg.ref.png b/test/reference/caps-joins-2.svg.ref.png
new file mode 100644
index 000000000..70faca9dc
Binary files /dev/null and b/test/reference/caps-joins-2.svg.ref.png differ
diff --git a/test/reference/caps-joins-curve.svg.ref.png b/test/reference/caps-joins-curve.svg.ref.png
new file mode 100644
index 000000000..17d6b451d
Binary files /dev/null and b/test/reference/caps-joins-curve.svg.ref.png differ
diff --git a/test/reference/caps-sub-paths.svg.ref.png b/test/reference/caps-sub-paths.svg.ref.png
new file mode 100644
index 000000000..8a5816047
Binary files /dev/null and b/test/reference/caps-sub-paths.svg.ref.png differ
diff --git a/test/reference/caps-tails-curve.svg.ref.png b/test/reference/caps-tails-curve.svg.ref.png
new file mode 100644
index 000000000..fa7e21fea
Binary files /dev/null and b/test/reference/caps-tails-curve.svg.ref.png differ
diff --git a/test/reference/caps.svg.ref.png b/test/reference/caps.svg.ref.png
new file mode 100644
index 000000000..8ec25032a
Binary files /dev/null and b/test/reference/caps.svg.ref.png differ
diff --git a/test/reference/checkerboard.svg.ref.png b/test/reference/checkerboard.svg.ref.png
new file mode 100644
index 000000000..3f0391ca2
Binary files /dev/null and b/test/reference/checkerboard.svg.ref.png differ
diff --git a/test/reference/clear.svg12.argb32.xfail.png b/test/reference/clear.svg12.argb32.xfail.png
deleted file mode 100644
index cb25bcb40..000000000
Binary files a/test/reference/clear.svg12.argb32.xfail.png and /dev/null differ
diff --git a/test/reference/clear.svg12.rgb24.xfail.png b/test/reference/clear.svg12.rgb24.xfail.png
deleted file mode 100644
index cb25bcb40..000000000
Binary files a/test/reference/clear.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/clip-complex-bug61592.svg.ref.png b/test/reference/clip-complex-bug61592.svg.ref.png
new file mode 100644
index 000000000..02abd0e76
Binary files /dev/null and b/test/reference/clip-complex-bug61592.svg.ref.png differ
diff --git a/test/reference/clip-disjoint-quad.svg.ref.png b/test/reference/clip-disjoint-quad.svg.ref.png
new file mode 100644
index 000000000..d24d910b6
Binary files /dev/null and b/test/reference/clip-disjoint-quad.svg.ref.png differ
diff --git a/test/reference/clip-fill-eo-unbounded.svg.ref.png b/test/reference/clip-fill-eo-unbounded.svg.ref.png
new file mode 100644
index 000000000..f16e517c0
Binary files /dev/null and b/test/reference/clip-fill-eo-unbounded.svg.ref.png differ
diff --git a/test/reference/clip-fill-eo-unbounded.svg12.rgb24.xfail.png b/test/reference/clip-fill-eo-unbounded.svg12.rgb24.xfail.png
deleted file mode 100644
index f949de1ad..000000000
Binary files a/test/reference/clip-fill-eo-unbounded.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/clip-fill-nz-unbounded.svg.ref.png b/test/reference/clip-fill-nz-unbounded.svg.ref.png
new file mode 100644
index 000000000..f16e517c0
Binary files /dev/null and b/test/reference/clip-fill-nz-unbounded.svg.ref.png differ
diff --git a/test/reference/clip-fill-nz-unbounded.svg12.rgb24.xfail.png b/test/reference/clip-fill-nz-unbounded.svg12.rgb24.xfail.png
deleted file mode 100644
index f949de1ad..000000000
Binary files a/test/reference/clip-fill-nz-unbounded.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/clip-image.svg.ref.png b/test/reference/clip-image.svg.ref.png
new file mode 100644
index 000000000..8893e0f08
Binary files /dev/null and b/test/reference/clip-image.svg.ref.png differ
diff --git a/test/reference/clip-operator.svg12.argb32.xfail.png b/test/reference/clip-operator.svg12.argb32.xfail.png
deleted file mode 100644
index a1b807226..000000000
Binary files a/test/reference/clip-operator.svg12.argb32.xfail.png and /dev/null differ
diff --git a/test/reference/clip-operator.svg12.rgb24.xfail.png b/test/reference/clip-operator.svg12.rgb24.xfail.png
deleted file mode 100644
index 95227701b..000000000
Binary files a/test/reference/clip-operator.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/clip-push-group.svg.ref.png b/test/reference/clip-push-group.svg.ref.png
index 291b4738b..d6640fe45 100644
Binary files a/test/reference/clip-push-group.svg.ref.png and b/test/reference/clip-push-group.svg.ref.png differ
diff --git a/test/reference/clip-rotate-image-surface-paint.svg.ref.png b/test/reference/clip-rotate-image-surface-paint.svg.ref.png
new file mode 100644
index 000000000..764a4759a
Binary files /dev/null and b/test/reference/clip-rotate-image-surface-paint.svg.ref.png differ
diff --git a/test/reference/clip-stroke-unbounded.svg.ref.png b/test/reference/clip-stroke-unbounded.svg.ref.png
new file mode 100644
index 000000000..1297523ed
Binary files /dev/null and b/test/reference/clip-stroke-unbounded.svg.ref.png differ
diff --git a/test/reference/clip-stroke-unbounded.svg12.rgb24.xfail.png b/test/reference/clip-stroke-unbounded.svg12.rgb24.xfail.png
deleted file mode 100644
index c35fc8326..000000000
Binary files a/test/reference/clip-stroke-unbounded.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/clip-text.svg.ref.png b/test/reference/clip-text.svg.ref.png
deleted file mode 100644
index a113b14ed..000000000
Binary files a/test/reference/clip-text.svg.ref.png and /dev/null differ
diff --git a/test/reference/clip-unbounded.svg12.rgb24.xfail.png b/test/reference/clip-unbounded.svg12.rgb24.xfail.png
deleted file mode 100644
index 0b6590565..000000000
Binary files a/test/reference/clip-unbounded.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/clipped-group.svg.ref.png b/test/reference/clipped-group.svg.ref.png
index 196aec049..55217cace 100644
Binary files a/test/reference/clipped-group.svg.ref.png and b/test/reference/clipped-group.svg.ref.png differ
diff --git a/test/reference/close-path-current-point.svg.ref.png b/test/reference/close-path-current-point.svg.ref.png
new file mode 100644
index 000000000..a162638ce
Binary files /dev/null and b/test/reference/close-path-current-point.svg.ref.png differ
diff --git a/test/reference/close-path.svg.ref.png b/test/reference/close-path.svg.ref.png
new file mode 100644
index 000000000..e57654d27
Binary files /dev/null and b/test/reference/close-path.svg.ref.png differ
diff --git a/test/reference/composite-integer-translate-source.svg12.argb32.xfail.png b/test/reference/composite-integer-translate-source.svg12.argb32.xfail.png
deleted file mode 100644
index c4f319701..000000000
Binary files a/test/reference/composite-integer-translate-source.svg12.argb32.xfail.png and /dev/null differ
diff --git a/test/reference/composite-integer-translate-source.svg12.rgb24.xfail.png b/test/reference/composite-integer-translate-source.svg12.rgb24.xfail.png
deleted file mode 100644
index c4f319701..000000000
Binary files a/test/reference/composite-integer-translate-source.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/copy-path.svg.ref.png b/test/reference/copy-path.svg.ref.png
new file mode 100644
index 000000000..01673eeb5
Binary files /dev/null and b/test/reference/copy-path.svg.ref.png differ
diff --git a/test/reference/dash-caps-joins.svg.ref.png b/test/reference/dash-caps-joins.svg.ref.png
new file mode 100644
index 000000000..55a8c87ef
Binary files /dev/null and b/test/reference/dash-caps-joins.svg.ref.png differ
diff --git a/test/reference/dash-curve.svg.ref.png b/test/reference/dash-curve.svg.ref.png
new file mode 100644
index 000000000..ef4e76b39
Binary files /dev/null and b/test/reference/dash-curve.svg.ref.png differ
diff --git a/test/reference/dash-infinite-loop.svg.ref.png b/test/reference/dash-infinite-loop.svg.ref.png
new file mode 100644
index 000000000..e329b6826
Binary files /dev/null and b/test/reference/dash-infinite-loop.svg.ref.png differ
diff --git a/test/reference/dash-scale.svg.ref.png b/test/reference/dash-scale.svg.ref.png
new file mode 100644
index 000000000..335551fa7
Binary files /dev/null and b/test/reference/dash-scale.svg.ref.png differ
diff --git a/test/reference/dash-state.svg.ref.png b/test/reference/dash-state.svg.ref.png
new file mode 100644
index 000000000..42db6e4c0
Binary files /dev/null and b/test/reference/dash-state.svg.ref.png differ
diff --git a/test/reference/dash-zero-length.svg.ref.png b/test/reference/dash-zero-length.svg.ref.png
new file mode 100644
index 000000000..ffe19affe
Binary files /dev/null and b/test/reference/dash-zero-length.svg.ref.png differ
diff --git a/test/reference/degenerate-arcs.svg.ref.png b/test/reference/degenerate-arcs.svg.ref.png
new file mode 100644
index 000000000..d581ac17b
Binary files /dev/null and b/test/reference/degenerate-arcs.svg.ref.png differ
diff --git a/test/reference/degenerate-curve-to.svg.ref.png b/test/reference/degenerate-curve-to.svg.ref.png
new file mode 100644
index 000000000..1a1b7e49b
Binary files /dev/null and b/test/reference/degenerate-curve-to.svg.ref.png differ
diff --git a/test/reference/degenerate-linear-gradient.svg.ref.png b/test/reference/degenerate-linear-gradient.svg.ref.png
new file mode 100644
index 000000000..06f18b03f
Binary files /dev/null and b/test/reference/degenerate-linear-gradient.svg.ref.png differ
diff --git a/test/reference/degenerate-path.svg.ref.png b/test/reference/degenerate-path.svg.ref.png
new file mode 100644
index 000000000..723d0bc3f
Binary files /dev/null and b/test/reference/degenerate-path.svg.ref.png differ
diff --git a/test/reference/degenerate-pen.svg.ref.png b/test/reference/degenerate-pen.svg.ref.png
new file mode 100644
index 000000000..24e9a4f32
Binary files /dev/null and b/test/reference/degenerate-pen.svg.ref.png differ
diff --git a/test/reference/degenerate-radial-gradient.svg.ref.png b/test/reference/degenerate-radial-gradient.svg.ref.png
new file mode 100644
index 000000000..ba47eb1a9
Binary files /dev/null and b/test/reference/degenerate-radial-gradient.svg.ref.png differ
diff --git a/test/reference/degenerate-rel-curve-to.svg.ref.png b/test/reference/degenerate-rel-curve-to.svg.ref.png
new file mode 100644
index 000000000..5b3ef49ba
Binary files /dev/null and b/test/reference/degenerate-rel-curve-to.svg.ref.png differ
diff --git a/test/reference/device-offset-fractional.svg.ref.png b/test/reference/device-offset-fractional.svg.ref.png
new file mode 100644
index 000000000..7c070937d
Binary files /dev/null and b/test/reference/device-offset-fractional.svg.ref.png differ
diff --git a/test/reference/device-offset-scale.svg.xfail.png b/test/reference/device-offset-scale.svg.xfail.png
deleted file mode 100644
index 58a82d698..000000000
Binary files a/test/reference/device-offset-scale.svg.xfail.png and /dev/null differ
diff --git a/test/reference/extend-pad-border.svg.ref.png b/test/reference/extend-pad-border.svg.ref.png
new file mode 100644
index 000000000..c22743e8f
Binary files /dev/null and b/test/reference/extend-pad-border.svg.ref.png differ
diff --git a/test/reference/extend-pad-border.svg.xfail.png b/test/reference/extend-pad-border.svg.xfail.png
deleted file mode 100644
index 0fde36d90..000000000
Binary files a/test/reference/extend-pad-border.svg.xfail.png and /dev/null differ
diff --git a/test/reference/extend-pad-similar.svg.xfail.png b/test/reference/extend-pad-similar.svg.xfail.png
deleted file mode 100644
index a2cf3530c..000000000
Binary files a/test/reference/extend-pad-similar.svg.xfail.png and /dev/null differ
diff --git a/test/reference/extend-pad.svg.xfail.png b/test/reference/extend-pad.svg.xfail.png
deleted file mode 100644
index a2cf3530c..000000000
Binary files a/test/reference/extend-pad.svg.xfail.png and /dev/null differ
diff --git a/test/reference/extended-blend-alpha.svg12.argb32.xfail.png b/test/reference/extended-blend-alpha.svg12.argb32.xfail.png
deleted file mode 100644
index cc344164f..000000000
Binary files a/test/reference/extended-blend-alpha.svg12.argb32.xfail.png and /dev/null differ
diff --git a/test/reference/extended-blend-alpha.svg12.rgb24.xfail.png b/test/reference/extended-blend-alpha.svg12.rgb24.xfail.png
deleted file mode 100644
index f80569e99..000000000
Binary files a/test/reference/extended-blend-alpha.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/extended-blend.svg12.argb32.xfail.png b/test/reference/extended-blend.svg12.argb32.xfail.png
deleted file mode 100644
index 93297a5c4..000000000
Binary files a/test/reference/extended-blend.svg12.argb32.xfail.png and /dev/null differ
diff --git a/test/reference/extended-blend.svg12.rgb24.xfail.png b/test/reference/extended-blend.svg12.rgb24.xfail.png
deleted file mode 100644
index 8db02c554..000000000
Binary files a/test/reference/extended-blend.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/fallback-resolution.ppi288x288.svg.ref.png b/test/reference/fallback-resolution.ppi288x288.svg.ref.png
deleted file mode 100644
index e71ff8157..000000000
Binary files a/test/reference/fallback-resolution.ppi288x288.svg.ref.png and /dev/null differ
diff --git a/test/reference/fallback-resolution.ppi576x576.svg.ref.png b/test/reference/fallback-resolution.ppi576x576.svg.ref.png
deleted file mode 100644
index b5a97e30d..000000000
Binary files a/test/reference/fallback-resolution.ppi576x576.svg.ref.png and /dev/null differ
diff --git a/test/reference/fallback.svg.ref.png b/test/reference/fallback.svg.ref.png
new file mode 100644
index 000000000..4a83fa180
Binary files /dev/null and b/test/reference/fallback.svg.ref.png differ
diff --git a/test/reference/fallback.svg.rgb24.ref.png b/test/reference/fallback.svg.rgb24.ref.png
new file mode 100644
index 000000000..a352e00c1
Binary files /dev/null and b/test/reference/fallback.svg.rgb24.ref.png differ
diff --git a/test/reference/fill-and-stroke-alpha-add.svg.ref.png b/test/reference/fill-and-stroke-alpha-add.svg.ref.png
new file mode 100644
index 000000000..609ed1f77
Binary files /dev/null and b/test/reference/fill-and-stroke-alpha-add.svg.ref.png differ
diff --git a/test/reference/fill-and-stroke-alpha-add.svg12.xfail.png b/test/reference/fill-and-stroke-alpha-add.svg12.xfail.png
deleted file mode 100644
index c1d7d6fc7..000000000
Binary files a/test/reference/fill-and-stroke-alpha-add.svg12.xfail.png and /dev/null differ
diff --git a/test/reference/fill-and-stroke-alpha.svg.ref.png b/test/reference/fill-and-stroke-alpha.svg.ref.png
new file mode 100644
index 000000000..e1746d5d5
Binary files /dev/null and b/test/reference/fill-and-stroke-alpha.svg.ref.png differ
diff --git a/test/reference/fill-and-stroke.svg.ref.png b/test/reference/fill-and-stroke.svg.ref.png
new file mode 100644
index 000000000..c83640557
Binary files /dev/null and b/test/reference/fill-and-stroke.svg.ref.png differ
diff --git a/test/reference/fill-empty.svg12.rgb24.xfail.png b/test/reference/fill-empty.svg12.rgb24.xfail.png
deleted file mode 100644
index 8c26f7ebf..000000000
Binary files a/test/reference/fill-empty.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/fill-missed-stop.svg.ref.png b/test/reference/fill-missed-stop.svg.ref.png
new file mode 100644
index 000000000..1f580a498
Binary files /dev/null and b/test/reference/fill-missed-stop.svg.ref.png differ
diff --git a/test/reference/filter-nearest-offset.svg.xfail.png b/test/reference/filter-nearest-offset.svg.xfail.png
deleted file mode 100644
index a46dc76d5..000000000
Binary files a/test/reference/filter-nearest-offset.svg.xfail.png and /dev/null differ
diff --git a/test/reference/filter-nearest-transformed.svg.xfail.png b/test/reference/filter-nearest-transformed.svg.xfail.png
deleted file mode 100644
index e6bbe28e8..000000000
Binary files a/test/reference/filter-nearest-transformed.svg.xfail.png and /dev/null differ
diff --git a/test/reference/finer-grained-fallbacks.svg.ref.png b/test/reference/finer-grained-fallbacks.svg.ref.png
new file mode 100644
index 000000000..532181ea1
Binary files /dev/null and b/test/reference/finer-grained-fallbacks.svg.ref.png differ
diff --git a/test/reference/finer-grained-fallbacks.svg12.argb32.ref.png b/test/reference/finer-grained-fallbacks.svg12.argb32.ref.png
deleted file mode 100644
index 5aaf86b27..000000000
Binary files a/test/reference/finer-grained-fallbacks.svg12.argb32.ref.png and /dev/null differ
diff --git a/test/reference/finer-grained-fallbacks.svg12.rgb24.ref.png b/test/reference/finer-grained-fallbacks.svg12.rgb24.ref.png
deleted file mode 100644
index ad55366dd..000000000
Binary files a/test/reference/finer-grained-fallbacks.svg12.rgb24.ref.png and /dev/null differ
diff --git a/test/reference/font-matrix-translation.svg.ref.png b/test/reference/font-matrix-translation.svg.ref.png
index e35f9bea5..98d8bb5bf 100644
Binary files a/test/reference/font-matrix-translation.svg.ref.png and b/test/reference/font-matrix-translation.svg.ref.png differ
diff --git a/test/reference/ft-show-glyphs-positioning.svg.ref.png b/test/reference/ft-show-glyphs-positioning.svg.ref.png
deleted file mode 100644
index 04fe674d1..000000000
Binary files a/test/reference/ft-show-glyphs-positioning.svg.ref.png and /dev/null differ
diff --git a/test/reference/ft-show-glyphs-table.svg.ref.png b/test/reference/ft-show-glyphs-table.svg.ref.png
index e0654b7a0..9097f6d32 100644
Binary files a/test/reference/ft-show-glyphs-table.svg.ref.png and b/test/reference/ft-show-glyphs-table.svg.ref.png differ
diff --git a/test/reference/ft-text-vertical-layout-type1.svg.ref.png b/test/reference/ft-text-vertical-layout-type1.svg.ref.png
deleted file mode 100644
index 0be400c13..000000000
Binary files a/test/reference/ft-text-vertical-layout-type1.svg.ref.png and /dev/null differ
diff --git a/test/reference/ft-text-vertical-layout-type3.svg.ref.png b/test/reference/ft-text-vertical-layout-type3.svg.ref.png
deleted file mode 100644
index cddb955aa..000000000
Binary files a/test/reference/ft-text-vertical-layout-type3.svg.ref.png and /dev/null differ
diff --git a/test/reference/glyph-cache-pressure.svg.ref.png b/test/reference/glyph-cache-pressure.svg.ref.png
new file mode 100644
index 000000000..79ddf29aa
Binary files /dev/null and b/test/reference/glyph-cache-pressure.svg.ref.png differ
diff --git a/test/reference/gradient-alpha.svg.ref.png b/test/reference/gradient-alpha.svg.ref.png
new file mode 100644
index 000000000..399f59694
Binary files /dev/null and b/test/reference/gradient-alpha.svg.ref.png differ
diff --git a/test/reference/gradient-constant-alpha.svg.ref.png b/test/reference/gradient-constant-alpha.svg.ref.png
new file mode 100644
index 000000000..45a19307f
Binary files /dev/null and b/test/reference/gradient-constant-alpha.svg.ref.png differ
diff --git a/test/reference/group-unaligned.svg.argb32.xfail.png b/test/reference/group-unaligned.svg.argb32.xfail.png
deleted file mode 100644
index 01c34bec4..000000000
Binary files a/test/reference/group-unaligned.svg.argb32.xfail.png and /dev/null differ
diff --git a/test/reference/group-unaligned.svg.ref.png b/test/reference/group-unaligned.svg.ref.png
new file mode 100644
index 000000000..4dd1b7194
Binary files /dev/null and b/test/reference/group-unaligned.svg.ref.png differ
diff --git a/test/reference/group-unaligned.svg.rgb24.xfail.png b/test/reference/group-unaligned.svg.rgb24.xfail.png
deleted file mode 100644
index c0f18619b..000000000
Binary files a/test/reference/group-unaligned.svg.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/halo.svg.ref.png b/test/reference/halo.svg.ref.png
new file mode 100644
index 000000000..af31ccfd6
Binary files /dev/null and b/test/reference/halo.svg.ref.png differ
diff --git a/test/reference/huge-radial.svg.ref.png b/test/reference/huge-radial.svg.ref.png
new file mode 100644
index 000000000..3bed71d8c
Binary files /dev/null and b/test/reference/huge-radial.svg.ref.png differ
diff --git a/test/reference/image-surface-source.svg12.argb32.xfail.png b/test/reference/image-surface-source.svg12.argb32.xfail.png
deleted file mode 100644
index 6ebcaf9a1..000000000
Binary files a/test/reference/image-surface-source.svg12.argb32.xfail.png and /dev/null differ
diff --git a/test/reference/image-surface-source.svg12.rgb24.xfail.png b/test/reference/image-surface-source.svg12.rgb24.xfail.png
deleted file mode 100644
index 6ebcaf9a1..000000000
Binary files a/test/reference/image-surface-source.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/infinite-join.svg.ref.png b/test/reference/infinite-join.svg.ref.png
new file mode 100644
index 000000000..15038bd6e
Binary files /dev/null and b/test/reference/infinite-join.svg.ref.png differ
diff --git a/test/reference/inverse-text.svg.ref.png b/test/reference/inverse-text.svg.ref.png
new file mode 100644
index 000000000..276187eab
Binary files /dev/null and b/test/reference/inverse-text.svg.ref.png differ
diff --git a/test/reference/joins.svg.ref.png b/test/reference/joins.svg.ref.png
new file mode 100644
index 000000000..7ad9fb92a
Binary files /dev/null and b/test/reference/joins.svg.ref.png differ
diff --git a/test/reference/large-font.svg.ref.png b/test/reference/large-font.svg.ref.png
new file mode 100644
index 000000000..ced43d447
Binary files /dev/null and b/test/reference/large-font.svg.ref.png differ
diff --git a/test/reference/leaky-dashed-stroke.svg.ref.png b/test/reference/leaky-dashed-stroke.svg.ref.png
new file mode 100644
index 000000000..6d3d9818a
Binary files /dev/null and b/test/reference/leaky-dashed-stroke.svg.ref.png differ
diff --git a/test/reference/leaky-polygon.svg.ref.png b/test/reference/leaky-polygon.svg.ref.png
new file mode 100644
index 000000000..db32c0c8e
Binary files /dev/null and b/test/reference/leaky-polygon.svg.ref.png differ
diff --git a/test/reference/line-width-scale.svg.ref.png b/test/reference/line-width-scale.svg.ref.png
new file mode 100644
index 000000000..9759b084b
Binary files /dev/null and b/test/reference/line-width-scale.svg.ref.png differ
diff --git a/test/reference/line-width-tolerance.svg.ref.png b/test/reference/line-width-tolerance.svg.ref.png
new file mode 100644
index 000000000..f890a52ed
Binary files /dev/null and b/test/reference/line-width-tolerance.svg.ref.png differ
diff --git a/test/reference/linear-gradient-extend.svg.ref.png b/test/reference/linear-gradient-extend.svg.ref.png
new file mode 100644
index 000000000..4c3764cd3
Binary files /dev/null and b/test/reference/linear-gradient-extend.svg.ref.png differ
diff --git a/test/reference/linear-gradient-subset.svg.ref.png b/test/reference/linear-gradient-subset.svg.ref.png
new file mode 100644
index 000000000..f3fafb563
Binary files /dev/null and b/test/reference/linear-gradient-subset.svg.ref.png differ
diff --git a/test/reference/linear-gradient.svg.ref.png b/test/reference/linear-gradient.svg.ref.png
new file mode 100644
index 000000000..64f71b571
Binary files /dev/null and b/test/reference/linear-gradient.svg.ref.png differ
diff --git a/test/reference/long-dashed-lines.svg.ref.png b/test/reference/long-dashed-lines.svg.ref.png
new file mode 100644
index 000000000..8c203a4ca
Binary files /dev/null and b/test/reference/long-dashed-lines.svg.ref.png differ
diff --git a/test/reference/mask-alpha.svg.rgb24.xfail.png b/test/reference/mask-alpha.svg.rgb24.xfail.png
deleted file mode 100644
index 15ebf7559..000000000
Binary files a/test/reference/mask-alpha.svg.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/mask-glyphs.svg.ref.png b/test/reference/mask-glyphs.svg.ref.png
deleted file mode 100644
index bbc44f207..000000000
Binary files a/test/reference/mask-glyphs.svg.ref.png and /dev/null differ
diff --git a/test/reference/mask-transformed-image.svg.ref.png b/test/reference/mask-transformed-image.svg.ref.png
new file mode 100644
index 000000000..35459b7ad
Binary files /dev/null and b/test/reference/mask-transformed-image.svg.ref.png differ
diff --git a/test/reference/mask-transformed-similar.svg.ref.png b/test/reference/mask-transformed-similar.svg.ref.png
index a5b9b00b9..339c71ee1 100644
Binary files a/test/reference/mask-transformed-similar.svg.ref.png and b/test/reference/mask-transformed-similar.svg.ref.png differ
diff --git a/test/reference/mask.svg.argb32.xfail.png b/test/reference/mask.svg.argb32.xfail.png
deleted file mode 100644
index 867248004..000000000
Binary files a/test/reference/mask.svg.argb32.xfail.png and /dev/null differ
diff --git a/test/reference/mask.svg.ref.png b/test/reference/mask.svg.ref.png
new file mode 100644
index 000000000..999f41595
Binary files /dev/null and b/test/reference/mask.svg.ref.png differ
diff --git a/test/reference/mask.svg.rgb24.xfail.png b/test/reference/mask.svg.rgb24.xfail.png
deleted file mode 100644
index 743a758e6..000000000
Binary files a/test/reference/mask.svg.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/mesh-pattern-conical.svg.ref.png b/test/reference/mesh-pattern-conical.svg.ref.png
new file mode 100644
index 000000000..4c830b150
Binary files /dev/null and b/test/reference/mesh-pattern-conical.svg.ref.png differ
diff --git a/test/reference/mesh-pattern-control-points.svg.ref.png b/test/reference/mesh-pattern-control-points.svg.ref.png
new file mode 100644
index 000000000..34445d000
Binary files /dev/null and b/test/reference/mesh-pattern-control-points.svg.ref.png differ
diff --git a/test/reference/mesh-pattern-fold.svg.ref.png b/test/reference/mesh-pattern-fold.svg.ref.png
new file mode 100644
index 000000000..8cf5eb467
Binary files /dev/null and b/test/reference/mesh-pattern-fold.svg.ref.png differ
diff --git a/test/reference/mesh-pattern-overlap.svg.ref.png b/test/reference/mesh-pattern-overlap.svg.ref.png
new file mode 100644
index 000000000..0403b0470
Binary files /dev/null and b/test/reference/mesh-pattern-overlap.svg.ref.png differ
diff --git a/test/reference/mesh-pattern-transformed.svg.ref.png b/test/reference/mesh-pattern-transformed.svg.ref.png
new file mode 100644
index 000000000..fd6b89ff1
Binary files /dev/null and b/test/reference/mesh-pattern-transformed.svg.ref.png differ
diff --git a/test/reference/mesh-pattern.svg.ref.png b/test/reference/mesh-pattern.svg.ref.png
new file mode 100644
index 000000000..812432ce8
Binary files /dev/null and b/test/reference/mesh-pattern.svg.ref.png differ
diff --git a/test/reference/mime-data.svg.ref.png b/test/reference/mime-data.svg.ref.png
deleted file mode 100644
index 1889c6e8d..000000000
Binary files a/test/reference/mime-data.svg.ref.png and /dev/null differ
diff --git a/test/reference/new-sub-path.svg.ref.png b/test/reference/new-sub-path.svg.ref.png
new file mode 100644
index 000000000..d45d4a066
Binary files /dev/null and b/test/reference/new-sub-path.svg.ref.png differ
diff --git a/test/reference/operator-alpha-alpha.svg.xfail.png b/test/reference/operator-alpha-alpha.svg.xfail.png
deleted file mode 100644
index c7dc8cbd3..000000000
Binary files a/test/reference/operator-alpha-alpha.svg.xfail.png and /dev/null differ
diff --git a/test/reference/operator-alpha.svg12.argb32.xfail.png b/test/reference/operator-alpha.svg12.argb32.xfail.png
deleted file mode 100644
index e821d206f..000000000
Binary files a/test/reference/operator-alpha.svg12.argb32.xfail.png and /dev/null differ
diff --git a/test/reference/operator-alpha.svg12.rgb24.xfail.png b/test/reference/operator-alpha.svg12.rgb24.xfail.png
deleted file mode 100644
index 42d9ddee9..000000000
Binary files a/test/reference/operator-alpha.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/operator-clear.svg.ref.png b/test/reference/operator-clear.svg.ref.png
new file mode 100644
index 000000000..257f112ea
Binary files /dev/null and b/test/reference/operator-clear.svg.ref.png differ
diff --git a/test/reference/operator-clear.svg12.argb32.xfail.png b/test/reference/operator-clear.svg12.argb32.xfail.png
deleted file mode 100644
index 7dfbd28fa..000000000
Binary files a/test/reference/operator-clear.svg12.argb32.xfail.png and /dev/null differ
diff --git a/test/reference/operator-clear.svg12.rgb24.xfail.png b/test/reference/operator-clear.svg12.rgb24.xfail.png
deleted file mode 100644
index c561bc36c..000000000
Binary files a/test/reference/operator-clear.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/operator-source.svg.ref.png b/test/reference/operator-source.svg.ref.png
new file mode 100644
index 000000000..376867e87
Binary files /dev/null and b/test/reference/operator-source.svg.ref.png differ
diff --git a/test/reference/operator-www.svg.ref.png b/test/reference/operator-www.svg.ref.png
new file mode 100644
index 000000000..4d7080571
Binary files /dev/null and b/test/reference/operator-www.svg.ref.png differ
diff --git a/test/reference/operator-www.svg.rgb24.ref.png b/test/reference/operator-www.svg.rgb24.ref.png
new file mode 100644
index 000000000..55d24f347
Binary files /dev/null and b/test/reference/operator-www.svg.rgb24.ref.png differ
diff --git a/test/reference/operator.svg12.argb32.xfail.png b/test/reference/operator.svg12.argb32.xfail.png
deleted file mode 100644
index 3996221e7..000000000
Binary files a/test/reference/operator.svg12.argb32.xfail.png and /dev/null differ
diff --git a/test/reference/operator.svg12.rgb24.xfail.png b/test/reference/operator.svg12.rgb24.xfail.png
deleted file mode 100644
index 198d4b1c9..000000000
Binary files a/test/reference/operator.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/over-above-source.svg12.rgb24.xfail.png b/test/reference/over-above-source.svg12.rgb24.xfail.png
deleted file mode 100644
index b2939c24b..000000000
Binary files a/test/reference/over-above-source.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/over-around-source.svg12.argb32.xfail.png b/test/reference/over-around-source.svg12.argb32.xfail.png
deleted file mode 100644
index bb29538d1..000000000
Binary files a/test/reference/over-around-source.svg12.argb32.xfail.png and /dev/null differ
diff --git a/test/reference/over-around-source.svg12.rgb24.xfail.png b/test/reference/over-around-source.svg12.rgb24.xfail.png
deleted file mode 100644
index bb29538d1..000000000
Binary files a/test/reference/over-around-source.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/over-below-source.svg12.argb32.xfail.png b/test/reference/over-below-source.svg12.argb32.xfail.png
deleted file mode 100644
index c80705b7e..000000000
Binary files a/test/reference/over-below-source.svg12.argb32.xfail.png and /dev/null differ
diff --git a/test/reference/over-below-source.svg12.rgb24.xfail.png b/test/reference/over-below-source.svg12.rgb24.xfail.png
deleted file mode 100644
index c80705b7e..000000000
Binary files a/test/reference/over-below-source.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/over-between-source.svg12.argb32.xfail.png b/test/reference/over-between-source.svg12.argb32.xfail.png
deleted file mode 100644
index c80705b7e..000000000
Binary files a/test/reference/over-between-source.svg12.argb32.xfail.png and /dev/null differ
diff --git a/test/reference/over-between-source.svg12.rgb24.xfail.png b/test/reference/over-between-source.svg12.rgb24.xfail.png
deleted file mode 100644
index c80705b7e..000000000
Binary files a/test/reference/over-between-source.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/overlapping-glyphs.svg.argb32.ref.png b/test/reference/overlapping-glyphs.svg.argb32.ref.png
deleted file mode 100644
index ce3849967..000000000
Binary files a/test/reference/overlapping-glyphs.svg.argb32.ref.png and /dev/null differ
diff --git a/test/reference/overlapping-glyphs.svg.rgb24.ref.png b/test/reference/overlapping-glyphs.svg.rgb24.ref.png
deleted file mode 100644
index ce3849967..000000000
Binary files a/test/reference/overlapping-glyphs.svg.rgb24.ref.png and /dev/null differ
diff --git a/test/reference/paint-source-alpha.svg.ref.png b/test/reference/paint-source-alpha.svg.ref.png
deleted file mode 100644
index 763bb592b..000000000
Binary files a/test/reference/paint-source-alpha.svg.ref.png and /dev/null differ
diff --git a/test/reference/paint-with-alpha-solid-clip.svg.ref.png b/test/reference/paint-with-alpha-solid-clip.svg.ref.png
new file mode 100644
index 000000000..034ba6d9b
Binary files /dev/null and b/test/reference/paint-with-alpha-solid-clip.svg.ref.png differ
diff --git a/test/reference/paint-with-alpha.svg.ref.png b/test/reference/paint-with-alpha.svg.ref.png
deleted file mode 100644
index c0df8eb72..000000000
Binary files a/test/reference/paint-with-alpha.svg.ref.png and /dev/null differ
diff --git a/test/reference/partial-clip-text-bottom.svg.ref.png b/test/reference/partial-clip-text-bottom.svg.ref.png
new file mode 100644
index 000000000..267f0cc74
Binary files /dev/null and b/test/reference/partial-clip-text-bottom.svg.ref.png differ
diff --git a/test/reference/partial-clip-text-left.svg.ref.png b/test/reference/partial-clip-text-left.svg.ref.png
new file mode 100644
index 000000000..e47088091
Binary files /dev/null and b/test/reference/partial-clip-text-left.svg.ref.png differ
diff --git a/test/reference/partial-clip-text-right.svg.ref.png b/test/reference/partial-clip-text-right.svg.ref.png
new file mode 100644
index 000000000..9c0bdb8f9
Binary files /dev/null and b/test/reference/partial-clip-text-right.svg.ref.png differ
diff --git a/test/reference/partial-clip-text-top.svg.ref.png b/test/reference/partial-clip-text-top.svg.ref.png
index dc3fc5869..c445867cd 100644
Binary files a/test/reference/partial-clip-text-top.svg.ref.png and b/test/reference/partial-clip-text-top.svg.ref.png differ
diff --git a/test/reference/path-stroke-twice.svg.ref.png b/test/reference/path-stroke-twice.svg.ref.png
new file mode 100644
index 000000000..10763bfd8
Binary files /dev/null and b/test/reference/path-stroke-twice.svg.ref.png differ
diff --git a/test/reference/pdf-surface-source.svg12.argb32.xfail.png b/test/reference/pdf-surface-source.svg12.argb32.xfail.png
deleted file mode 100644
index 6ebcaf9a1..000000000
Binary files a/test/reference/pdf-surface-source.svg12.argb32.xfail.png and /dev/null differ
diff --git a/test/reference/pdf-surface-source.svg12.rgb24.xfail.png b/test/reference/pdf-surface-source.svg12.rgb24.xfail.png
deleted file mode 100644
index 6ebcaf9a1..000000000
Binary files a/test/reference/pdf-surface-source.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/pixman-downscale-best-95.svg11.ref.png b/test/reference/pixman-downscale-best-95.svg.ref.png
similarity index 100%
rename from test/reference/pixman-downscale-best-95.svg11.ref.png
rename to test/reference/pixman-downscale-best-95.svg.ref.png
diff --git a/test/reference/pixman-downscale-bilinear-24.svg.ref.png b/test/reference/pixman-downscale-bilinear-24.svg.ref.png
new file mode 100644
index 000000000..d21ea5a2e
Binary files /dev/null and b/test/reference/pixman-downscale-bilinear-24.svg.ref.png differ
diff --git a/test/reference/pixman-downscale-fast-24.svg.ref.png b/test/reference/pixman-downscale-fast-24.svg.ref.png
new file mode 100644
index 000000000..d21ea5a2e
Binary files /dev/null and b/test/reference/pixman-downscale-fast-24.svg.ref.png differ
diff --git a/test/reference/pixman-downscale-best-95.svg12.ref.png b/test/reference/pixman-downscale-fast-95.svg.ref.png
similarity index 100%
rename from test/reference/pixman-downscale-best-95.svg12.ref.png
rename to test/reference/pixman-downscale-fast-95.svg.ref.png
diff --git a/test/reference/pixman-downscale-fast-95.svg12.ref.png b/test/reference/pixman-downscale-fast-95.svg12.ref.png
deleted file mode 100644
index 777f448e3..000000000
Binary files a/test/reference/pixman-downscale-fast-95.svg12.ref.png and /dev/null differ
diff --git a/test/reference/pixman-downscale-good-24.svg.ref.png b/test/reference/pixman-downscale-good-24.svg.ref.png
new file mode 100644
index 000000000..d21ea5a2e
Binary files /dev/null and b/test/reference/pixman-downscale-good-24.svg.ref.png differ
diff --git a/test/reference/pixman-downscale-nearest-24.svg.ref.png b/test/reference/pixman-downscale-nearest-24.svg.ref.png
new file mode 100644
index 000000000..d21ea5a2e
Binary files /dev/null and b/test/reference/pixman-downscale-nearest-24.svg.ref.png differ
diff --git a/test/reference/pixman-downscale-fast-95.svg11.ref.png b/test/reference/pixman-downscale-nearest-95.svg.ref.png
similarity index 100%
rename from test/reference/pixman-downscale-fast-95.svg11.ref.png
rename to test/reference/pixman-downscale-nearest-95.svg.ref.png
diff --git a/test/reference/pixman-downscale-nearest-95.svg11.ref.png b/test/reference/pixman-downscale-nearest-95.svg11.ref.png
deleted file mode 100644
index 777f448e3..000000000
Binary files a/test/reference/pixman-downscale-nearest-95.svg11.ref.png and /dev/null differ
diff --git a/test/reference/pixman-downscale-nearest-95.svg12.ref.png b/test/reference/pixman-downscale-nearest-95.svg12.ref.png
deleted file mode 100644
index 777f448e3..000000000
Binary files a/test/reference/pixman-downscale-nearest-95.svg12.ref.png and /dev/null differ
diff --git a/test/reference/pixman-rotate.svg.ref.png b/test/reference/pixman-rotate.svg.ref.png
new file mode 100644
index 000000000..91d75d0f6
Binary files /dev/null and b/test/reference/pixman-rotate.svg.ref.png differ
diff --git a/test/reference/ps-surface-source.svg12.argb32.xfail.png b/test/reference/ps-surface-source.svg12.argb32.xfail.png
deleted file mode 100644
index 6ebcaf9a1..000000000
Binary files a/test/reference/ps-surface-source.svg12.argb32.xfail.png and /dev/null differ
diff --git a/test/reference/ps-surface-source.svg12.rgb24.xfail.png b/test/reference/ps-surface-source.svg12.rgb24.xfail.png
deleted file mode 100644
index 6ebcaf9a1..000000000
Binary files a/test/reference/ps-surface-source.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/push-group-color.svg.ref.png b/test/reference/push-group-color.svg.ref.png
new file mode 100644
index 000000000..f0cefa6ca
Binary files /dev/null and b/test/reference/push-group-color.svg.ref.png differ
diff --git a/test/reference/push-group.svg.ref.png b/test/reference/push-group.svg.ref.png
new file mode 100644
index 000000000..a7bcc1f36
Binary files /dev/null and b/test/reference/push-group.svg.ref.png differ
diff --git a/test/reference/radial-gradient-extend.svg.ref.png b/test/reference/radial-gradient-extend.svg.ref.png
new file mode 100644
index 000000000..fb7878535
Binary files /dev/null and b/test/reference/radial-gradient-extend.svg.ref.png differ
diff --git a/test/reference/radial-gradient-mask-source.svg.ref.png b/test/reference/radial-gradient-mask-source.svg.ref.png
new file mode 100644
index 000000000..92b13e39a
Binary files /dev/null and b/test/reference/radial-gradient-mask-source.svg.ref.png differ
diff --git a/test/reference/radial-gradient-mask.svg.ref.png b/test/reference/radial-gradient-mask.svg.ref.png
new file mode 100644
index 000000000..8ed24c641
Binary files /dev/null and b/test/reference/radial-gradient-mask.svg.ref.png differ
diff --git a/test/reference/radial-gradient-one-stop.svg.ref.png b/test/reference/radial-gradient-one-stop.svg.ref.png
new file mode 100644
index 000000000..16ff29db8
Binary files /dev/null and b/test/reference/radial-gradient-one-stop.svg.ref.png differ
diff --git a/test/reference/radial-gradient-source.ref.png b/test/reference/radial-gradient-source.ref.png
index c5c494966..cf7b0c96a 100644
Binary files a/test/reference/radial-gradient-source.ref.png and b/test/reference/radial-gradient-source.ref.png differ
diff --git a/test/reference/radial-gradient-source.svg.ref.png b/test/reference/radial-gradient-source.svg.ref.png
new file mode 100644
index 000000000..fd788826c
Binary files /dev/null and b/test/reference/radial-gradient-source.svg.ref.png differ
diff --git a/test/reference/radial-gradient.svg.ref.png b/test/reference/radial-gradient.svg.ref.png
new file mode 100644
index 000000000..baf9c2ff5
Binary files /dev/null and b/test/reference/radial-gradient.svg.ref.png differ
diff --git a/test/reference/record-fill-alpha.svg.ref.png b/test/reference/record-fill-alpha.svg.ref.png
new file mode 100644
index 000000000..25c1ac68f
Binary files /dev/null and b/test/reference/record-fill-alpha.svg.ref.png differ
diff --git a/test/reference/record-mesh.svg.ref.png b/test/reference/record-mesh.svg.ref.png
new file mode 100644
index 000000000..6e781b1a4
Binary files /dev/null and b/test/reference/record-mesh.svg.ref.png differ
diff --git a/test/reference/record-neg-extents-bounded.svg.ref.png b/test/reference/record-neg-extents-bounded.svg.ref.png
new file mode 100644
index 000000000..9f7524f84
Binary files /dev/null and b/test/reference/record-neg-extents-bounded.svg.ref.png differ
diff --git a/test/reference/record-neg-extents-unbounded.svg.ref.png b/test/reference/record-neg-extents-unbounded.svg.ref.png
new file mode 100644
index 000000000..9f7524f84
Binary files /dev/null and b/test/reference/record-neg-extents-unbounded.svg.ref.png differ
diff --git a/test/reference/record-paint-alpha-solid-clip.svg.ref.png b/test/reference/record-paint-alpha-solid-clip.svg.ref.png
new file mode 100644
index 000000000..034ba6d9b
Binary files /dev/null and b/test/reference/record-paint-alpha-solid-clip.svg.ref.png differ
diff --git a/test/reference/record-replay-extend-pad.svg.ref.png b/test/reference/record-replay-extend-pad.svg.ref.png
new file mode 100644
index 000000000..c07fa7036
Binary files /dev/null and b/test/reference/record-replay-extend-pad.svg.ref.png differ
diff --git a/test/reference/record-replay-extend-reflect.svg.ref.png b/test/reference/record-replay-extend-reflect.svg.ref.png
new file mode 100644
index 000000000..903451d93
Binary files /dev/null and b/test/reference/record-replay-extend-reflect.svg.ref.png differ
diff --git a/test/reference/record-replay-extend-repeat.svg.ref.png b/test/reference/record-replay-extend-repeat.svg.ref.png
new file mode 100644
index 000000000..5e0746b39
Binary files /dev/null and b/test/reference/record-replay-extend-repeat.svg.ref.png differ
diff --git a/test/reference/record-replay-extend-repeat.svg.rgb24.ref.png b/test/reference/record-replay-extend-repeat.svg.rgb24.ref.png
new file mode 100644
index 000000000..3f52c58b2
Binary files /dev/null and b/test/reference/record-replay-extend-repeat.svg.rgb24.ref.png differ
diff --git a/test/reference/record-select-font-face.svg.ref.png b/test/reference/record-select-font-face.svg.ref.png
new file mode 100644
index 000000000..2ab46d10a
Binary files /dev/null and b/test/reference/record-select-font-face.svg.ref.png differ
diff --git a/test/reference/record-text-transform.svg.ref.png b/test/reference/record-text-transform.svg.ref.png
new file mode 100644
index 000000000..684e93b92
Binary files /dev/null and b/test/reference/record-text-transform.svg.ref.png differ
diff --git a/test/reference/record1414x-fill-alpha.svg.ref.png b/test/reference/record1414x-fill-alpha.svg.ref.png
new file mode 100644
index 000000000..4c4060331
Binary files /dev/null and b/test/reference/record1414x-fill-alpha.svg.ref.png differ
diff --git a/test/reference/record1414x-paint-alpha-solid-clip.svg.ref.png b/test/reference/record1414x-paint-alpha-solid-clip.svg.ref.png
new file mode 100644
index 000000000..ea9be2be3
Binary files /dev/null and b/test/reference/record1414x-paint-alpha-solid-clip.svg.ref.png differ
diff --git a/test/reference/record1414x-paint.svg.ref.png b/test/reference/record1414x-paint.svg.ref.png
new file mode 100644
index 000000000..38e79a319
Binary files /dev/null and b/test/reference/record1414x-paint.svg.ref.png differ
diff --git a/test/reference/record1414x-self-intersecting.svg.ref.png b/test/reference/record1414x-self-intersecting.svg.ref.png
new file mode 100644
index 000000000..3276de513
Binary files /dev/null and b/test/reference/record1414x-self-intersecting.svg.ref.png differ
diff --git a/test/reference/record2x-fill-alpha.svg.ref.png b/test/reference/record2x-fill-alpha.svg.ref.png
new file mode 100644
index 000000000..7ecd5717b
Binary files /dev/null and b/test/reference/record2x-fill-alpha.svg.ref.png differ
diff --git a/test/reference/record2x-paint-alpha-solid-clip.svg.ref.png b/test/reference/record2x-paint-alpha-solid-clip.svg.ref.png
new file mode 100644
index 000000000..b22ac6d38
Binary files /dev/null and b/test/reference/record2x-paint-alpha-solid-clip.svg.ref.png differ
diff --git a/test/reference/record2x-select-font-face.svg.ref.png b/test/reference/record2x-select-font-face.svg.ref.png
new file mode 100644
index 000000000..3dd20c46d
Binary files /dev/null and b/test/reference/record2x-select-font-face.svg.ref.png differ
diff --git a/test/reference/record2x-text-transform.svg.ref.png b/test/reference/record2x-text-transform.svg.ref.png
new file mode 100644
index 000000000..356c03292
Binary files /dev/null and b/test/reference/record2x-text-transform.svg.ref.png differ
diff --git a/test/reference/record90-fill-alpha.svg.ref.png b/test/reference/record90-fill-alpha.svg.ref.png
new file mode 100644
index 000000000..1dacde30a
Binary files /dev/null and b/test/reference/record90-fill-alpha.svg.ref.png differ
diff --git a/test/reference/record90-paint-alpha-solid-clip.svg.ref.png b/test/reference/record90-paint-alpha-solid-clip.svg.ref.png
new file mode 100644
index 000000000..260be2199
Binary files /dev/null and b/test/reference/record90-paint-alpha-solid-clip.svg.ref.png differ
diff --git a/test/reference/record90-select-font-face.svg.ref.png b/test/reference/record90-select-font-face.svg.ref.png
new file mode 100644
index 000000000..c64c5090d
Binary files /dev/null and b/test/reference/record90-select-font-face.svg.ref.png differ
diff --git a/test/reference/record90-self-intersecting.svg.ref.png b/test/reference/record90-self-intersecting.svg.ref.png
new file mode 100644
index 000000000..15ce4c005
Binary files /dev/null and b/test/reference/record90-self-intersecting.svg.ref.png differ
diff --git a/test/reference/record90-text-transform.svg.ref.png b/test/reference/record90-text-transform.svg.ref.png
new file mode 100644
index 000000000..5fc2f4011
Binary files /dev/null and b/test/reference/record90-text-transform.svg.ref.png differ
diff --git a/test/reference/recordflip-fill-alpha.svg.ref.png b/test/reference/recordflip-fill-alpha.svg.ref.png
new file mode 100644
index 000000000..69035ef5f
Binary files /dev/null and b/test/reference/recordflip-fill-alpha.svg.ref.png differ
diff --git a/test/reference/recordflip-select-font-face.svg.ref.png b/test/reference/recordflip-select-font-face.svg.ref.png
new file mode 100644
index 000000000..31ac171b6
Binary files /dev/null and b/test/reference/recordflip-select-font-face.svg.ref.png differ
diff --git a/test/reference/recordflip-text-transform.svg.ref.png b/test/reference/recordflip-text-transform.svg.ref.png
new file mode 100644
index 000000000..4a3a1105f
Binary files /dev/null and b/test/reference/recordflip-text-transform.svg.ref.png differ
diff --git a/test/reference/recordflip-whole-select-font-face.svg.ref.png b/test/reference/recordflip-whole-select-font-face.svg.ref.png
new file mode 100644
index 000000000..31ac171b6
Binary files /dev/null and b/test/reference/recordflip-whole-select-font-face.svg.ref.png differ
diff --git a/test/reference/recordflip-whole-text-transform.svg.ref.png b/test/reference/recordflip-whole-text-transform.svg.ref.png
new file mode 100644
index 000000000..4a3a1105f
Binary files /dev/null and b/test/reference/recordflip-whole-text-transform.svg.ref.png differ
diff --git a/test/reference/recording-surface-extend-none.svg.ref.png b/test/reference/recording-surface-extend-none.svg.ref.png
new file mode 100644
index 000000000..0c86fe40a
Binary files /dev/null and b/test/reference/recording-surface-extend-none.svg.ref.png differ
diff --git a/test/reference/recording-surface-extend-reflect.svg.ref.png b/test/reference/recording-surface-extend-reflect.svg.ref.png
new file mode 100644
index 000000000..e975c7f7f
Binary files /dev/null and b/test/reference/recording-surface-extend-reflect.svg.ref.png differ
diff --git a/test/reference/recording-surface-extend-repeat.svg.ref.png b/test/reference/recording-surface-extend-repeat.svg.ref.png
new file mode 100644
index 000000000..2938781b5
Binary files /dev/null and b/test/reference/recording-surface-extend-repeat.svg.ref.png differ
diff --git a/test/reference/recording-surface-extend-repeat.svg.rgb24.ref.png b/test/reference/recording-surface-extend-repeat.svg.rgb24.ref.png
new file mode 100644
index 000000000..e04fe7e2e
Binary files /dev/null and b/test/reference/recording-surface-extend-repeat.svg.rgb24.ref.png differ
diff --git a/test/reference/recording-surface-over.svg.argb32.ref.png b/test/reference/recording-surface-over.svg.argb32.ref.png
deleted file mode 100644
index ff4154d61..000000000
Binary files a/test/reference/recording-surface-over.svg.argb32.ref.png and /dev/null differ
diff --git a/test/reference/recording-surface-over.svg.ref.png b/test/reference/recording-surface-over.svg.ref.png
new file mode 100644
index 000000000..0c86fe40a
Binary files /dev/null and b/test/reference/recording-surface-over.svg.ref.png differ
diff --git a/test/reference/recording-surface-over.svg.rgb24.ref.png b/test/reference/recording-surface-over.svg.rgb24.ref.png
deleted file mode 100644
index d2d537241..000000000
Binary files a/test/reference/recording-surface-over.svg.rgb24.ref.png and /dev/null differ
diff --git a/test/reference/recording-surface-source.svg.ref.png b/test/reference/recording-surface-source.svg.ref.png
new file mode 100644
index 000000000..0c86fe40a
Binary files /dev/null and b/test/reference/recording-surface-source.svg.ref.png differ
diff --git a/test/reference/rectilinear-dash-scale-unaligned.svg.ref.png b/test/reference/rectilinear-dash-scale-unaligned.svg.ref.png
new file mode 100644
index 000000000..63622f56e
Binary files /dev/null and b/test/reference/rectilinear-dash-scale-unaligned.svg.ref.png differ
diff --git a/test/reference/rectilinear-dash-scale.svg.ref.png b/test/reference/rectilinear-dash-scale.svg.ref.png
new file mode 100644
index 000000000..3c0c9b93a
Binary files /dev/null and b/test/reference/rectilinear-dash-scale.svg.ref.png differ
diff --git a/test/reference/rectilinear-miter-limit.svg.ref.png b/test/reference/rectilinear-miter-limit.svg.ref.png
new file mode 100644
index 000000000..ee8a66656
Binary files /dev/null and b/test/reference/rectilinear-miter-limit.svg.ref.png differ
diff --git a/test/reference/reflected-stroke.svg.ref.png b/test/reference/reflected-stroke.svg.ref.png
new file mode 100644
index 000000000..efae740da
Binary files /dev/null and b/test/reference/reflected-stroke.svg.ref.png differ
diff --git a/test/reference/rel-path.svg.ref.png b/test/reference/rel-path.svg.ref.png
new file mode 100644
index 000000000..4f36ad50b
Binary files /dev/null and b/test/reference/rel-path.svg.ref.png differ
diff --git a/test/reference/rotate-clip-image-surface-paint.svg.ref.png b/test/reference/rotate-clip-image-surface-paint.svg.ref.png
new file mode 100644
index 000000000..c1e357e94
Binary files /dev/null and b/test/reference/rotate-clip-image-surface-paint.svg.ref.png differ
diff --git a/test/reference/rotate-image-surface-paint.svg.ref.png b/test/reference/rotate-image-surface-paint.svg.ref.png
index e0db2452e..8d8d59b09 100644
Binary files a/test/reference/rotate-image-surface-paint.svg.ref.png and b/test/reference/rotate-image-surface-paint.svg.ref.png differ
diff --git a/test/reference/rotate-image-surface-paint.svg.xfail.png b/test/reference/rotate-image-surface-paint.svg.xfail.png
deleted file mode 100644
index 4040784b9..000000000
Binary files a/test/reference/rotate-image-surface-paint.svg.xfail.png and /dev/null differ
diff --git a/test/reference/scale-offset-similar.svg.ref.png b/test/reference/scale-offset-similar.svg.ref.png
new file mode 100644
index 000000000..30ec6b8b0
Binary files /dev/null and b/test/reference/scale-offset-similar.svg.ref.png differ
diff --git a/test/reference/scale-source-surface-paint.svg.argb32.xfail.png b/test/reference/scale-source-surface-paint.svg.argb32.xfail.png
deleted file mode 100644
index ed946d4d4..000000000
Binary files a/test/reference/scale-source-surface-paint.svg.argb32.xfail.png and /dev/null differ
diff --git a/test/reference/scale-source-surface-paint.svg.rgb24.xfail.png b/test/reference/scale-source-surface-paint.svg.rgb24.xfail.png
deleted file mode 100644
index 7d065d405..000000000
Binary files a/test/reference/scale-source-surface-paint.svg.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/select-font-face.svg.ref.png b/test/reference/select-font-face.svg.ref.png
new file mode 100644
index 000000000..2ab46d10a
Binary files /dev/null and b/test/reference/select-font-face.svg.ref.png differ
diff --git a/test/reference/set-source.svg.ref.png b/test/reference/set-source.svg.ref.png
new file mode 100644
index 000000000..f4a4fae12
Binary files /dev/null and b/test/reference/set-source.svg.ref.png differ
diff --git a/test/reference/shape-sierpinski.svg.ref.png b/test/reference/shape-sierpinski.svg.ref.png
new file mode 100644
index 000000000..601d3575c
Binary files /dev/null and b/test/reference/shape-sierpinski.svg.ref.png differ
diff --git a/test/reference/shifted-operator.rgb24.ref.png b/test/reference/shifted-operator.rgb24.ref.png
index 6fc9ad30d..4627fff6d 100644
Binary files a/test/reference/shifted-operator.rgb24.ref.png and b/test/reference/shifted-operator.rgb24.ref.png differ
diff --git a/test/reference/shifted-operator.svg.rgb24.ref.png b/test/reference/shifted-operator.svg.rgb24.ref.png
deleted file mode 100644
index 6fc9ad30d..000000000
Binary files a/test/reference/shifted-operator.svg.rgb24.ref.png and /dev/null differ
diff --git a/test/reference/show-glyphs-advance.svg.ref.png b/test/reference/show-glyphs-advance.svg.ref.png
deleted file mode 100644
index 914d4d69f..000000000
Binary files a/test/reference/show-glyphs-advance.svg.ref.png and /dev/null differ
diff --git a/test/reference/show-text-current-point.svg.ref.png b/test/reference/show-text-current-point.svg.ref.png
new file mode 100644
index 000000000..0baa57268
Binary files /dev/null and b/test/reference/show-text-current-point.svg.ref.png differ
diff --git a/test/reference/smask-fill.svg.ref.png b/test/reference/smask-fill.svg.ref.png
index 824e8cff1..d3983a0ae 100644
Binary files a/test/reference/smask-fill.svg.ref.png and b/test/reference/smask-fill.svg.ref.png differ
diff --git a/test/reference/smask-image-mask.svg.ref.png b/test/reference/smask-image-mask.svg.ref.png
new file mode 100644
index 000000000..6bbf2d32a
Binary files /dev/null and b/test/reference/smask-image-mask.svg.ref.png differ
diff --git a/test/reference/smask-mask.svg.ref.png b/test/reference/smask-mask.svg.ref.png
index ae46036f4..963aea64a 100644
Binary files a/test/reference/smask-mask.svg.ref.png and b/test/reference/smask-mask.svg.ref.png differ
diff --git a/test/reference/smask-paint.svg.ref.png b/test/reference/smask-paint.svg.ref.png
index 93a423fe5..00500e41f 100644
Binary files a/test/reference/smask-paint.svg.ref.png and b/test/reference/smask-paint.svg.ref.png differ
diff --git a/test/reference/smask-stroke.svg.ref.png b/test/reference/smask-stroke.svg.ref.png
new file mode 100644
index 000000000..feb367a71
Binary files /dev/null and b/test/reference/smask-stroke.svg.ref.png differ
diff --git a/test/reference/smask-text.svg.ref.png b/test/reference/smask-text.svg.ref.png
index 65f225ea8..88cae9bee 100644
Binary files a/test/reference/smask-text.svg.ref.png and b/test/reference/smask-text.svg.ref.png differ
diff --git a/test/reference/smask.svg.ref.png b/test/reference/smask.svg.ref.png
index b9c0308d2..b5a6d9eaa 100644
Binary files a/test/reference/smask.svg.ref.png and b/test/reference/smask.svg.ref.png differ
diff --git a/test/reference/smp-glyph.svg.ref.png b/test/reference/smp-glyph.svg.ref.png
new file mode 100644
index 000000000..d15848ce1
Binary files /dev/null and b/test/reference/smp-glyph.svg.ref.png differ
diff --git a/test/reference/spline-decomposition.svg.ref.png b/test/reference/spline-decomposition.svg.ref.png
index 5afa09498..99fd1d637 100644
Binary files a/test/reference/spline-decomposition.svg.ref.png and b/test/reference/spline-decomposition.svg.ref.png differ
diff --git a/test/reference/stroke-ctm-caps.svg.ref.png b/test/reference/stroke-ctm-caps.svg.ref.png
new file mode 100644
index 000000000..dbc6415dc
Binary files /dev/null and b/test/reference/stroke-ctm-caps.svg.ref.png differ
diff --git a/test/reference/stroke-pattern.svg.ref.png b/test/reference/stroke-pattern.svg.ref.png
new file mode 100644
index 000000000..985f91f50
Binary files /dev/null and b/test/reference/stroke-pattern.svg.ref.png differ
diff --git a/test/reference/surface-pattern-scale-down.svg.ref.png b/test/reference/surface-pattern-scale-down.svg.ref.png
new file mode 100644
index 000000000..fd82dc53c
Binary files /dev/null and b/test/reference/surface-pattern-scale-down.svg.ref.png differ
diff --git a/test/reference/surface-pattern.svg.xfail.png b/test/reference/surface-pattern.svg.xfail.png
deleted file mode 100644
index cdbcf476b..000000000
Binary files a/test/reference/surface-pattern.svg.xfail.png and /dev/null differ
diff --git a/test/reference/svg-surface-source.base.argb32.ref.png b/test/reference/svg-surface-source.base.argb32.ref.png
deleted file mode 100644
index 018297208..000000000
Binary files a/test/reference/svg-surface-source.base.argb32.ref.png and /dev/null differ
diff --git a/test/reference/svg-surface-source.base.rgb24.ref.png b/test/reference/svg-surface-source.base.rgb24.ref.png
deleted file mode 100644
index 0d68a82cc..000000000
Binary files a/test/reference/svg-surface-source.base.rgb24.ref.png and /dev/null differ
diff --git a/test/reference/svg-surface-source.image16.ref.png b/test/reference/svg-surface-source.image16.ref.png
deleted file mode 100644
index 2a7460e28..000000000
Binary files a/test/reference/svg-surface-source.image16.ref.png and /dev/null differ
diff --git a/test/reference/svg-surface-source.ps.rgb24.ref.png b/test/reference/svg-surface-source.ps.rgb24.ref.png
deleted file mode 100644
index 26cbb57c4..000000000
Binary files a/test/reference/svg-surface-source.ps.rgb24.ref.png and /dev/null differ
diff --git a/test/reference/svg-surface-source.ref.png b/test/reference/svg-surface-source.ref.png
deleted file mode 100644
index 018297208..000000000
Binary files a/test/reference/svg-surface-source.ref.png and /dev/null differ
diff --git a/test/reference/svg-surface-source.svg12.argb32.xfail.png b/test/reference/svg-surface-source.svg12.argb32.xfail.png
deleted file mode 100644
index 6ebcaf9a1..000000000
Binary files a/test/reference/svg-surface-source.svg12.argb32.xfail.png and /dev/null differ
diff --git a/test/reference/svg-surface-source.svg12.rgb24.xfail.png b/test/reference/svg-surface-source.svg12.rgb24.xfail.png
deleted file mode 100644
index 6ebcaf9a1..000000000
Binary files a/test/reference/svg-surface-source.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/text-glyph-range.svg.ref.png b/test/reference/text-glyph-range.svg.ref.png
new file mode 100644
index 000000000..e194be7e5
Binary files /dev/null and b/test/reference/text-glyph-range.svg.ref.png differ
diff --git a/test/reference/text-pattern.svg.argb32.ref.png b/test/reference/text-pattern.svg.argb32.ref.png
deleted file mode 100644
index f472858f9..000000000
Binary files a/test/reference/text-pattern.svg.argb32.ref.png and /dev/null differ
diff --git a/test/reference/text-pattern.svg.rgb24.ref.png b/test/reference/text-pattern.svg.rgb24.ref.png
deleted file mode 100644
index 2b2064ece..000000000
Binary files a/test/reference/text-pattern.svg.rgb24.ref.png and /dev/null differ
diff --git a/test/reference/text-rotate.svg.ref.png b/test/reference/text-rotate.svg.ref.png
deleted file mode 100644
index 9d887a02f..000000000
Binary files a/test/reference/text-rotate.svg.ref.png and /dev/null differ
diff --git a/test/reference/text-transform.svg.ref.png b/test/reference/text-transform.svg.ref.png
index 1473a643a..684e93b92 100644
Binary files a/test/reference/text-transform.svg.ref.png and b/test/reference/text-transform.svg.ref.png differ
diff --git a/test/reference/tiger.svg.ref.png b/test/reference/tiger.svg.ref.png
new file mode 100644
index 000000000..5b9a5ad67
Binary files /dev/null and b/test/reference/tiger.svg.ref.png differ
diff --git a/test/reference/transforms.svg.ref.png b/test/reference/transforms.svg.ref.png
new file mode 100644
index 000000000..d6bff0a02
Binary files /dev/null and b/test/reference/transforms.svg.ref.png differ
diff --git a/test/reference/trap-clip.svg.ref.png b/test/reference/trap-clip.svg.ref.png
new file mode 100644
index 000000000..0bc8231bb
Binary files /dev/null and b/test/reference/trap-clip.svg.ref.png differ
diff --git a/test/reference/twin.svg.ref.png b/test/reference/twin.svg.ref.png
index 628a83c76..ce209c330 100644
Binary files a/test/reference/twin.svg.ref.png and b/test/reference/twin.svg.ref.png differ
diff --git a/test/reference/unbounded-operator.svg12.argb32.ref.png b/test/reference/unbounded-operator.svg12.argb32.ref.png
deleted file mode 100644
index 45b173fae..000000000
Binary files a/test/reference/unbounded-operator.svg12.argb32.ref.png and /dev/null differ
diff --git a/test/reference/unbounded-operator.svg12.rgb24.xfail.png b/test/reference/unbounded-operator.svg12.rgb24.xfail.png
deleted file mode 100644
index 828a9db97..000000000
Binary files a/test/reference/unbounded-operator.svg12.rgb24.xfail.png and /dev/null differ
diff --git a/test/reference/unclosed-strokes.svg.ref.png b/test/reference/unclosed-strokes.svg.ref.png
new file mode 100644
index 000000000..17b161f54
Binary files /dev/null and b/test/reference/unclosed-strokes.svg.ref.png differ
diff --git a/test/reference/user-font-mask.svg.ref.png b/test/reference/user-font-mask.svg.ref.png
deleted file mode 100644
index 1a8f2c8cc..000000000
Binary files a/test/reference/user-font-mask.svg.ref.png and /dev/null differ
diff --git a/test/reference/user-font-proxy.svg.ref.png b/test/reference/user-font-proxy.svg.ref.png
index 6c458485d..106583e0f 100644
Binary files a/test/reference/user-font-proxy.svg.ref.png and b/test/reference/user-font-proxy.svg.ref.png differ
diff --git a/test/reference/user-font-rescale.svg.ref.png b/test/reference/user-font-rescale.svg.ref.png
index 6ed2a1924..048c6e907 100644
Binary files a/test/reference/user-font-rescale.svg.ref.png and b/test/reference/user-font-rescale.svg.ref.png differ
diff --git a/test/reference/user-font.svg.ref.png b/test/reference/user-font.svg.ref.png
index 1ff6ea0fe..b89e92d20 100644
Binary files a/test/reference/user-font.svg.ref.png and b/test/reference/user-font.svg.ref.png differ
diff --git a/test/reference/world-map-fill.svg.ref.png b/test/reference/world-map-fill.svg.ref.png
new file mode 100644
index 000000000..a29e71215
Binary files /dev/null and b/test/reference/world-map-fill.svg.ref.png differ
diff --git a/test/reference/world-map-stroke.svg.ref.png b/test/reference/world-map-stroke.svg.ref.png
new file mode 100644
index 000000000..dc4190d3d
Binary files /dev/null and b/test/reference/world-map-stroke.svg.ref.png differ
diff --git a/test/reference/world-map.svg.ref.png b/test/reference/world-map.svg.ref.png
new file mode 100644
index 000000000..acf818476
Binary files /dev/null and b/test/reference/world-map.svg.ref.png differ
diff --git a/test/reference/xlib-surface-source.svg12.argb32.xfail.png b/test/reference/xlib-surface-source.svg12.argb32.xfail.png
deleted file mode 100644
index 6ebcaf9a1..000000000
Binary files a/test/reference/xlib-surface-source.svg12.argb32.xfail.png and /dev/null differ
diff --git a/test/reference/xlib-surface-source.svg12.rgb24.xfail.png b/test/reference/xlib-surface-source.svg12.rgb24.xfail.png
deleted file mode 100644
index 6ebcaf9a1..000000000
Binary files a/test/reference/xlib-surface-source.svg12.rgb24.xfail.png and /dev/null differ
commit 5b678d818566bc1fd1abe3ab41662f13ffa39687
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Mon May 3 14:58:19 2021 +0200

    Fix applying shifted operators

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 436dccbe0..079a6d0b4 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -58,6 +58,16 @@
 #include "cairo-surface-snapshot-inline.h"
 #include "cairo-svg-surface-private.h"
 
+/**
+ * SECTION:cairo-svg
+ * @Title: SVG Surfaces
+ * @Short_Description: Rendering SVG documents
+ * @See_Also: #cairo_surface_t
+ *
+ * The SVG surface is used to render cairo graphics to
+ * SVG files and is a multi-page vector surface backend.
+ **/
+
 typedef struct _cairo_svg_source_surface {
     cairo_hash_entry_t base;
     unsigned int id;
@@ -158,7 +168,14 @@ _cairo_svg_paint_box_add_padding (cairo_box_double_t *box)
 
 enum cairo_svg_stream_element_type {
     CAIRO_SVG_STREAM_ELEMENT_TYPE_TEXT,
-    CAIRO_SVG_STREAM_ELEMENT_TYPE_RECTANGLE,
+    CAIRO_SVG_STREAM_ELEMENT_TYPE_PAINT_DEPENDENT,
+};
+
+enum cairo_svg_stream_paint_dependent_element_type {
+    CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE,
+    CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE_AT_ORIGIN,
+    CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_TRANSLATION,
+    CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_INVERSE_TRANSLATION,
 };
 
 typedef struct _cairo_svg_stream_element {
@@ -169,7 +186,8 @@ typedef struct _cairo_svg_stream_element {
 	} text;
         struct {
 	    unsigned int source_id;
-        } rectangle;
+	    enum cairo_svg_stream_paint_dependent_element_type type;
+        } paint_dependent;
     };
 } cairo_svg_stream_element_t;
 
@@ -253,14 +271,16 @@ _cairo_svg_stream_printf (cairo_svg_stream_t *svg_stream,
 }
 
 void
-_cairo_svg_stream_append_rectangle (cairo_svg_stream_t *svg_stream,
-				    unsigned int source_id)
+_cairo_svg_stream_append_paint_dependent (cairo_svg_stream_t *svg_stream,
+					  unsigned int source_id,
+					  enum cairo_svg_stream_paint_dependent_element_type type)
 {
     cairo_status_t status;
 
     cairo_svg_stream_element_t element;
-    element.type = CAIRO_SVG_STREAM_ELEMENT_TYPE_RECTANGLE;
-    element.rectangle.source_id = source_id;
+    element.type = CAIRO_SVG_STREAM_ELEMENT_TYPE_PAINT_DEPENDENT;
+    element.paint_dependent.source_id = source_id;
+    element.paint_dependent.type = type;
     status = _cairo_array_append (&svg_stream->elements, &element);
     if (svg_stream->status == CAIRO_STATUS_SUCCESS) {
 	svg_stream->status = status;
@@ -317,21 +337,43 @@ _cairo_svg_stream_copy_to_output_stream (cairo_svg_stream_t *from,
 	if (element->type == CAIRO_SVG_STREAM_ELEMENT_TYPE_TEXT) {
 	    _cairo_memory_stream_copy (element->text.output_stream, to);
 	}
-	if (element->type == CAIRO_SVG_STREAM_ELEMENT_TYPE_RECTANGLE) {
+	if (element->type == CAIRO_SVG_STREAM_ELEMENT_TYPE_PAINT_DEPENDENT) {
 	    cairo_svg_paint_t paint_key;
-	    paint_key.source_id = element->rectangle.source_id;
+	    paint_key.source_id = element->paint_dependent.source_id;
 	    _cairo_svg_paint_init_key (&paint_key);
 
 	    cairo_svg_paint_t *found_paint_entry = _cairo_hash_table_lookup (paints,
 									     &paint_key.base);
 	    assert (found_paint_entry);
 
-	    _cairo_output_stream_printf (to,
-					 " x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\"",
-					 found_paint_entry->box.p1.x,
-					 found_paint_entry->box.p1.y,
-					 found_paint_entry->box.p2.x - found_paint_entry->box.p1.x,
-					 found_paint_entry->box.p2.y - found_paint_entry->box.p1.y);
+	    switch (element->paint_dependent.type) {
+	    case CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE:
+		_cairo_output_stream_printf (to,
+					     " x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\"",
+					     found_paint_entry->box.p1.x,
+					     found_paint_entry->box.p1.y,
+					     found_paint_entry->box.p2.x - found_paint_entry->box.p1.x,
+					     found_paint_entry->box.p2.y - found_paint_entry->box.p1.y);
+		break;
+	    case CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE_AT_ORIGIN:
+		_cairo_output_stream_printf (to,
+					     " x=\"0\" y=\"0\" width=\"%f\" height=\"%f\"",
+					     found_paint_entry->box.p2.x - found_paint_entry->box.p1.x,
+					     found_paint_entry->box.p2.y - found_paint_entry->box.p1.y);
+		break;
+	    case CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_TRANSLATION:
+		_cairo_output_stream_printf (to,
+					     " transform=\"translate(%f, %f)\"",
+					     found_paint_entry->box.p1.x,
+					     found_paint_entry->box.p1.y);
+		break;
+	    case CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_INVERSE_TRANSLATION:
+		_cairo_output_stream_printf (to,
+					     " transform=\"translate(%f, %f)\"",
+					     -found_paint_entry->box.p1.x,
+					     -found_paint_entry->box.p1.y);
+		break;
+	    }
 	}
     }
 }
@@ -353,16 +395,6 @@ _cairo_svg_stream_destroy (cairo_svg_stream_t *svg_stream)
     return status;
 }
 
-/**
- * SECTION:cairo-svg
- * @Title: SVG Surfaces
- * @Short_Description: Rendering SVG documents
- * @See_Also: #cairo_surface_t
- *
- * The SVG surface is used to render cairo graphics to
- * SVG files and is a multi-page vector surface backend.
- **/
-
 /**
  * CAIRO_HAS_SVG_SURFACE:
  *
@@ -547,7 +579,8 @@ _cairo_svg_surface_emit_composite_pattern (cairo_svg_stream_t *output,
 static cairo_status_t
 _cairo_svg_surface_emit_paint (cairo_svg_stream_t *output,
 			       cairo_svg_surface_t *surface,
-			       const cairo_pattern_t *source);
+			       const cairo_pattern_t *source,
+			       cairo_bool_t at_origin);
 
 static const cairo_surface_backend_t cairo_svg_surface_backend;
 static const cairo_paginated_surface_backend_t cairo_svg_surface_paginated_backend;
@@ -1411,7 +1444,9 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document,
     svg_surface->transitive_paint_used = TRUE;
 
     _cairo_svg_stream_printf (&document->xml_node_glyphs, "<rect");
-    _cairo_svg_stream_append_rectangle (&document->xml_node_glyphs, source_id);
+    _cairo_svg_stream_append_paint_dependent (&document->xml_node_glyphs,
+					      source_id,
+					      CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE);
     _cairo_svg_stream_printf (&document->xml_node_glyphs,
 			      " mask=\"url(#mask-%d)\"",
 			      mask_id);
@@ -1700,29 +1735,55 @@ _cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cair
     _cairo_svg_stream_printf (&surface->document->xml_node_filters, \
                               "<filter id=\"filter-%d\" " \
                               "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n" \
-                              "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\" x=\"0\" y=\"0\"/>\n" \
-                              "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\" x=\"0\" y=\"0\"/>\n" \
+                              "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"", \
+                              filter_id, \
+                              source_compositing_group_id); \
+    _cairo_svg_stream_append_paint_dependent (&surface->document->xml_node_filters, \
+                                              surface->source_id, \
+                                              CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE_AT_ORIGIN); \
+    _cairo_svg_stream_printf (&surface->document->xml_node_filters, \
+                              "/>\n" \
+                              "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"", \
+                              destination_compositing_group_id); \
+    _cairo_svg_stream_append_paint_dependent (&surface->document->xml_node_filters, \
+                                              surface->source_id, \
+                                              CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE_AT_ORIGIN); \
+    _cairo_svg_stream_printf (&surface->document->xml_node_filters, \
+                              "/>\n" \
                               "<feComposite in=\"source\" in2=\"destination\" " \
                               "operator=\"" operation "\" " \
                               "color-interpolation-filters=\"sRGB\"/>\n" \
                               "</filter>\n", \
                               filter_id, \
                               source_compositing_group_id, \
-                              destination_compositing_group_id)
+                              destination_compositing_group_id);
 
 #define _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER(mode) \
     _cairo_svg_stream_printf (&surface->document->xml_node_filters, \
                               "<filter id=\"filter-%d\" " \
                               "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n" \
-                              "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\" x=\"0\" y=\"0\"/>\n" \
-                              "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\" x=\"0\" y=\"0\"/>\n" \
+                              "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"", \
+                              filter_id, \
+                              source_compositing_group_id); \
+    _cairo_svg_stream_append_paint_dependent (&surface->document->xml_node_filters, \
+                                              surface->source_id, \
+                                              CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE_AT_ORIGIN); \
+    _cairo_svg_stream_printf (&surface->document->xml_node_filters, \
+                              "/>\n" \
+                              "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"", \
+                              destination_compositing_group_id); \
+    _cairo_svg_stream_append_paint_dependent (&surface->document->xml_node_filters, \
+                                              surface->source_id, \
+                                              CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE_AT_ORIGIN); \
+    _cairo_svg_stream_printf (&surface->document->xml_node_filters, \
+                              "/>\n" \
                               "<feBlend in=\"source\" in2=\"destination\" " \
                               "mode=\"" mode "\" " \
                               "color-interpolation-filters=\"sRGB\"/>\n" \
                               "</filter>\n", \
                               filter_id, \
                               source_compositing_group_id, \
-                              destination_compositing_group_id)
+                              destination_compositing_group_id);
 
 static unsigned int
 _cairo_svg_surface_emit_parametric_filter (cairo_svg_surface_t *surface,
@@ -1733,82 +1794,91 @@ _cairo_svg_surface_emit_parametric_filter (cairo_svg_surface_t *surface,
     unsigned int filter_id = surface->document->filter_id++;
     switch (filter) {
     case CAIRO_SVG_FILTER_OVER:
-	_CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("over");
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("over")
 	break;
     case CAIRO_SVG_FILTER_IN:
-	_CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("in");
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("in")
 	break;
     case CAIRO_SVG_FILTER_OUT:
-	_CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("out");
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("out")
 	break;
     case CAIRO_SVG_FILTER_ATOP:
-	_CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("atop");
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("atop")
 	break;
     case CAIRO_SVG_FILTER_XOR:
-	_CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("xor");
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("xor")
 	break;
     case CAIRO_SVG_FILTER_ADD:
 	// This can also be done with <feComposite operator="lighter"/>, but it is not in SVG 1.1
 	_cairo_svg_stream_printf (&surface->document->xml_node_filters,
 				  "<filter id=\"filter-%d\" "
 				  "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
-				  "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\" x=\"0\" y=\"0\"/>\n"
-				  "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\" x=\"0\" y=\"0\"/>\n"
+				  "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"",
+				  filter_id,
+				  source_compositing_group_id);
+	_cairo_svg_stream_append_paint_dependent (&surface->document->xml_node_filters,
+						  surface->source_id,
+						  CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE_AT_ORIGIN);
+	_cairo_svg_stream_printf (&surface->document->xml_node_filters,
+				  "/>\n"
+				  "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"",
+				  destination_compositing_group_id);
+	_cairo_svg_stream_append_paint_dependent (&surface->document->xml_node_filters,
+						  surface->source_id,
+						  CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE_AT_ORIGIN);
+	_cairo_svg_stream_printf (&surface->document->xml_node_filters,
+				  "/>\n"
 				  "<feComposite in=\"source\" in2=\"destination\" "
 				  "operator=\"arithmetic\" k1=\"0\" k2=\"1\" k3=\"1\" k4=\"0\" "
 				  "color-interpolation-filters=\"sRGB\"/>\n"
-				  "</filter>\n",
-				  filter_id,
-				  source_compositing_group_id,
-				  destination_compositing_group_id);
+				  "</filter>\n");
 	break;
     case CAIRO_SVG_FILTER_MULTIPLY:
-	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("multiply");
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("multiply")
 	break;
     case CAIRO_SVG_FILTER_SCREEN:
-	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("screen");
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("screen")
 	break;
     case CAIRO_SVG_FILTER_OVERLAY:
-	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("overlay");
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("overlay")
 	break;
     case CAIRO_SVG_FILTER_DARKEN:
-	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("darken");
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("darken")
 	break;
     case CAIRO_SVG_FILTER_LIGHTEN:
-	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("lighten");
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("lighten")
 	break;
     case CAIRO_SVG_FILTER_COLOR_DODGE:
-	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("color-dodge");
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("color-dodge")
 	break;
     case CAIRO_SVG_FILTER_COLOR_BURN:
-	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("color-burn");
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("color-burn")
 	break;
     case CAIRO_SVG_FILTER_HARD_LIGHT:
-	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("hard-light");
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("hard-light")
 	break;
     case CAIRO_SVG_FILTER_SOFT_LIGHT:
-	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("soft-light");
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("soft-light")
 	break;
     case CAIRO_SVG_FILTER_DIFFERENCE:
-	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("difference");
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("difference")
 	break;
     case CAIRO_SVG_FILTER_EXCLUSION:
-	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("exclusion");
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("exclusion")
 	break;
     case CAIRO_SVG_FILTER_HUE:
-	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("hue");
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("hue")
 	break;
     case CAIRO_SVG_FILTER_SATURATION:
-	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("saturation");
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("saturation")
 	break;
     case CAIRO_SVG_FILTER_COLOR:
-	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("color");
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("color")
 	break;
     case CAIRO_SVG_FILTER_LUMINOSITY:
-	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("luminosity");
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("luminosity")
 	break;
     default:
-	printf ("%d\n", filter);
 	ASSERT_NOT_REACHED;
     }
     return filter_id;
@@ -2190,7 +2260,7 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_surface_t *surface,
 					   document->owner->y_fallback_resolution);
 
     if (source->base.content == CAIRO_CONTENT_COLOR) {
-	_cairo_svg_surface_emit_paint (&svg_surface->xml_node, svg_surface, &_cairo_pattern_black.base);
+	_cairo_svg_surface_emit_paint (&svg_surface->xml_node, svg_surface, &_cairo_pattern_black.base, FALSE);
     }
     status = _cairo_recording_surface_replay (&source->base, paginated_surface);
     if (unlikely (status)) {
@@ -2975,7 +3045,8 @@ _cairo_svg_surface_get_extents (void		        *abstract_surface,
 static cairo_status_t
 _cairo_svg_surface_emit_paint (cairo_svg_stream_t *output,
 			       cairo_svg_surface_t *surface,
-			       const cairo_pattern_t *source)
+			       const cairo_pattern_t *source,
+			       cairo_bool_t at_origin)
 {
     cairo_status_t status;
 
@@ -2990,7 +3061,15 @@ _cairo_svg_surface_emit_paint (cairo_svg_stream_t *output,
     surface->transitive_paint_used = TRUE;
 
     _cairo_svg_stream_printf (output, "<rect");
-    _cairo_svg_stream_append_rectangle (output, surface->source_id);
+    if (at_origin) {
+	_cairo_svg_stream_append_paint_dependent (output,
+						  surface->source_id,
+						  CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE_AT_ORIGIN);
+    } else {
+	_cairo_svg_stream_append_paint_dependent (output,
+						  surface->source_id,
+						  CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE);
+    }
     status = _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, NULL);
     if (unlikely (status)) {
 	return status;
@@ -3022,7 +3101,7 @@ _cairo_svg_surface_do_operator (cairo_svg_stream_t *output,
 							 op == CAIRO_OPERATOR_DEST_OUT ||
 							 op == CAIRO_OPERATOR_DEST_ATOP ||
 							 op == CAIRO_OPERATOR_XOR)) {
-	_cairo_svg_surface_emit_paint (output, surface, &_cairo_pattern_black.base);
+	_cairo_svg_surface_emit_paint (output, surface, &_cairo_pattern_black.base, FALSE);
     }
 
     if (op == CAIRO_OPERATOR_CLEAR) {
@@ -3067,9 +3146,13 @@ _cairo_svg_surface_do_operator (cairo_svg_stream_t *output,
 
 	unsigned int lerp_compositing_group_id = document->compositing_group_id++;
 	_cairo_svg_stream_printf (&document->xml_node_defs,
-				  "<g id=\"compositing-group-%d\">\n",
+				  "<g id=\"compositing-group-%d\"",
 				  lerp_compositing_group_id);
-	_cairo_svg_surface_emit_paint (&document->xml_node_defs, surface, &_cairo_pattern_clear.base);
+	_cairo_svg_stream_append_paint_dependent (&document->xml_node_defs,
+						  surface->source_id,
+						  CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_INVERSE_TRANSLATION);
+	_cairo_svg_stream_printf (&document->xml_node_defs, ">\n");
+	_cairo_svg_surface_emit_paint (&document->xml_node_defs, surface, &_cairo_pattern_clear.base, FALSE);
 	status = _cairo_svg_surface_set_clip (surface, &document->xml_node_defs, clip);
 	if (unlikely (status)) {
 	    (void) _cairo_svg_stream_destroy (destination_stream);
@@ -3112,6 +3195,11 @@ _cairo_svg_surface_do_operator (cairo_svg_stream_t *output,
 				  "<g id=\"compositing-group-%d\" mask=\"url(#mask-%d)\">\n",
 				  lerped_source_compositing_group_id,
 				  positive_lerp_mask_id);
+	_cairo_svg_stream_printf (&document->xml_node_defs, "<g");
+	_cairo_svg_stream_append_paint_dependent (&document->xml_node_defs,
+						  surface->source_id,
+						  CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_INVERSE_TRANSLATION);
+	_cairo_svg_stream_printf (&document->xml_node_defs, ">\n");
 	_cairo_svg_stream_copy (source_stream, &document->xml_node_defs);
 	status = _cairo_svg_stream_destroy (source_stream);
 	if (unlikely (status)) {
@@ -3119,26 +3207,37 @@ _cairo_svg_surface_do_operator (cairo_svg_stream_t *output,
 	    return status;
 	}
 	_cairo_svg_stream_printf (&document->xml_node_defs, "</g>\n");
+	_cairo_svg_stream_printf (&document->xml_node_defs, "</g>\n");
 
 	unsigned int lerped_destination_compositing_group_id = document->compositing_group_id++;
 	_cairo_svg_stream_printf (&document->xml_node_defs,
 				  "<g id=\"compositing-group-%d\" mask=\"url(#mask-%d)\">\n",
 				  lerped_destination_compositing_group_id,
 				  negative_lerp_mask_id);
+	_cairo_svg_stream_printf (&document->xml_node_defs, "<g");
+	_cairo_svg_stream_append_paint_dependent (&document->xml_node_defs,
+						  surface->source_id,
+						  CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_INVERSE_TRANSLATION);
+	_cairo_svg_stream_printf (&document->xml_node_defs, ">\n");
 	_cairo_svg_stream_copy (destination_stream, &document->xml_node_defs);
 	status = _cairo_svg_stream_destroy (destination_stream);
 	if (unlikely (status)) {
 	    return status;
 	}
 	_cairo_svg_stream_printf (&document->xml_node_defs, "</g>\n");
+	_cairo_svg_stream_printf (&document->xml_node_defs, "</g>\n");
 
 	_cairo_svg_stream_printf (&surface->xml_node,
-				  "<g filter=\"url(#filter-%d)\">\n",
+				  "<g filter=\"url(#filter-%d)\"",
 				  _cairo_svg_surface_emit_parametric_filter (surface,
 									     CAIRO_SVG_FILTER_ADD,
 									     lerped_source_compositing_group_id,
 									     lerped_destination_compositing_group_id));
-	status = _cairo_svg_surface_emit_paint (&surface->xml_node, surface, &_cairo_pattern_black.base);
+	_cairo_svg_stream_append_paint_dependent (&surface->xml_node,
+						  surface->source_id,
+						  CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_TRANSLATION);
+	_cairo_svg_stream_printf (&surface->xml_node, ">\n");
+	status = _cairo_svg_surface_emit_paint (&surface->xml_node, surface, &_cairo_pattern_black.base, TRUE);
 	if (unlikely (status)) {
 	    return status;
 	}
@@ -3195,9 +3294,13 @@ _cairo_svg_surface_do_operator (cairo_svg_stream_t *output,
 
     unsigned int lerp_compositing_group_id = document->compositing_group_id++;
     _cairo_svg_stream_printf (&document->xml_node_defs,
-			      "<g id=\"compositing-group-%d\">\n",
+			      "<g id=\"compositing-group-%d\"",
 			      lerp_compositing_group_id);
-    _cairo_svg_surface_emit_paint (&document->xml_node_defs, surface, &_cairo_pattern_clear.base);
+    _cairo_svg_stream_append_paint_dependent (&document->xml_node_defs,
+					      surface->source_id,
+					      CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_INVERSE_TRANSLATION);
+    _cairo_svg_stream_printf (&document->xml_node_defs, ">\n");
+    _cairo_svg_surface_emit_paint (&document->xml_node_defs, surface, &_cairo_pattern_clear.base, FALSE);
     status = _cairo_svg_surface_set_clip (surface, &document->xml_node_defs, clip);
     if (unlikely (status)) {
 	(void) _cairo_svg_stream_destroy (destination_stream);
@@ -3205,7 +3308,7 @@ _cairo_svg_surface_do_operator (cairo_svg_stream_t *output,
 	(void) _cairo_svg_stream_destroy (mask_stream);
 	return status;
     }
-    status = _cairo_svg_surface_emit_paint (&document->xml_node_defs, surface, &_cairo_pattern_white.base);
+    status = _cairo_svg_surface_emit_paint (&document->xml_node_defs, surface, &_cairo_pattern_white.base, FALSE);
     if (unlikely (status)) {
 	(void) _cairo_svg_stream_destroy (destination_stream);
 	(void) _cairo_svg_stream_destroy (source_stream);
@@ -3239,6 +3342,11 @@ _cairo_svg_surface_do_operator (cairo_svg_stream_t *output,
     _cairo_svg_stream_printf (&document->xml_node_defs,
 			      "<mask id=\"mask-%d\">\n",
 			      mask_mask_id);
+    _cairo_svg_stream_printf (&document->xml_node_defs, "<g");
+    _cairo_svg_stream_append_paint_dependent (&document->xml_node_defs,
+					      surface->source_id,
+					      CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_INVERSE_TRANSLATION);
+    _cairo_svg_stream_printf (&document->xml_node_defs, ">\n");
     _cairo_svg_stream_copy (mask_stream, &document->xml_node_defs);
     status = _cairo_svg_stream_destroy (mask_stream);
     if (unlikely (status)) {
@@ -3246,6 +3354,7 @@ _cairo_svg_surface_do_operator (cairo_svg_stream_t *output,
 	(void) _cairo_svg_stream_destroy (destination_stream);
 	return status;
     }
+    _cairo_svg_stream_printf (&document->xml_node_defs, "</g>\n");
     _cairo_svg_stream_printf (&document->xml_node_defs, "</mask>\n");
 
     unsigned int masked_source_compositing_group_id = document->compositing_group_id++;
@@ -3253,6 +3362,11 @@ _cairo_svg_surface_do_operator (cairo_svg_stream_t *output,
 			      "<g id=\"compositing-group-%d\" mask=\"url(#mask-%d)\">\n",
 			      masked_source_compositing_group_id,
 			      mask_mask_id);
+    _cairo_svg_stream_printf (&document->xml_node_defs, "<g");
+    _cairo_svg_stream_append_paint_dependent (&document->xml_node_defs,
+					      surface->source_id,
+					      CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_INVERSE_TRANSLATION);
+    _cairo_svg_stream_printf (&document->xml_node_defs, ">\n");
     _cairo_svg_stream_copy (source_stream, &document->xml_node_defs);
     status = _cairo_svg_stream_destroy (source_stream);
     if (unlikely (status)) {
@@ -3260,11 +3374,16 @@ _cairo_svg_surface_do_operator (cairo_svg_stream_t *output,
 	return status;
     }
     _cairo_svg_stream_printf (&document->xml_node_defs, "</g>\n");
+    _cairo_svg_stream_printf (&document->xml_node_defs, "</g>\n");
 
     unsigned int destination_compositing_group_id = document->compositing_group_id++;
     _cairo_svg_stream_printf (&document->xml_node_defs,
-			      "<g id=\"compositing-group-%d\">\n",
+			      "<g id=\"compositing-group-%d\"",
 			      destination_compositing_group_id);
+    _cairo_svg_stream_append_paint_dependent (&document->xml_node_defs,
+					      surface->source_id,
+					      CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_INVERSE_TRANSLATION);
+    _cairo_svg_stream_printf (&document->xml_node_defs, ">\n");
     _cairo_svg_stream_copy (destination_stream, &document->xml_node_defs);
     status = _cairo_svg_stream_destroy (destination_stream);
     if (unlikely (status)) {
@@ -3437,7 +3556,7 @@ _cairo_svg_surface_do_operator (cairo_svg_stream_t *output,
 			      " filter=\"url(#filter-%d)\" mask=\"url(#mask-%d)\">\n",
 			      filter_id,
 			      positive_lerp_mask_id);
-    status = _cairo_svg_surface_emit_paint (&document->xml_node_defs, surface, &_cairo_pattern_black.base);
+    status = _cairo_svg_surface_emit_paint (&document->xml_node_defs, surface, &_cairo_pattern_black.base, TRUE);
     if (unlikely (status)) {
 	return status;
     }
@@ -3454,12 +3573,16 @@ _cairo_svg_surface_do_operator (cairo_svg_stream_t *output,
     _cairo_svg_stream_printf (&document->xml_node_defs, "</g>\n");
 
     _cairo_svg_stream_printf (&surface->xml_node,
-			      "<g filter=\"url(#filter-%d)\">\n",
+			      "<g filter=\"url(#filter-%d)\"",
 			      _cairo_svg_surface_emit_parametric_filter (surface,
 									 CAIRO_SVG_FILTER_ADD,
 									 lerped_operation_compositing_group_id,
 									 lerped_destination_compositing_group_id));
-    status = _cairo_svg_surface_emit_paint (&surface->xml_node, surface, &_cairo_pattern_black.base);
+    _cairo_svg_stream_append_paint_dependent (&surface->xml_node,
+					      surface->source_id,
+					      CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_TRANSLATION);
+    _cairo_svg_stream_printf (&surface->xml_node, ">\n");
+    status = _cairo_svg_surface_emit_paint (&surface->xml_node, surface, &_cairo_pattern_black.base, TRUE);
     if (unlikely (status)) {
 	return status;
     }
@@ -3486,7 +3609,8 @@ _cairo_svg_surface_do_operator (cairo_svg_stream_t *output,
         cairo_svg_stream_t source_stream = _cairo_svg_stream_create (); \
         status = _cairo_svg_surface_emit_paint (&source_stream, \
                                                 surface, \
-                                                SOURCE); \
+                                                SOURCE,                   \
+                                                FALSE); \
         if (unlikely (status)) { \
             (void) _cairo_svg_stream_destroy (&source_stream); \
             (void) _cairo_svg_stream_destroy (&mask_stream); \
@@ -3508,7 +3632,7 @@ _cairo_svg_surface_paint_impl (cairo_svg_stream_t *output,
 			       cairo_svg_surface_t *surface,
 			       const cairo_pattern_t *source)
 {
-    return _cairo_svg_surface_emit_paint (output, surface, source);
+    return _cairo_svg_surface_emit_paint (output, surface, source, FALSE);
 }
 
 static cairo_int_status_t
@@ -3575,7 +3699,7 @@ _cairo_svg_surface_mask_impl (cairo_svg_stream_t *output,
     _cairo_svg_stream_printf (&temporary_stream,
 				 "<g filter=\"url(#filter-%s)\">\n",
 				 _cairo_svg_surface_emit_static_filter (document, CAIRO_SVG_FILTER_REMOVE_COLOR));
-    status = _cairo_svg_surface_emit_paint (&temporary_stream, surface, mask);
+    status = _cairo_svg_surface_emit_paint (&temporary_stream, surface, mask, FALSE);
     if (unlikely (status)) {
 	(void) _cairo_svg_stream_destroy (&temporary_stream);
 	return status;
@@ -3594,7 +3718,7 @@ _cairo_svg_surface_mask_impl (cairo_svg_stream_t *output,
 				 "<g mask=\"url(#mask-%d)\">\n",
 				 mask_id);
 
-    status = _cairo_svg_surface_emit_paint (output, surface, source);
+    status = _cairo_svg_surface_emit_paint (output, surface, source, FALSE);
     if (unlikely (status)) {
 	return status;
     }
diff --git a/test/Makefile.sources b/test/Makefile.sources
index cdcf9e33e..0e68ccb7d 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -322,6 +322,7 @@ test_sources = \
 	show-text-current-point.c			\
 	shape-general-convex.c				\
 	shape-sierpinski.c				\
+	shifted-operator.c				\
 	simple.c					\
 	skew-extreme.c					\
 	smask.c						\
diff --git a/test/meson.build b/test/meson.build
index 5cd220ce8..b4562adb8 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -322,6 +322,7 @@ test_sources = [
   'show-text-current-point.c',
   'shape-general-convex.c',
   'shape-sierpinski.c',
+  'shifted-operator.c',
   'simple.c',
   'skew-extreme.c',
   'smask.c',
diff --git a/test/reference/shifted-operator.ref.png b/test/reference/shifted-operator.ref.png
new file mode 100644
index 000000000..3b27dbe04
Binary files /dev/null and b/test/reference/shifted-operator.ref.png differ
diff --git a/test/reference/shifted-operator.rgb24.ref.png b/test/reference/shifted-operator.rgb24.ref.png
new file mode 100644
index 000000000..6fc9ad30d
Binary files /dev/null and b/test/reference/shifted-operator.rgb24.ref.png differ
diff --git a/test/reference/shifted-operator.svg.rgb24.ref.png b/test/reference/shifted-operator.svg.rgb24.ref.png
new file mode 100644
index 000000000..6fc9ad30d
Binary files /dev/null and b/test/reference/shifted-operator.svg.rgb24.ref.png differ
diff --git a/test/shifted-operator.c b/test/shifted-operator.c
new file mode 100644
index 000000000..c8b7cc737
--- /dev/null
+++ b/test/shifted-operator.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright © 2021 Anton Danilkin
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "cairo-test.h"
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    cairo_surface_t *recording_surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL);
+    cairo_t *cr2 = cairo_create (recording_surface);
+    cairo_translate (cr2, -30, -30);
+    cairo_rectangle (cr2, 0, 0, 120, 90);
+    cairo_set_source_rgba (cr2, 0.7, 0, 0, 0.8);
+    cairo_fill (cr2);
+    cairo_set_operator (cr2, CAIRO_OPERATOR_XOR);
+    cairo_rectangle (cr2, 40, 30, 120, 90);
+    cairo_set_source_rgba (cr2, 0, 0, 0.9, 0.4);
+    cairo_fill (cr2);
+
+    cairo_pattern_t *pattern = cairo_pattern_create_for_surface (recording_surface);
+    cairo_matrix_t matrix;
+    cairo_matrix_init_translate (&matrix, -30, -30);
+    cairo_pattern_set_matrix (pattern, &matrix);
+    cairo_set_source (cr, pattern);
+    cairo_paint (cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (shifted_operator,
+	    "Test drawing a rectangle shifted into negative coordinates with an operator",
+	    "operator, transform, record", /* keywords */
+	    NULL, /* requirements */
+	    160, 120,
+	    NULL, draw)
commit c30a031a686e53d7df4f86aae52823a4282c046c
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Mon May 3 09:58:40 2021 +0200

    Fix painting of glyphs

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index fc95fcc13..436dccbe0 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -1410,10 +1410,11 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document,
 
     svg_surface->transitive_paint_used = TRUE;
 
+    _cairo_svg_stream_printf (&document->xml_node_glyphs, "<rect");
+    _cairo_svg_stream_append_rectangle (&document->xml_node_glyphs, source_id);
     _cairo_svg_stream_printf (&document->xml_node_glyphs,
-				 "<use xlink:href=\"#paint-%d\" mask=\"url(#mask-%d)\"",
-				 source_id,
-				 mask_id);
+			      " mask=\"url(#mask-%d)\"",
+			      mask_id);
     if (!use_recording_surface) {
 	_cairo_svg_surface_emit_transform (&document->xml_node_glyphs,
 					   "transform",
@@ -1469,7 +1470,7 @@ _cairo_svg_document_emit_glyph (cairo_svg_document_t	*document,
     cairo_int_status_t	     status;
 
     _cairo_svg_stream_printf (&document->xml_node_glyphs,
-			      "<g overflow=\"visible\" id=\"glyph-%d-%d\">\n",
+			      "<g id=\"glyph-%d-%d\">\n",
 			      font_id,
 			      subset_glyph_index);
 
commit 55b57b2c681929077de649f65d10d05f74c2c5b6
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Mon May 3 00:30:57 2021 +0200

    Fix operators in Chrome

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index e512bab82..fc95fcc13 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -158,7 +158,7 @@ _cairo_svg_paint_box_add_padding (cairo_box_double_t *box)
 
 enum cairo_svg_stream_element_type {
     CAIRO_SVG_STREAM_ELEMENT_TYPE_TEXT,
-    CAIRO_SVG_STREAM_ELEMENT_TYPE_BOX,
+    CAIRO_SVG_STREAM_ELEMENT_TYPE_RECTANGLE,
 };
 
 typedef struct _cairo_svg_stream_element {
@@ -218,7 +218,7 @@ _cairo_svg_stream_write (cairo_svg_stream_t *svg_stream,
     _cairo_output_stream_write (last_element->text.output_stream, data, length);
 }
 
-void
+void CAIRO_PRINTF_FORMAT (2, 0)
 _cairo_svg_stream_printf (cairo_svg_stream_t *svg_stream,
 			  const char *fmt,
 			  ...)
@@ -254,18 +254,16 @@ _cairo_svg_stream_printf (cairo_svg_stream_t *svg_stream,
 
 void
 _cairo_svg_stream_append_rectangle (cairo_svg_stream_t *svg_stream,
-			     unsigned int source_id)
+				    unsigned int source_id)
 {
     cairo_status_t status;
 
     cairo_svg_stream_element_t element;
-    element.type = CAIRO_SVG_STREAM_ELEMENT_TYPE_BOX;
+    element.type = CAIRO_SVG_STREAM_ELEMENT_TYPE_RECTANGLE;
     element.rectangle.source_id = source_id;
     status = _cairo_array_append (&svg_stream->elements, &element);
-    if (unlikely (status)) {
-	if (svg_stream->status == CAIRO_STATUS_SUCCESS) {
-	    svg_stream->status = status;
-	}
+    if (svg_stream->status == CAIRO_STATUS_SUCCESS) {
+	svg_stream->status = status;
     }
 }
 
@@ -319,7 +317,7 @@ _cairo_svg_stream_copy_to_output_stream (cairo_svg_stream_t *from,
 	if (element->type == CAIRO_SVG_STREAM_ELEMENT_TYPE_TEXT) {
 	    _cairo_memory_stream_copy (element->text.output_stream, to);
 	}
-	if (element->type == CAIRO_SVG_STREAM_ELEMENT_TYPE_BOX) {
+	if (element->type == CAIRO_SVG_STREAM_ELEMENT_TYPE_RECTANGLE) {
 	    cairo_svg_paint_t paint_key;
 	    paint_key.source_id = element->rectangle.source_id;
 	    _cairo_svg_paint_init_key (&paint_key);
@@ -1698,11 +1696,11 @@ _cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cair
 }
 
 #define _CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER(operation) \
-    _cairo_svg_stream_printf (&document->xml_node_filters, \
+    _cairo_svg_stream_printf (&surface->document->xml_node_filters, \
                               "<filter id=\"filter-%d\" " \
                               "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n" \
-                              "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"/>\n" \
-                              "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"/>\n" \
+                              "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\" x=\"0\" y=\"0\"/>\n" \
+                              "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\" x=\"0\" y=\"0\"/>\n" \
                               "<feComposite in=\"source\" in2=\"destination\" " \
                               "operator=\"" operation "\" " \
                               "color-interpolation-filters=\"sRGB\"/>\n" \
@@ -1712,11 +1710,11 @@ _cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cair
                               destination_compositing_group_id)
 
 #define _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER(mode) \
-    _cairo_svg_stream_printf (&document->xml_node_filters, \
+    _cairo_svg_stream_printf (&surface->document->xml_node_filters, \
                               "<filter id=\"filter-%d\" " \
                               "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n" \
-                              "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"/>\n" \
-                              "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"/>\n" \
+                              "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\" x=\"0\" y=\"0\"/>\n" \
+                              "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\" x=\"0\" y=\"0\"/>\n" \
                               "<feBlend in=\"source\" in2=\"destination\" " \
                               "mode=\"" mode "\" " \
                               "color-interpolation-filters=\"sRGB\"/>\n" \
@@ -1726,12 +1724,12 @@ _cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cair
                               destination_compositing_group_id)
 
 static unsigned int
-_cairo_svg_surface_emit_parametric_filter (cairo_svg_document_t *document,
+_cairo_svg_surface_emit_parametric_filter (cairo_svg_surface_t *surface,
 					   enum cairo_svg_filter filter,
 					   unsigned int source_compositing_group_id,
 					   unsigned int destination_compositing_group_id)
 {
-    unsigned int filter_id = document->filter_id++;
+    unsigned int filter_id = surface->document->filter_id++;
     switch (filter) {
     case CAIRO_SVG_FILTER_OVER:
 	_CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("over");
@@ -1750,11 +1748,11 @@ _cairo_svg_surface_emit_parametric_filter (cairo_svg_document_t *document,
 	break;
     case CAIRO_SVG_FILTER_ADD:
 	// This can also be done with <feComposite operator="lighter"/>, but it is not in SVG 1.1
-	_cairo_svg_stream_printf (&document->xml_node_filters,
+	_cairo_svg_stream_printf (&surface->document->xml_node_filters,
 				  "<filter id=\"filter-%d\" "
 				  "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
-				  "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"/>\n"
-				  "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"/>\n"
+				  "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\" x=\"0\" y=\"0\"/>\n"
+				  "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\" x=\"0\" y=\"0\"/>\n"
 				  "<feComposite in=\"source\" in2=\"destination\" "
 				  "operator=\"arithmetic\" k1=\"0\" k2=\"1\" k3=\"1\" k4=\"0\" "
 				  "color-interpolation-filters=\"sRGB\"/>\n"
@@ -3135,7 +3133,7 @@ _cairo_svg_surface_do_operator (cairo_svg_stream_t *output,
 
 	_cairo_svg_stream_printf (&surface->xml_node,
 				  "<g filter=\"url(#filter-%d)\">\n",
-				  _cairo_svg_surface_emit_parametric_filter (document,
+				  _cairo_svg_surface_emit_parametric_filter (surface,
 									     CAIRO_SVG_FILTER_ADD,
 									     lerped_source_compositing_group_id,
 									     lerped_destination_compositing_group_id));
@@ -3275,7 +3273,7 @@ _cairo_svg_surface_do_operator (cairo_svg_stream_t *output,
 
     unsigned int lerped_operation_compositing_group_id = document->compositing_group_id++;
     _cairo_svg_stream_printf (&document->xml_node_defs,
-			      "<g id=\"compositing-group-%d\" ",
+			      "<g id=\"compositing-group-%d\"",
 			      lerped_operation_compositing_group_id);
     unsigned int filter_id;
     switch (op) {
@@ -3284,19 +3282,19 @@ _cairo_svg_surface_do_operator (cairo_svg_stream_t *output,
     case CAIRO_OPERATOR_OVER:
 	ASSERT_NOT_REACHED;
     case CAIRO_OPERATOR_IN:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_IN,
 							       masked_source_compositing_group_id,
 							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_OUT:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_OUT,
 							       masked_source_compositing_group_id,
 							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_ATOP:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_ATOP,
 							       masked_source_compositing_group_id,
 							       destination_compositing_group_id);
@@ -3304,37 +3302,37 @@ _cairo_svg_surface_do_operator (cairo_svg_stream_t *output,
     case CAIRO_OPERATOR_DEST:
 	ASSERT_NOT_REACHED;
     case CAIRO_OPERATOR_DEST_OVER:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_OVER,
 							       destination_compositing_group_id,
 							       masked_source_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_DEST_IN:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_IN,
 							       destination_compositing_group_id,
 							       masked_source_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_DEST_OUT:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_OUT,
 							       destination_compositing_group_id,
 							       masked_source_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_DEST_ATOP:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_ATOP,
 							       destination_compositing_group_id,
 							       masked_source_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_XOR:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_XOR,
 							       masked_source_compositing_group_id,
 							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_ADD:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_ADD,
 							       masked_source_compositing_group_id,
 							       destination_compositing_group_id);
@@ -3342,91 +3340,91 @@ _cairo_svg_surface_do_operator (cairo_svg_stream_t *output,
     case CAIRO_OPERATOR_SATURATE:
 	ASSERT_NOT_REACHED;
     case CAIRO_OPERATOR_MULTIPLY:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_MULTIPLY,
 							       masked_source_compositing_group_id,
 							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_SCREEN:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_SCREEN,
 							       masked_source_compositing_group_id,
 							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_OVERLAY:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_OVERLAY,
 							       masked_source_compositing_group_id,
 							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_DARKEN:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_DARKEN,
 							       masked_source_compositing_group_id,
 							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_LIGHTEN:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_LIGHTEN,
 							       masked_source_compositing_group_id,
 							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_COLOR_DODGE:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_COLOR_DODGE,
 							       masked_source_compositing_group_id,
 							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_COLOR_BURN:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_COLOR_BURN,
 							       masked_source_compositing_group_id,
 							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_HARD_LIGHT:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_HARD_LIGHT,
 							       masked_source_compositing_group_id,
 							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_SOFT_LIGHT:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_SOFT_LIGHT,
 							       masked_source_compositing_group_id,
 							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_DIFFERENCE:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_DIFFERENCE,
 							       masked_source_compositing_group_id,
 							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_EXCLUSION:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_EXCLUSION,
 							       masked_source_compositing_group_id,
 							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_HSL_HUE:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_HUE,
 							       masked_source_compositing_group_id,
 							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_HSL_SATURATION:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_SATURATION,
 							       masked_source_compositing_group_id,
 							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_HSL_COLOR:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_COLOR,
 							       masked_source_compositing_group_id,
 							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_HSL_LUMINOSITY:
-	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+	filter_id = _cairo_svg_surface_emit_parametric_filter (surface,
 							       CAIRO_SVG_FILTER_LUMINOSITY,
 							       masked_source_compositing_group_id,
 							       destination_compositing_group_id);
@@ -3435,7 +3433,7 @@ _cairo_svg_surface_do_operator (cairo_svg_stream_t *output,
 	ASSERT_NOT_REACHED;
     }
     _cairo_svg_stream_printf (&document->xml_node_defs,
-			      "filter=\"url(#filter-%d)\" mask=\"url(#mask-%d)\">\n",
+			      " filter=\"url(#filter-%d)\" mask=\"url(#mask-%d)\">\n",
 			      filter_id,
 			      positive_lerp_mask_id);
     status = _cairo_svg_surface_emit_paint (&document->xml_node_defs, surface, &_cairo_pattern_black.base);
@@ -3456,7 +3454,7 @@ _cairo_svg_surface_do_operator (cairo_svg_stream_t *output,
 
     _cairo_svg_stream_printf (&surface->xml_node,
 			      "<g filter=\"url(#filter-%d)\">\n",
-			      _cairo_svg_surface_emit_parametric_filter (document,
+			      _cairo_svg_surface_emit_parametric_filter (surface,
 									 CAIRO_SVG_FILTER_ADD,
 									 lerped_operation_compositing_group_id,
 									 lerped_destination_compositing_group_id));
commit 10552fa78f63266f448bd0785ef3ef27cb91b9a3
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Mon May 3 00:30:14 2021 +0200

    Use g instead of symbol for glyphs

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 1042a51a0..e512bab82 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -1471,7 +1471,7 @@ _cairo_svg_document_emit_glyph (cairo_svg_document_t	*document,
     cairo_int_status_t	     status;
 
     _cairo_svg_stream_printf (&document->xml_node_glyphs,
-			      "<symbol overflow=\"visible\" id=\"glyph-%d-%d\">\n",
+			      "<g overflow=\"visible\" id=\"glyph-%d-%d\">\n",
 			      font_id,
 			      subset_glyph_index);
 
@@ -1485,7 +1485,7 @@ _cairo_svg_document_emit_glyph (cairo_svg_document_t	*document,
     if (unlikely (status))
 	return status;
 
-    _cairo_svg_stream_printf (&document->xml_node_glyphs, "</symbol>\n");
+    _cairo_svg_stream_printf (&document->xml_node_glyphs, "</g>\n");
 
     return CAIRO_INT_STATUS_SUCCESS;
 }
commit 62628c8886c074f8cc3e3d96e55120e3abf72f15
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sun May 2 21:38:02 2021 +0200

    Migrate from cairo_output_stream_t to cairo_svg_stream_t

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 92db887c4..1042a51a0 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -58,6 +58,303 @@
 #include "cairo-surface-snapshot-inline.h"
 #include "cairo-svg-surface-private.h"
 
+typedef struct _cairo_svg_source_surface {
+    cairo_hash_entry_t base;
+    unsigned int id;
+    unsigned char *unique_id;
+    unsigned long unique_id_length;
+    cairo_bool_t transitive_paint_used;
+} cairo_svg_source_surface_t;
+
+/*
+ * _cairo_svg_paint_element and _cairo_svg_paint are used to implement paints in transformed recording patterns.
+ */
+
+typedef struct _cairo_svg_paint_element {
+    unsigned int source_id;
+    cairo_matrix_t matrix;
+} cairo_svg_paint_element_t;
+
+typedef struct _cairo_svg_paint {
+    cairo_hash_entry_t base;
+    unsigned int source_id;
+    cairo_array_t paint_elements;
+    cairo_box_double_t box;
+} cairo_svg_paint_t;
+
+static void
+_cairo_svg_source_surface_init_key (cairo_svg_source_surface_t *source_surface)
+{
+    if (source_surface->unique_id && source_surface->unique_id_length > 0) {
+	source_surface->base.hash = _cairo_hash_bytes (_CAIRO_HASH_INIT_VALUE,
+						       source_surface->unique_id,
+						       source_surface->unique_id_length);
+    } else {
+	source_surface->base.hash = source_surface->id;
+    }
+}
+
+static cairo_bool_t
+_cairo_svg_source_surface_equal (const void *key_a, const void *key_b)
+{
+    const cairo_svg_source_surface_t *a = key_a;
+    const cairo_svg_source_surface_t *b = key_b;
+
+    if (a->unique_id && b->unique_id && a->unique_id_length == b->unique_id_length) {
+	return memcmp (a->unique_id, b->unique_id, a->unique_id_length) == 0;
+    }
+
+    return a->id == b->id;
+}
+
+static void
+_cairo_svg_source_surface_pluck (void *entry, void *closure)
+{
+    cairo_svg_source_surface_t *source_surface = entry;
+    cairo_hash_table_t *patterns = closure;
+
+    _cairo_hash_table_remove (patterns, &source_surface->base);
+    free (source_surface->unique_id);
+    free (source_surface);
+}
+
+static void
+_cairo_svg_paint_init_key (cairo_svg_paint_t *paint)
+{
+    paint->base.hash = paint->source_id;
+}
+
+static cairo_bool_t
+_cairo_svg_paint_equal (const void *key_a, const void *key_b)
+{
+    const cairo_svg_paint_t *a = key_a;
+    const cairo_svg_paint_t *b = key_b;
+
+    return a->source_id == b->source_id;
+}
+
+static void
+_cairo_svg_paint_pluck (void *entry, void *closure)
+{
+    cairo_svg_paint_t *paint = entry;
+    cairo_hash_table_t *patterns = closure;
+
+    _cairo_hash_table_remove (patterns, &paint->base);
+    _cairo_array_fini (&paint->paint_elements);
+    free (paint);
+}
+
+static void
+_cairo_svg_paint_box_add_padding (cairo_box_double_t *box)
+{
+    double width = box->p2.x - box->p1.x;
+    double height = box->p2.y - box->p1.y;
+
+    box->p1.x -= width / 10.0;
+    box->p1.y -= height / 10.0;
+    box->p2.x += width / 10.0;
+    box->p2.y += height / 10.0;
+}
+
+enum cairo_svg_stream_element_type {
+    CAIRO_SVG_STREAM_ELEMENT_TYPE_TEXT,
+    CAIRO_SVG_STREAM_ELEMENT_TYPE_BOX,
+};
+
+typedef struct _cairo_svg_stream_element {
+    enum cairo_svg_stream_element_type type;
+    union {
+        struct {
+	    cairo_output_stream_t *output_stream;
+	} text;
+        struct {
+	    unsigned int source_id;
+        } rectangle;
+    };
+} cairo_svg_stream_element_t;
+
+typedef struct _cairo_svg_stream {
+    cairo_status_t status;
+    cairo_array_t elements;
+} cairo_svg_stream_t;
+
+cairo_svg_stream_t
+_cairo_svg_stream_create ()
+{
+    cairo_svg_stream_t svg_stream;
+    svg_stream.status = CAIRO_STATUS_SUCCESS;
+    _cairo_array_init (&svg_stream.elements, sizeof (cairo_svg_stream_element_t));
+    return svg_stream;
+}
+
+void
+_cairo_svg_stream_write (cairo_svg_stream_t *svg_stream,
+			 const void *data,
+			 size_t length)
+{
+    cairo_status_t status;
+
+    cairo_svg_stream_element_t *last_element = NULL;
+    if (svg_stream->elements.num_elements > 0) {
+	last_element = _cairo_array_index (&svg_stream->elements,
+					   svg_stream->elements.num_elements - 1);
+    }
+
+    if (last_element == NULL || last_element->type != CAIRO_SVG_STREAM_ELEMENT_TYPE_TEXT) {
+	cairo_svg_stream_element_t element;
+	element.type = CAIRO_SVG_STREAM_ELEMENT_TYPE_TEXT;
+	element.text.output_stream = _cairo_memory_stream_create();
+	status = _cairo_array_append (&svg_stream->elements, &element);
+	if (unlikely (status)) {
+	    if (svg_stream->status == CAIRO_STATUS_SUCCESS) {
+		svg_stream->status = status;
+	    }
+	    return;
+	}
+	last_element = _cairo_array_index (&svg_stream->elements,
+					   svg_stream->elements.num_elements - 1);
+    }
+
+    _cairo_output_stream_write (last_element->text.output_stream, data, length);
+}
+
+void
+_cairo_svg_stream_printf (cairo_svg_stream_t *svg_stream,
+			  const char *fmt,
+			  ...)
+{
+    cairo_status_t status;
+
+    cairo_svg_stream_element_t *last_element = NULL;
+    if (svg_stream->elements.num_elements > 0) {
+	last_element = _cairo_array_index (&svg_stream->elements,
+					   svg_stream->elements.num_elements - 1);
+    }
+
+    if (last_element == NULL || last_element->type != CAIRO_SVG_STREAM_ELEMENT_TYPE_TEXT) {
+        cairo_svg_stream_element_t element;
+	element.type = CAIRO_SVG_STREAM_ELEMENT_TYPE_TEXT;
+	element.text.output_stream = _cairo_memory_stream_create();
+	status = _cairo_array_append (&svg_stream->elements, &element);
+	if (unlikely (status)) {
+	    if (svg_stream->status == CAIRO_STATUS_SUCCESS) {
+		svg_stream->status = status;
+	    }
+	    return;
+	}
+	last_element = _cairo_array_index (&svg_stream->elements,
+					   svg_stream->elements.num_elements - 1);
+    }
+
+    va_list ap;
+    va_start (ap, fmt);
+    _cairo_output_stream_vprintf (last_element->text.output_stream, fmt, ap);
+    va_end (ap);
+}
+
+void
+_cairo_svg_stream_append_rectangle (cairo_svg_stream_t *svg_stream,
+			     unsigned int source_id)
+{
+    cairo_status_t status;
+
+    cairo_svg_stream_element_t element;
+    element.type = CAIRO_SVG_STREAM_ELEMENT_TYPE_BOX;
+    element.rectangle.source_id = source_id;
+    status = _cairo_array_append (&svg_stream->elements, &element);
+    if (unlikely (status)) {
+	if (svg_stream->status == CAIRO_STATUS_SUCCESS) {
+	    svg_stream->status = status;
+	}
+    }
+}
+
+void
+_cairo_svg_stream_copy (cairo_svg_stream_t *from,
+			cairo_svg_stream_t *to)
+{
+    cairo_status_t status;
+
+    if (unlikely (from->status)) {
+	if (to->status == CAIRO_STATUS_SUCCESS) {
+	    to->status = from->status;
+	}
+	return;
+    }
+
+    for (unsigned int i = 0; i < from->elements.num_elements; i++) {
+	cairo_svg_stream_element_t *element = _cairo_array_index (&from->elements, i);
+	cairo_svg_stream_element_t element_copy = *element;
+	if (element->type == CAIRO_SVG_STREAM_ELEMENT_TYPE_TEXT) {
+	    element_copy.text.output_stream = _cairo_memory_stream_create ();
+	    _cairo_memory_stream_copy (element->text.output_stream, element_copy.text.output_stream);
+	    if (to->status == CAIRO_STATUS_SUCCESS) {
+		to->status = element->text.output_stream->status;
+	    }
+	}
+	status = _cairo_array_append (&to->elements, &element_copy);
+	if (unlikely (status)) {
+	    if (to->status == CAIRO_STATUS_SUCCESS) {
+		to->status = status;
+	    }
+	    return;
+	}
+    }
+}
+
+void
+_cairo_svg_stream_copy_to_output_stream (cairo_svg_stream_t *from,
+					 cairo_output_stream_t *to,
+					 cairo_hash_table_t *paints)
+{
+    if (unlikely (from->status)) {
+	if (to->status == CAIRO_STATUS_SUCCESS) {
+	    to->status = from->status;
+	}
+	return;
+    }
+
+    for (unsigned int i = 0; i < from->elements.num_elements; i++) {
+	cairo_svg_stream_element_t *element = _cairo_array_index (&from->elements, i);
+	if (element->type == CAIRO_SVG_STREAM_ELEMENT_TYPE_TEXT) {
+	    _cairo_memory_stream_copy (element->text.output_stream, to);
+	}
+	if (element->type == CAIRO_SVG_STREAM_ELEMENT_TYPE_BOX) {
+	    cairo_svg_paint_t paint_key;
+	    paint_key.source_id = element->rectangle.source_id;
+	    _cairo_svg_paint_init_key (&paint_key);
+
+	    cairo_svg_paint_t *found_paint_entry = _cairo_hash_table_lookup (paints,
+									     &paint_key.base);
+	    assert (found_paint_entry);
+
+	    _cairo_output_stream_printf (to,
+					 " x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\"",
+					 found_paint_entry->box.p1.x,
+					 found_paint_entry->box.p1.y,
+					 found_paint_entry->box.p2.x - found_paint_entry->box.p1.x,
+					 found_paint_entry->box.p2.y - found_paint_entry->box.p1.y);
+	}
+    }
+}
+
+cairo_status_t
+_cairo_svg_stream_destroy (cairo_svg_stream_t *svg_stream)
+{
+    cairo_status_t status = svg_stream->status;
+    for (unsigned int i = 0; i < svg_stream->elements.num_elements; i++) {
+	cairo_svg_stream_element_t *element = _cairo_array_index (&svg_stream->elements, i);
+	if (element->type == CAIRO_SVG_STREAM_ELEMENT_TYPE_TEXT) {
+	    cairo_status_t element_status = _cairo_output_stream_destroy (element->text.output_stream);
+	    if (status == CAIRO_STATUS_SUCCESS) {
+		status = element_status;
+	    }
+	}
+    }
+    _cairo_array_fini (&svg_stream->elements);
+    return status;
+}
+
 /**
  * SECTION:cairo-svg
  * @Title: SVG Surfaces
@@ -97,9 +394,9 @@ static const char *_cairo_svg_supported_mime_types[] =
 };
 
 static void
-_cairo_svg_surface_emit_path (cairo_output_stream_t	*output,
-			      const cairo_path_fixed_t	*path,
-			      const cairo_matrix_t	*ctm_inverse);
+_cairo_svg_surface_emit_path (cairo_svg_stream_t *output,
+			      const cairo_path_fixed_t *path,
+			      const cairo_matrix_t *ctm_inverse);
 
 static const char * _cairo_svg_version_strings[CAIRO_SVG_VERSION_LAST] =
 {
@@ -149,33 +446,8 @@ enum cairo_svg_filter {
     CAIRO_SVG_FILTER_LUMINOSITY,
 };
 
-typedef struct _cairo_svg_source_surface {
-    cairo_hash_entry_t base;
-    unsigned int id;
-    unsigned char *unique_id;
-    unsigned long unique_id_length;
-    cairo_bool_t transitive_paint_used;
-} cairo_svg_source_surface_t;
-
-/*
- * _cairo_svg_paint_element and _cairo_svg_paint are used to implement paints in transformed recording patterns.
- */
-
-typedef struct _cairo_svg_paint_element {
-    unsigned int source_id;
-    cairo_matrix_t matrix;
-} cairo_svg_paint_element_t;
-
-typedef struct _cairo_svg_paint {
-    cairo_hash_entry_t base;
-    unsigned int source_id;
-    cairo_bool_t paint_used;
-    cairo_array_t paint_elements;
-    cairo_box_double_t box;
-} cairo_svg_paint_t;
-
 typedef struct _cairo_svg_page {
-    cairo_output_stream_t *xml_node;
+    cairo_svg_stream_t xml_node;
 } cairo_svg_page_t;
 
 typedef struct _cairo_svg_document {
@@ -188,9 +460,9 @@ typedef struct _cairo_svg_document {
     double height;
     cairo_svg_unit_t unit;
 
-    cairo_output_stream_t *xml_node_defs;
-    cairo_output_stream_t *xml_node_glyphs;
-    cairo_output_stream_t *xml_node_filters;
+    cairo_svg_stream_t xml_node_defs;
+    cairo_svg_stream_t xml_node_glyphs;
+    cairo_svg_stream_t xml_node_filters;
 
     unsigned int linear_pattern_id;
     unsigned int radial_pattern_id;
@@ -224,27 +496,26 @@ typedef struct _cairo_svg_surface {
 
     cairo_svg_document_t *document;
 
-    cairo_output_stream_t *xml_node;
+    cairo_svg_stream_t xml_node;
     cairo_array_t page_set;
 
     cairo_hash_table_t *source_surfaces;
 
     cairo_surface_clipper_t clipper;
-    cairo_output_stream_t *current_clipper_output_stream;
+    cairo_svg_stream_t *current_clipper_stream;
     unsigned int clip_level;
 
-    cairo_bool_t paint_used;
     cairo_bool_t transitive_paint_used;
 
     cairo_paginated_mode_t paginated_mode;
 } cairo_svg_surface_t;
 
 static cairo_status_t
-_cairo_svg_document_create (cairo_output_stream_t	 *stream,
-			    double			  width,
-			    double			  height,
-			    cairo_svg_version_t		  version,
-			    cairo_svg_document_t	**document_out);
+_cairo_svg_document_create (cairo_output_stream_t *stream,
+			    double width,
+			    double height,
+			    cairo_svg_version_t version,
+			    cairo_svg_document_t **document_out);
 
 static cairo_status_t
 _cairo_svg_document_destroy (cairo_svg_document_t *document);
@@ -256,27 +527,27 @@ static cairo_svg_document_t *
 _cairo_svg_document_reference (cairo_svg_document_t *document);
 
 static cairo_surface_t *
-_cairo_svg_surface_create_for_document (cairo_svg_document_t	*document,
-					cairo_content_t		 content,
-					double			 width,
-					double			 height,
-					cairo_bool_t             bounded);
+_cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
+					cairo_content_t content,
+					double width,
+					double height,
+					cairo_bool_t bounded);
 
 static cairo_surface_t *
-_cairo_svg_surface_create_for_stream_internal (cairo_output_stream_t	*stream,
-					       double			 width,
-					       double			 height,
-					       cairo_svg_version_t	 version);
+_cairo_svg_surface_create_for_stream_internal (cairo_output_stream_t *stream,
+					       double width,
+					       double height,
+					       cairo_svg_version_t version);
 
 static cairo_status_t
-_cairo_svg_surface_emit_composite_pattern (cairo_output_stream_t *output,
+_cairo_svg_surface_emit_composite_pattern (cairo_svg_stream_t *output,
 					   cairo_svg_surface_t *surface,
 					   cairo_surface_pattern_t *pattern,
 					   unsigned int pattern_id,
 					   const cairo_matrix_t *parent_matrix);
 
 static cairo_status_t
-_cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
+_cairo_svg_surface_emit_paint (cairo_svg_stream_t *output,
 			       cairo_svg_surface_t *surface,
 			       const cairo_pattern_t *source);
 
@@ -556,80 +827,6 @@ cairo_svg_surface_get_document_unit (cairo_surface_t	*abstract_surface)
     return surface->document->unit;
 }
 
-static void
-_cairo_svg_source_surface_init_key (cairo_svg_source_surface_t *source_surface)
-{
-    if (source_surface->unique_id && source_surface->unique_id_length > 0) {
-	source_surface->base.hash = _cairo_hash_bytes (_CAIRO_HASH_INIT_VALUE,
-						       source_surface->unique_id,
-						       source_surface->unique_id_length);
-    } else {
-	source_surface->base.hash = source_surface->id;
-    }
-}
-
-static cairo_bool_t
-_cairo_svg_source_surface_equal (const void *key_a, const void *key_b)
-{
-    const cairo_svg_source_surface_t *a = key_a;
-    const cairo_svg_source_surface_t *b = key_b;
-
-    if (a->unique_id && b->unique_id && a->unique_id_length == b->unique_id_length) {
-	return memcmp (a->unique_id, b->unique_id, a->unique_id_length) == 0;
-    }
-
-    return a->id == b->id;
-}
-
-static void
-_cairo_svg_source_surface_pluck (void *entry, void *closure)
-{
-    cairo_svg_source_surface_t *source_surface = entry;
-    cairo_hash_table_t *patterns = closure;
-
-    _cairo_hash_table_remove (patterns, &source_surface->base);
-    free (source_surface->unique_id);
-    free (source_surface);
-}
-
-static void
-_cairo_svg_paint_init_key (cairo_svg_paint_t *paint)
-{
-    paint->base.hash = paint->source_id;
-}
-
-static cairo_bool_t
-_cairo_svg_paint_equal (const void *key_a, const void *key_b)
-{
-    const cairo_svg_paint_t *a = key_a;
-    const cairo_svg_paint_t *b = key_b;
-
-    return a->source_id == b->source_id;
-}
-
-static void
-_cairo_svg_paint_pluck (void *entry, void *closure)
-{
-    cairo_svg_paint_t *paint = entry;
-    cairo_hash_table_t *patterns = closure;
-
-    _cairo_hash_table_remove (patterns, &paint->base);
-    _cairo_array_fini (&paint->paint_elements);
-    free (paint);
-}
-
-static void
-_cairo_svg_paint_box_add_padding (cairo_box_double_t *box)
-{
-    double width = box->p2.x - box->p1.x;
-    double height = box->p2.y - box->p1.y;
-
-    box->p1.x -= width / 10.0;
-    box->p1.y -= height / 10.0;
-    box->p2.x += width / 10.0;
-    box->p2.y += height / 10.0;
-}
-
 static void
 _cairo_svg_paint_compute (cairo_svg_document_t *document, cairo_svg_paint_t *paint) {
     for (unsigned int i = 0; i < paint->paint_elements.num_elements; i++) {
@@ -673,21 +870,6 @@ _cairo_svg_paint_compute_func (void *entry, void *closure)
     _cairo_svg_paint_compute (document, paint);
 }
 
-static void
-_cairo_svg_paint_emit_func (void *entry, void *closure)
-{
-    cairo_svg_paint_t *paint = entry;
-    cairo_output_stream_t *output = closure;
-
-    if (paint->paint_used) {
-	_cairo_output_stream_printf (output,
-				     "<rect id=\"paint-%d\" x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\"/>\n",
-				     paint->source_id,
-				     paint->box.p1.x, paint->box.p1.y,
-				     paint->box.p2.x - paint->box.p1.x, paint->box.p2.y - paint->box.p1.y);
-    }
-}
-
 static cairo_status_t
 _cairo_svg_surface_add_source_surface (cairo_svg_surface_t *surface,
 				       cairo_surface_t *source_surface,
@@ -779,7 +961,7 @@ _cairo_svg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper
 
     if (path == NULL) {
 	for (unsigned int i = 0; i < surface->clip_level; i++) {
-	    _cairo_output_stream_printf (surface->current_clipper_output_stream, "</g>\n");
+	    _cairo_svg_stream_printf (surface->current_clipper_stream, "</g>\n");
 	}
 	surface->clip_level = 0;
 	return CAIRO_STATUS_SUCCESS;
@@ -790,21 +972,21 @@ _cairo_svg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper
 	return CAIRO_STATUS_SUCCESS;
     }
 
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<clipPath id=\"clip-%d\">\n",
-				 document->clip_id);
+    _cairo_svg_stream_printf (&document->xml_node_defs,
+			      "<clipPath id=\"clip-%d\">\n",
+			      document->clip_id);
 
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<path clip-rule=\"%s\"",
-				 fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero");
-    _cairo_svg_surface_emit_path (document->xml_node_defs, path, NULL);
-    _cairo_output_stream_printf (document->xml_node_defs, "/>\n");
+    _cairo_svg_stream_printf (&document->xml_node_defs,
+			      "<path clip-rule=\"%s\"",
+			      fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero");
+    _cairo_svg_surface_emit_path (&document->xml_node_defs, path, NULL);
+    _cairo_svg_stream_printf (&document->xml_node_defs, "/>\n");
 
-    _cairo_output_stream_printf (document->xml_node_defs, "</clipPath>\n");
+    _cairo_svg_stream_printf (&document->xml_node_defs, "</clipPath>\n");
 
-    _cairo_output_stream_printf (surface->current_clipper_output_stream,
-				 "<g clip-path=\"url(#clip-%d)\">\n",
-				 document->clip_id);
+    _cairo_svg_stream_printf (surface->current_clipper_stream,
+			      "<g clip-path=\"url(#clip-%d)\">\n",
+			      document->clip_id);
 
     document->clip_id++;
     surface->clip_level++;
@@ -816,9 +998,9 @@ static void
 _cairo_svg_surface_reset_clip (cairo_svg_surface_t *surface)
 {
     _cairo_surface_clipper_reset (&surface->clipper);
-    if (surface->current_clipper_output_stream != NULL) {
+    if (surface->current_clipper_stream != NULL) {
 	for (unsigned int i = 0; i < surface->clip_level; i++) {
-	    _cairo_output_stream_printf (surface->current_clipper_output_stream, "</g>\n");
+	    _cairo_svg_stream_printf (surface->current_clipper_stream, "</g>\n");
 	}
     }
     surface->clip_level = 0;
@@ -826,12 +1008,12 @@ _cairo_svg_surface_reset_clip (cairo_svg_surface_t *surface)
 
 static cairo_status_t
 _cairo_svg_surface_set_clip (cairo_svg_surface_t *surface,
-			     cairo_output_stream_t *clipper_output_stream,
+			     cairo_svg_stream_t *clipper_stream,
 			     const cairo_clip_t *clip)
 {
-    if (surface->current_clipper_output_stream != clipper_output_stream) {
+    if (surface->current_clipper_stream != clipper_stream) {
 	_cairo_svg_surface_reset_clip (surface);
-	surface->current_clipper_output_stream = clipper_output_stream;
+	surface->current_clipper_stream = clipper_stream;
     }
     return _cairo_surface_clipper_set_clip (&surface->clipper, clip);
 }
@@ -867,7 +1049,7 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
 
     surface->document = _cairo_svg_document_reference (document);
 
-    surface->xml_node = _cairo_memory_stream_create ();
+    surface->xml_node = _cairo_svg_stream_create ();
     _cairo_array_init (&surface->page_set, sizeof (cairo_svg_page_t));
 
     surface->source_surfaces = _cairo_hash_table_create (_cairo_svg_source_surface_equal);
@@ -877,9 +1059,8 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
     }
 
     _cairo_surface_clipper_init (&surface->clipper, _cairo_svg_surface_clipper_intersect_clip_path);
-    surface->current_clipper_output_stream = NULL;
+    surface->current_clipper_stream = NULL;
     surface->clip_level = 0;
-    surface->paint_used = FALSE;
     surface->transitive_paint_used = FALSE;
 
     surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
@@ -899,7 +1080,7 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
 
     /* ignore status as we are on the error path */
     CLEANUP:
-    (void) _cairo_output_stream_destroy (surface->xml_node);
+    (void) _cairo_svg_stream_destroy (&surface->xml_node);
     (void) _cairo_svg_document_destroy (document);
 
     free (surface);
@@ -951,7 +1132,7 @@ _cairo_svg_surface_store_page (cairo_svg_surface_t *surface)
     if (_cairo_array_append (&surface->page_set, &page)) {
 	return NULL;
     }
-    surface->xml_node = _cairo_memory_stream_create ();
+    surface->xml_node = _cairo_svg_stream_create ();
     return _cairo_array_index (&surface->page_set,
 			       surface->page_set.num_elements - 1);
 }
@@ -966,7 +1147,7 @@ _cairo_svg_surface_copy_page (void *abstract_surface)
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     }
 
-    _cairo_memory_stream_copy (page->xml_node, surface->xml_node);
+    _cairo_svg_stream_copy (&page->xml_node, &surface->xml_node);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -985,7 +1166,7 @@ _cairo_svg_surface_show_page (void *abstract_surface)
 }
 
 static void
-_cairo_svg_surface_emit_transform (cairo_output_stream_t *output,
+_cairo_svg_surface_emit_transform (cairo_svg_stream_t *output,
 				   char const *attribute_name,
 				   const cairo_matrix_t *object_matrix,
 				   const cairo_matrix_t *parent_matrix)
@@ -997,17 +1178,17 @@ _cairo_svg_surface_emit_transform (cairo_output_stream_t *output,
     }
 
     if (!_cairo_matrix_is_identity (&matrix)) {
-	_cairo_output_stream_printf (output,
-				     " %s=\"matrix(%f, %f, %f, %f, %f, %f)\"",
-				     attribute_name,
-				     matrix.xx, matrix.yx,
-				     matrix.xy, matrix.yy,
-				     matrix.x0, matrix.y0);
+	_cairo_svg_stream_printf (output,
+				  " %s=\"matrix(%f, %f, %f, %f, %f, %f)\"",
+				  attribute_name,
+				  matrix.xx, matrix.yx,
+				  matrix.xy, matrix.yy,
+				  matrix.x0, matrix.y0);
     }
 }
 
 typedef struct {
-    cairo_output_stream_t *output;
+    cairo_svg_stream_t *output;
     const cairo_matrix_t *ctm_inverse;
 } svg_path_info_t;
 
@@ -1022,7 +1203,7 @@ _cairo_svg_path_move_to (void *closure,
     if (info->ctm_inverse)
 	cairo_matrix_transform_point (info->ctm_inverse, &x, &y);
 
-    _cairo_output_stream_printf (info->output, "M %f %f ", x, y);
+    _cairo_svg_stream_printf (info->output, "M %f %f ", x, y);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1038,7 +1219,7 @@ _cairo_svg_path_line_to (void *closure,
     if (info->ctm_inverse)
 	cairo_matrix_transform_point (info->ctm_inverse, &x, &y);
 
-    _cairo_output_stream_printf (info->output, "L %f %f ", x, y);
+    _cairo_svg_stream_printf (info->output, "L %f %f ", x, y);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1063,9 +1244,9 @@ _cairo_svg_path_curve_to (void          *closure,
 	cairo_matrix_transform_point (info->ctm_inverse, &dx, &dy);
     }
 
-    _cairo_output_stream_printf (info->output,
-				 "C %f %f %f %f %f %f ",
-				 bx, by, cx, cy, dx, dy);
+    _cairo_svg_stream_printf (info->output,
+			      "C %f %f %f %f %f %f ",
+			      bx, by, cx, cy, dx, dy);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1075,20 +1256,20 @@ _cairo_svg_path_close_path (void *closure)
 {
     svg_path_info_t *info = closure;
 
-    _cairo_output_stream_printf (info->output, "Z ");
+    _cairo_svg_stream_printf (info->output, "Z ");
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static void
-_cairo_svg_surface_emit_path (cairo_output_stream_t *output,
+_cairo_svg_surface_emit_path (cairo_svg_stream_t *output,
 			      const cairo_path_fixed_t *path,
 			      const cairo_matrix_t *ctm_inverse)
 {
     cairo_status_t status;
     svg_path_info_t info;
 
-    _cairo_output_stream_printf (output, " d=\"");
+    _cairo_svg_stream_printf (output, " d=\"");
 
     info.output = output;
     info.ctm_inverse = ctm_inverse;
@@ -1100,7 +1281,7 @@ _cairo_svg_surface_emit_path (cairo_output_stream_t *output,
 					  &info);
     assert (status == CAIRO_STATUS_SUCCESS);
 
-    _cairo_output_stream_printf (output, "\"");
+    _cairo_svg_stream_printf (output, "\"");
 }
 
 static cairo_int_status_t
@@ -1120,15 +1301,15 @@ _cairo_svg_document_emit_outline_glyph_data (cairo_svg_document_t *document,
     }
 
     if (_cairo_path_fixed_size (scaled_glyph->path) != 0) {
-	_cairo_output_stream_printf (document->xml_node_glyphs,
-				     "<path");
+	_cairo_svg_stream_printf (&document->xml_node_glyphs,
+				  "<path");
 
-	_cairo_svg_surface_emit_path (document->xml_node_glyphs,
+	_cairo_svg_surface_emit_path (&document->xml_node_glyphs,
 				      scaled_glyph->path,
 				      NULL);
 
-	_cairo_output_stream_printf (document->xml_node_glyphs,
-				     "/>\n");
+	_cairo_svg_stream_printf (&document->xml_node_glyphs,
+				  "/>\n");
     }
 
     return status;
@@ -1203,46 +1384,45 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document,
 					   document->owner->x_fallback_resolution,
 					   document->owner->y_fallback_resolution);
 
-    cairo_output_stream_t *temporary_stream = _cairo_memory_stream_create ();
+    cairo_svg_stream_t temporary_stream = _cairo_svg_stream_create ();
 
     unsigned int mask_id = document->mask_id++;
 
-    _cairo_output_stream_printf (temporary_stream,
-				 "<mask id=\"mask-%d\">\n",
-				 mask_id);
+    _cairo_svg_stream_printf (&temporary_stream,
+			      "<mask id=\"mask-%d\">\n",
+			      mask_id);
 
     cairo_pattern_t *pattern = cairo_pattern_create_for_surface (use_recording_surface ? scaled_glyph->recording_surface
 										       : &glyph_image_surface->base);
-    _cairo_svg_surface_emit_composite_pattern (temporary_stream,
+    _cairo_svg_surface_emit_composite_pattern (&temporary_stream,
 					       svg_surface,
 					       (cairo_surface_pattern_t *) pattern,
 					       invalid_pattern_id,
 					       NULL);
     cairo_pattern_destroy (pattern);
 
-    _cairo_output_stream_printf (temporary_stream, "</mask>\n");
+    _cairo_svg_stream_printf (&temporary_stream, "</mask>\n");
 
-    _cairo_memory_stream_copy (temporary_stream, document->xml_node_defs);
+    _cairo_svg_stream_copy (&temporary_stream, &document->xml_node_defs);
 
-    status = _cairo_output_stream_destroy (temporary_stream);
+    status = _cairo_svg_stream_destroy (&temporary_stream);
     if (unlikely (status)) {
 	goto cleanup;
     }
 
-    svg_surface->paint_used = TRUE;
     svg_surface->transitive_paint_used = TRUE;
 
-    _cairo_output_stream_printf (document->xml_node_glyphs,
+    _cairo_svg_stream_printf (&document->xml_node_glyphs,
 				 "<use xlink:href=\"#paint-%d\" mask=\"url(#mask-%d)\"",
 				 source_id,
 				 mask_id);
     if (!use_recording_surface) {
-	_cairo_svg_surface_emit_transform (document->xml_node_glyphs,
+	_cairo_svg_surface_emit_transform (&document->xml_node_glyphs,
 					   "transform",
 					   &glyph_matrix,
 					   NULL);
     }
-    _cairo_output_stream_printf (document->xml_node_glyphs, "/>\n");
+    _cairo_svg_stream_printf (&document->xml_node_glyphs, "/>\n");
 
     cairo_svg_paint_t *paint_entry = malloc (sizeof (cairo_svg_paint_t));
     if (paint_entry == NULL) {
@@ -1250,7 +1430,6 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document,
 	goto cleanup;
     }
     paint_entry->source_id = source_id;
-    paint_entry->paint_used = svg_surface->paint_used;
     paint_entry->box.p1.x = 0;
     paint_entry->box.p1.y = 0;
     paint_entry->box.p2.x = glyph_image_surface->width;
@@ -1291,10 +1470,10 @@ _cairo_svg_document_emit_glyph (cairo_svg_document_t	*document,
 {
     cairo_int_status_t	     status;
 
-    _cairo_output_stream_printf (document->xml_node_glyphs,
-				 "<symbol overflow=\"visible\" id=\"glyph-%d-%d\">\n",
-				 font_id,
-				 subset_glyph_index);
+    _cairo_svg_stream_printf (&document->xml_node_glyphs,
+			      "<symbol overflow=\"visible\" id=\"glyph-%d-%d\">\n",
+			      font_id,
+			      subset_glyph_index);
 
     status = _cairo_svg_document_emit_outline_glyph_data (document,
 							  scaled_font,
@@ -1306,7 +1485,7 @@ _cairo_svg_document_emit_glyph (cairo_svg_document_t	*document,
     if (unlikely (status))
 	return status;
 
-    _cairo_output_stream_printf (document->xml_node_glyphs, "</symbol>\n");
+    _cairo_svg_stream_printf (&document->xml_node_glyphs, "</symbol>\n");
 
     return CAIRO_INT_STATUS_SUCCESS;
 }
@@ -1426,28 +1605,26 @@ _cairo_svg_surface_are_operation_and_pattern_supported (cairo_svg_surface_t *sur
 static cairo_status_t
 _cairo_svg_surface_finish (void *abstract_surface)
 {
-    cairo_status_t status, status2;
+    cairo_status_t status, final_status;
     cairo_svg_surface_t *surface = abstract_surface;
-    cairo_svg_document_t *document = surface->document;
-    cairo_svg_page_t *page;
-    unsigned int i;
 
-    if (_cairo_paginated_surface_get_target (document->owner) == &surface->base)
-	status = _cairo_svg_document_finish (document);
-    else
-	status = CAIRO_STATUS_SUCCESS;
+    if (_cairo_paginated_surface_get_target (surface->document->owner) == &surface->base) {
+	final_status = _cairo_svg_document_finish (surface->document);
+    } else {
+	final_status = CAIRO_STATUS_SUCCESS;
+    }
 
-    if (surface->xml_node != NULL) {
-	status2 = _cairo_output_stream_destroy (surface->xml_node);
-	if (status == CAIRO_STATUS_SUCCESS)
-	    status = status2;
+    status = _cairo_svg_stream_destroy (&surface->xml_node);
+    if (final_status == CAIRO_STATUS_SUCCESS) {
+	final_status = status;
     }
 
-    for (i = 0; i < surface->page_set.num_elements; i++) {
-	page = _cairo_array_index (&surface->page_set, i);
-	status2 = _cairo_output_stream_destroy (page->xml_node);
-	if (status == CAIRO_STATUS_SUCCESS)
-	    status = status2;
+    for (unsigned int i = 0; i < surface->page_set.num_elements; i++) {
+	cairo_svg_page_t *page = _cairo_array_index (&surface->page_set, i);
+	status = _cairo_svg_stream_destroy (&page->xml_node);
+	if (final_status == CAIRO_STATUS_SUCCESS) {
+	    final_status = status;
+	}
     }
     _cairo_array_fini (&surface->page_set);
 
@@ -1456,11 +1633,12 @@ _cairo_svg_surface_finish (void *abstract_surface)
     _cairo_hash_table_foreach (surface->source_surfaces, _cairo_svg_source_surface_pluck, surface->source_surfaces);
     _cairo_hash_table_destroy (surface->source_surfaces);
 
-    status2 = _cairo_svg_document_destroy (document);
-    if (status == CAIRO_STATUS_SUCCESS)
-	status = status2;
+    status = _cairo_svg_document_destroy (surface->document);
+    if (final_status == CAIRO_STATUS_SUCCESS) {
+	final_status = status;
+    }
 
-    return status;
+    return final_status;
 }
 
 static const char *
@@ -1471,36 +1649,36 @@ _cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cair
 	switch (filter) {
 	case CAIRO_SVG_FILTER_REMOVE_COLOR:
 	    // (r, g, b, a) -> (1, 1, 1, a)
-	    _cairo_output_stream_printf (document->xml_node_filters,
-					 "<filter id=\"filter-remove-color\" "
-					 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
-					 "<feColorMatrix values=\"0 0 0 0 1 "
-					 /*                   */ "0 0 0 0 1 "
-					 /*                   */ "0 0 0 0 1 "
-					 /*                   */ "0 0 0 1 0\"/>\n"
-					 "</filter>\n");
+	    _cairo_svg_stream_printf (&document->xml_node_filters,
+				      "<filter id=\"filter-remove-color\" "
+				      "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
+				      "<feColorMatrix values=\"0 0 0 0 1 "
+				      /*                   */ "0 0 0 0 1 "
+				      /*                   */ "0 0 0 0 1 "
+				      /*                   */ "0 0 0 1 0\"/>\n"
+				      "</filter>\n");
 	    break;
 	case CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA:
 	    // (r, g, b, a) -> (1, 1, 1, 1 - a)
-	    _cairo_output_stream_printf (document->xml_node_filters,
-					 "<filter id=\"filter-remove-color-and-invert-alpha\" "
-					 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
-					 "<feColorMatrix values=\"0 0 0 0 1 "
-					 /*                   */ "0 0 0 0 1 "
-					 /*                   */ "0 0 0 0 1 "
-					 /*                   */ "0 0 0 -1 1\"/>\n"
-					 "</filter>\n");
+	    _cairo_svg_stream_printf (&document->xml_node_filters,
+				      "<filter id=\"filter-remove-color-and-invert-alpha\" "
+				      "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
+				      "<feColorMatrix values=\"0 0 0 0 1 "
+				      /*                   */ "0 0 0 0 1 "
+				      /*                   */ "0 0 0 0 1 "
+				      /*                   */ "0 0 0 -1 1\"/>\n"
+				      "</filter>\n");
 	    break;
 	case CAIRO_SVG_FILTER_COLOR_TO_ALPHA:
 	    // (r, g, b, a) -> (1, 1, 1, 0.2126 * r + 0.7152 * g + 0.0722 * b)
-	    _cairo_output_stream_printf (document->xml_node_filters,
-					 "<filter id=\"filter-color-to-alpha\" "
-					 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
-					 "<feColorMatrix values=\"0 0 0 0 1 "
-					 /*                   */ "0 0 0 0 1 "
-					 /*                   */ "0 0 0 0 1 "
-					 /*                   */ "0.2126 0.7152 0.0722 0 0\"/>\n"
-					 "</filter>\n");
+	    _cairo_svg_stream_printf (&document->xml_node_filters,
+				      "<filter id=\"filter-color-to-alpha\" "
+				      "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
+				      "<feColorMatrix values=\"0 0 0 0 1 "
+				      /*                   */ "0 0 0 0 1 "
+				      /*                   */ "0 0 0 0 1 "
+				      /*                   */ "0.2126 0.7152 0.0722 0 0\"/>\n"
+				      "</filter>\n");
 	    break;
 	default:
 	    ASSERT_NOT_REACHED;
@@ -1520,32 +1698,32 @@ _cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cair
 }
 
 #define _CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER(operation) \
-    _cairo_output_stream_printf (document->xml_node_filters, \
-                                 "<filter id=\"filter-%d\" " \
-                                 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n" \
-                                 "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"/>\n" \
-                                 "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"/>\n" \
-                                 "<feComposite in=\"source\" in2=\"destination\" " \
-                                 "operator=\"" operation "\" " \
-                                 "color-interpolation-filters=\"sRGB\"/>\n" \
-                                 "</filter>\n", \
-                                 filter_id, \
-                                 source_compositing_group_id, \
-                                 destination_compositing_group_id)
+    _cairo_svg_stream_printf (&document->xml_node_filters, \
+                              "<filter id=\"filter-%d\" " \
+                              "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n" \
+                              "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"/>\n" \
+                              "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"/>\n" \
+                              "<feComposite in=\"source\" in2=\"destination\" " \
+                              "operator=\"" operation "\" " \
+                              "color-interpolation-filters=\"sRGB\"/>\n" \
+                              "</filter>\n", \
+                              filter_id, \
+                              source_compositing_group_id, \
+                              destination_compositing_group_id)
 
 #define _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER(mode) \
-    _cairo_output_stream_printf (document->xml_node_filters, \
-                                 "<filter id=\"filter-%d\" " \
-                                 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n" \
-                                 "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"/>\n" \
-                                 "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"/>\n" \
-                                 "<feBlend in=\"source\" in2=\"destination\" " \
-                                 "mode=\"" mode "\" " \
-                                 "color-interpolation-filters=\"sRGB\"/>\n" \
-                                 "</filter>\n", \
-                                 filter_id, \
-                                 source_compositing_group_id, \
-                                 destination_compositing_group_id)
+    _cairo_svg_stream_printf (&document->xml_node_filters, \
+                              "<filter id=\"filter-%d\" " \
+                              "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n" \
+                              "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"/>\n" \
+                              "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"/>\n" \
+                              "<feBlend in=\"source\" in2=\"destination\" " \
+                              "mode=\"" mode "\" " \
+                              "color-interpolation-filters=\"sRGB\"/>\n" \
+                              "</filter>\n", \
+                              filter_id, \
+                              source_compositing_group_id, \
+                              destination_compositing_group_id)
 
 static unsigned int
 _cairo_svg_surface_emit_parametric_filter (cairo_svg_document_t *document,
@@ -1572,18 +1750,18 @@ _cairo_svg_surface_emit_parametric_filter (cairo_svg_document_t *document,
 	break;
     case CAIRO_SVG_FILTER_ADD:
 	// This can also be done with <feComposite operator="lighter"/>, but it is not in SVG 1.1
-	_cairo_output_stream_printf (document->xml_node_filters,
-				     "<filter id=\"filter-%d\" "
-				     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
-				     "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"/>\n"
-				     "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"/>\n"
-				     "<feComposite in=\"source\" in2=\"destination\" "
-				     "operator=\"arithmetic\" k1=\"0\" k2=\"1\" k3=\"1\" k4=\"0\" "
-				     "color-interpolation-filters=\"sRGB\"/>\n"
-				     "</filter>\n",
-				     filter_id,
-				     source_compositing_group_id,
-				     destination_compositing_group_id);
+	_cairo_svg_stream_printf (&document->xml_node_filters,
+				  "<filter id=\"filter-%d\" "
+				  "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
+				  "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"/>\n"
+				  "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"/>\n"
+				  "<feComposite in=\"source\" in2=\"destination\" "
+				  "operator=\"arithmetic\" k1=\"0\" k2=\"1\" k3=\"1\" k4=\"0\" "
+				  "color-interpolation-filters=\"sRGB\"/>\n"
+				  "</filter>\n",
+				  filter_id,
+				  source_compositing_group_id,
+				  destination_compositing_group_id);
 	break;
     case CAIRO_SVG_FILTER_MULTIPLY:
 	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("multiply");
@@ -1638,7 +1816,7 @@ _cairo_svg_surface_emit_parametric_filter (cairo_svg_document_t *document,
 }
 
 typedef struct {
-    cairo_output_stream_t *output;
+    cairo_svg_stream_t *output;
     unsigned int in_mem;
     unsigned int trailing;
     unsigned char src[3];
@@ -1689,7 +1867,7 @@ base64_write_func (void *closure,
 	    default:
 		break;
 	}
-	_cairo_output_stream_write (info->output, dst, 4);
+	_cairo_svg_stream_write (info->output, dst, 4);
     } while (length >= 3);
 
     for (i = 0; i < length; i++) {
@@ -1697,12 +1875,12 @@ base64_write_func (void *closure,
     }
     info->in_mem = length;
 
-    return _cairo_output_stream_get_status (info->output);
+    return info->output->status;
 }
 
 static cairo_int_status_t
 _cairo_surface_base64_encode_jpeg (cairo_surface_t       *surface,
-				   cairo_output_stream_t *output)
+				   cairo_svg_stream_t *output)
 {
     const unsigned char *mime_data;
     unsigned long mime_data_length;
@@ -1722,7 +1900,7 @@ _cairo_surface_base64_encode_jpeg (cairo_surface_t       *surface,
     if (image_info.num_components == 4)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    _cairo_output_stream_printf (output, "data:image/jpeg;base64,");
+    _cairo_svg_stream_printf (output, "data:image/jpeg;base64,");
 
     info.output = output;
     info.in_mem = 0;
@@ -1744,7 +1922,7 @@ _cairo_surface_base64_encode_jpeg (cairo_surface_t       *surface,
 
 static cairo_int_status_t
 _cairo_surface_base64_encode_png (cairo_surface_t       *surface,
-				  cairo_output_stream_t *output)
+				  cairo_svg_stream_t *output)
 {
     const unsigned char *mime_data;
     unsigned long mime_data_length;
@@ -1758,7 +1936,7 @@ _cairo_surface_base64_encode_png (cairo_surface_t       *surface,
     if (mime_data == NULL)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    _cairo_output_stream_printf (output, "data:image/png;base64,");
+    _cairo_svg_stream_printf (output, "data:image/png;base64,");
 
     info.output = output;
     info.in_mem = 0;
@@ -1780,7 +1958,7 @@ _cairo_surface_base64_encode_png (cairo_surface_t       *surface,
 
 static cairo_int_status_t
 _cairo_surface_base64_encode (cairo_surface_t       *surface,
-			      cairo_output_stream_t *output)
+			      cairo_svg_stream_t *output)
 {
     cairo_int_status_t status;
     base64_write_closure_t info;
@@ -1797,7 +1975,7 @@ _cairo_surface_base64_encode (cairo_surface_t       *surface,
     info.in_mem = 0;
     info.trailing = 0;
 
-    _cairo_output_stream_printf (info.output, "data:image/png;base64,");
+    _cairo_svg_stream_printf (info.output, "data:image/png;base64,");
 
     status = cairo_surface_write_to_png_stream (surface, base64_write_func,
 						(void *) &info);
@@ -1823,7 +2001,7 @@ _cairo_surface_base64_encode (cairo_surface_t       *surface,
  * attribute's value context: & and ".
  **/
 static void
-_cairo_svg_surface_emit_attr_value (cairo_output_stream_t *stream,
+_cairo_svg_surface_emit_attr_value (cairo_svg_stream_t *stream,
 				    const unsigned char *value,
 				    unsigned int length)
 {
@@ -1838,20 +2016,20 @@ _cairo_svg_surface_emit_attr_value (cairo_output_stream_t *stream,
 	if (*p == '&' || *p == '"') {
 	    /* flush what's left before special char */
 	    if (p != q) {
-		_cairo_output_stream_write (stream, q, p - q);
+		_cairo_svg_stream_write (stream, q, p - q);
 		q = p + 1;
 	    }
 
 	    if (*p == '&')
-		_cairo_output_stream_printf (stream, "&");
+		_cairo_svg_stream_printf (stream, "&");
 	    else // p == '"'
-		_cairo_output_stream_printf (stream, """);
+		_cairo_svg_stream_printf (stream, """);
 	}
     }
 
     /* flush the trailing chars if any */
     if (p != q)
-	_cairo_output_stream_write (stream, q, p - q);
+	_cairo_svg_stream_write (stream, q, p - q);
 }
 
 static cairo_status_t
@@ -1868,31 +2046,31 @@ _cairo_svg_surface_emit_surface (cairo_svg_document_t *document,
     is_bounded = _cairo_surface_get_extents (surface, &extents);
     assert (is_bounded);
 
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<image id=\"source-%d\" x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" xlink:href=\"",
-				 source_id,
-				 extents.x, extents.y,
-				 extents.width, extents.height);
+    _cairo_svg_stream_printf (&document->xml_node_defs,
+			      "<image id=\"source-%d\" x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" xlink:href=\"",
+			      source_id,
+			      extents.x, extents.y,
+			      extents.width, extents.height);
 
     cairo_surface_get_mime_data (surface, CAIRO_MIME_TYPE_URI,
 				 &uri, &uri_len);
     if (uri != NULL) {
-	_cairo_svg_surface_emit_attr_value (document->xml_node_defs,
+	_cairo_svg_surface_emit_attr_value (&document->xml_node_defs,
 					    uri, uri_len);
     } else {
 	status = _cairo_surface_base64_encode (surface,
-					       document->xml_node_defs);
+					       &document->xml_node_defs);
 	if (unlikely (status))
 	    return status;
     }
 
-    _cairo_output_stream_printf (document->xml_node_defs, "\"/>\n");
+    _cairo_svg_stream_printf (&document->xml_node_defs, "\"/>\n");
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
-_cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output,
+_cairo_svg_surface_emit_composite_surface_pattern (cairo_svg_stream_t *output,
 						   cairo_svg_surface_t *surface,
 						   cairo_surface_pattern_t *pattern,
 						   unsigned int pattern_id,
@@ -1932,27 +2110,27 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output
 	is_bounded = _cairo_surface_get_extents (pattern->surface, &extents);
 	assert (is_bounded);
 
-	_cairo_output_stream_printf (output,
-				     "<pattern id=\"pattern-%d\" "
-				     "patternUnits=\"userSpaceOnUse\" "
-				     "x=\"%d\" y=\"%d\" "
-				     "width=\"%d\" height=\"%d\" "
-				     "viewBox=\"%d %d %d %d\"",
-				     pattern_id,
-				     extents.x, extents.y,
-				     extents.width, extents.height,
-				     extents.x, extents.y,
-				     extents.width, extents.height);
+	_cairo_svg_stream_printf (output,
+				  "<pattern id=\"pattern-%d\" "
+				  "patternUnits=\"userSpaceOnUse\" "
+				  "x=\"%d\" y=\"%d\" "
+				  "width=\"%d\" height=\"%d\" "
+				  "viewBox=\"%d %d %d %d\"",
+				  pattern_id,
+				  extents.x, extents.y,
+				  extents.width, extents.height,
+				  extents.x, extents.y,
+				  extents.width, extents.height);
 	_cairo_svg_surface_emit_transform (output,
 					   "patternTransform",
 					   &p2u,
 					   parent_matrix);
-	_cairo_output_stream_printf (output, ">\n");
+	_cairo_svg_stream_printf (output, ">\n");
     }
 
-    _cairo_output_stream_printf (output,
-				 "<use xlink:href=\"#source-%d\"",
-				 source_id);
+    _cairo_svg_stream_printf (output,
+			      "<use xlink:href=\"#source-%d\"",
+			      source_id);
     if (pattern->surface->content == CAIRO_CONTENT_ALPHA) {
 	cairo_bool_t can_skip_filter = FALSE;
 	if (pattern->surface->backend &&
@@ -1962,10 +2140,10 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output
 	    can_skip_filter = TRUE;
 	}
 	if (!can_skip_filter) {
-	    _cairo_output_stream_printf (output,
-					 " filter=\"url(#filter-%s)\"",
-					 _cairo_svg_surface_emit_static_filter (surface->document,
-										CAIRO_SVG_FILTER_COLOR_TO_ALPHA));
+	    _cairo_svg_stream_printf (output,
+				      " filter=\"url(#filter-%s)\"",
+				      _cairo_svg_surface_emit_static_filter (surface->document,
+									     CAIRO_SVG_FILTER_COLOR_TO_ALPHA));
 	}
     }
     if (pattern_id == invalid_pattern_id) {
@@ -1974,10 +2152,10 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output
 					   &p2u,
 					   parent_matrix);
     }
-    _cairo_output_stream_printf (output, "/>\n");
+    _cairo_svg_stream_printf (output, "/>\n");
 
     if (pattern_id != invalid_pattern_id) {
-	_cairo_output_stream_printf (output, "</pattern>\n");
+	_cairo_svg_stream_printf (output, "</pattern>\n");
     }
 
     return CAIRO_STATUS_SUCCESS;
@@ -1987,7 +2165,6 @@ static cairo_status_t
 _cairo_svg_surface_emit_recording_surface (cairo_svg_surface_t *surface,
 					   cairo_recording_surface_t *source,
 					   unsigned int source_id,
-					   cairo_bool_t *paint_used,
 					   cairo_bool_t *transitive_paint_used)
 {
     cairo_status_t status;
@@ -2014,7 +2191,7 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_surface_t *surface,
 					   document->owner->y_fallback_resolution);
 
     if (source->base.content == CAIRO_CONTENT_COLOR) {
-	_cairo_svg_surface_emit_paint (svg_surface->xml_node, svg_surface, &_cairo_pattern_black.base);
+	_cairo_svg_surface_emit_paint (&svg_surface->xml_node, svg_surface, &_cairo_pattern_black.base);
     }
     status = _cairo_recording_surface_replay (&source->base, paginated_surface);
     if (unlikely (status)) {
@@ -2033,36 +2210,36 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_surface_t *surface,
     if (bounded) {
 	clip_id = document->clip_id++;
 
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<clipPath id=\"clip-%d\">\n"
-				     "<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"/>\n"
-				     "</clipPath>\n",
-				     clip_id,
-				     extents.x,
-				     extents.y,
-				     extents.width,
-				     extents.height);
+	_cairo_svg_stream_printf (&document->xml_node_defs,
+				  "<clipPath id=\"clip-%d\">\n"
+				  "<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"/>\n"
+				  "</clipPath>\n",
+				  clip_id,
+				  extents.x,
+				  extents.y,
+				  extents.width,
+				  extents.height);
     }
 
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<g id=\"source-%d\"",
-				 source_id);
+    _cairo_svg_stream_printf (&document->xml_node_defs,
+			      "<g id=\"source-%d\"",
+			      source_id);
 
     if (bounded) {
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     " clip-path=\"url(#clip-%d)\"",
-				     clip_id);
+	_cairo_svg_stream_printf (&document->xml_node_defs,
+				  " clip-path=\"url(#clip-%d)\"",
+				  clip_id);
     }
 
     if (source->base.content == CAIRO_CONTENT_ALPHA) {
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     " filter=\"url(#filter-%s)\"",
-				     _cairo_svg_surface_emit_static_filter (document, CAIRO_SVG_FILTER_REMOVE_COLOR));
+	_cairo_svg_stream_printf (&document->xml_node_defs,
+				  " filter=\"url(#filter-%s)\"",
+				  _cairo_svg_surface_emit_static_filter (document, CAIRO_SVG_FILTER_REMOVE_COLOR));
     }
 
-    _cairo_output_stream_printf (document->xml_node_defs, ">\n");
+    _cairo_svg_stream_printf (&document->xml_node_defs, ">\n");
 
-    if (_cairo_memory_stream_length (svg_surface->xml_node) > 0) {
+    if (svg_surface->xml_node.elements.num_elements > 0) {
 	cairo_svg_page_t *page = _cairo_svg_surface_store_page (svg_surface);
 	if (unlikely (page == NULL)) {
 	    cairo_surface_destroy (paginated_surface);
@@ -2072,12 +2249,11 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_surface_t *surface,
 
     if (svg_surface->page_set.num_elements > 0) {
 	cairo_svg_page_t *page = _cairo_array_index (&svg_surface->page_set, svg_surface->page_set.num_elements - 1);
-	_cairo_memory_stream_copy (page->xml_node, document->xml_node_defs);
+	_cairo_svg_stream_copy (&page->xml_node, &document->xml_node_defs);
     }
 
-    _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
+    _cairo_svg_stream_printf (&document->xml_node_defs, "</g>\n");
 
-    *paint_used = svg_surface->paint_used;
     *transitive_paint_used = svg_surface->transitive_paint_used;
 
     status = cairo_surface_status (paginated_surface);
@@ -2113,7 +2289,7 @@ _cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (const cairo_pattern_t *p
 }
 
 static cairo_status_t
-_cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t *output,
+_cairo_svg_surface_emit_composite_recording_pattern (cairo_svg_stream_t *output,
 						     cairo_svg_surface_t *surface,
 						     cairo_surface_pattern_t *pattern,
 						     unsigned int pattern_id,
@@ -2140,12 +2316,9 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t *outp
 
     cairo_recording_surface_t *recording_surface = _cairo_svg_surface_to_recording_surface (pattern);
     if (is_new) {
-        cairo_bool_t paint_used;
-
 	status = _cairo_svg_surface_emit_recording_surface (surface,
 							    recording_surface,
 							    source_id,
-							    &paint_used,
 							    &source_surface->transitive_paint_used);
 	if (unlikely (status)) {
 	    return status;
@@ -2157,7 +2330,6 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t *outp
 		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	    }
 	    paint_entry->source_id = source_id;
-	    paint_entry->paint_used = paint_used;
 	    _cairo_array_init (&paint_entry->paint_elements, sizeof (cairo_svg_paint_element_t));
 	    _cairo_svg_paint_init_key (paint_entry);
 	    status = _cairo_hash_table_insert (document->paints, &paint_entry->base);
@@ -2196,43 +2368,43 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t *outp
 
     if (pattern_id != invalid_pattern_id) {
 	assert (!recording_surface->unbounded);
-	_cairo_output_stream_printf (output,
-				     "<pattern id=\"pattern-%d\" "
-				     "patternUnits=\"userSpaceOnUse\" "
-				     "x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" "
-				     "viewBox=\"%f %f %f %f\"",
-				     pattern_id,
-				     recording_surface->extents_pixels.x,
-				     recording_surface->extents_pixels.y,
-				     recording_surface->extents_pixels.width,
-				     recording_surface->extents_pixels.height,
-				     recording_surface->extents_pixels.x,
-				     recording_surface->extents_pixels.y,
-				     recording_surface->extents_pixels.width,
-				     recording_surface->extents_pixels.height);
+	_cairo_svg_stream_printf (output,
+				  "<pattern id=\"pattern-%d\" "
+				  "patternUnits=\"userSpaceOnUse\" "
+				  "x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" "
+				  "viewBox=\"%f %f %f %f\"",
+				  pattern_id,
+				  recording_surface->extents_pixels.x,
+				  recording_surface->extents_pixels.y,
+				  recording_surface->extents_pixels.width,
+				  recording_surface->extents_pixels.height,
+				  recording_surface->extents_pixels.x,
+				  recording_surface->extents_pixels.y,
+				  recording_surface->extents_pixels.width,
+				  recording_surface->extents_pixels.height);
 	_cairo_svg_surface_emit_transform (output, "patternTransform", &p2u, parent_matrix);
-	_cairo_output_stream_printf (output, ">\n");
+	_cairo_svg_stream_printf (output, ">\n");
     }
 
-    _cairo_output_stream_printf (output,
-				 "<use xlink:href=\"#source-%d\"",
-				 source_id);
+    _cairo_svg_stream_printf (output,
+			      "<use xlink:href=\"#source-%d\"",
+			      source_id);
 
     if (pattern_id == invalid_pattern_id) {
 	_cairo_svg_surface_emit_transform (output, "transform", &p2u, parent_matrix);
     }
 
-    _cairo_output_stream_printf (output, "/>\n");
+    _cairo_svg_stream_printf (output, "/>\n");
 
     if (pattern_id != invalid_pattern_id) {
-	_cairo_output_stream_printf (output, "</pattern>\n");
+	_cairo_svg_stream_printf (output, "</pattern>\n");
     }
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
-_cairo_svg_surface_emit_composite_pattern (cairo_output_stream_t *output,
+_cairo_svg_surface_emit_composite_pattern (cairo_svg_stream_t *output,
 					   cairo_svg_surface_t *surface,
 					   cairo_surface_pattern_t *pattern,
 					   unsigned int pattern_id,
@@ -2260,16 +2432,16 @@ _cairo_svg_surface_emit_composite_pattern (cairo_output_stream_t *output,
 static cairo_status_t
 _cairo_svg_surface_emit_solid_pattern (cairo_svg_surface_t *surface,
 				       cairo_solid_pattern_t *pattern,
-				       cairo_output_stream_t *output,
+				       cairo_svg_stream_t *output,
 				       cairo_bool_t is_stroke)
 {
-    _cairo_output_stream_printf (output,
-				 is_stroke ? " stroke=\"rgb(%f%%, %f%%, %f%%)\" stroke-opacity=\"%f\""
-					   : " fill=\"rgb(%f%%, %f%%, %f%%)\" fill-opacity=\"%f\"",
-				 pattern->color.red * 100.0,
-				 pattern->color.green * 100.0,
-				 pattern->color.blue * 100.0,
-				 pattern->color.alpha);
+    _cairo_svg_stream_printf (output,
+			      is_stroke ? " stroke=\"rgb(%f%%, %f%%, %f%%)\" stroke-opacity=\"%f\""
+					: " fill=\"rgb(%f%%, %f%%, %f%%)\" fill-opacity=\"%f\"",
+			      pattern->color.red * 100.0,
+			      pattern->color.green * 100.0,
+			      pattern->color.blue * 100.0,
+			      pattern->color.alpha);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -2277,7 +2449,7 @@ _cairo_svg_surface_emit_solid_pattern (cairo_svg_surface_t *surface,
 static cairo_status_t
 _cairo_svg_surface_emit_surface_pattern (cairo_svg_surface_t *surface,
 					 cairo_surface_pattern_t *pattern,
-					 cairo_output_stream_t *output,
+					 cairo_svg_stream_t *output,
 					 cairo_bool_t is_stroke,
 					 const cairo_matrix_t *parent_matrix)
 {
@@ -2286,7 +2458,7 @@ _cairo_svg_surface_emit_surface_pattern (cairo_svg_surface_t *surface,
 
     unsigned int pattern_id = document->pattern_id++;
 
-    status = _cairo_svg_surface_emit_composite_pattern (document->xml_node_defs,
+    status = _cairo_svg_surface_emit_composite_pattern (&document->xml_node_defs,
 							surface,
 							pattern,
 							pattern_id,
@@ -2294,16 +2466,16 @@ _cairo_svg_surface_emit_surface_pattern (cairo_svg_surface_t *surface,
     if (unlikely (status))
 	return status;
 
-    _cairo_output_stream_printf (output,
-				 is_stroke ? " stroke=\"url(#pattern-%d)\""
-					   : " fill=\"url(#pattern-%d)\"",
-				 pattern_id);
+    _cairo_svg_stream_printf (output,
+			      is_stroke ? " stroke=\"url(#pattern-%d)\""
+					: " fill=\"url(#pattern-%d)\"",
+			      pattern_id);
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
-_cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t *output,
+_cairo_svg_surface_emit_pattern_stops (cairo_svg_stream_t *output,
 				       const cairo_gradient_pattern_t *pattern,
 				       double start_offset,
 				       cairo_bool_t reverse_stops,
@@ -2317,15 +2489,15 @@ _cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t *output,
     }
 
     if (pattern->n_stops == 1) {
-	_cairo_output_stream_printf (output,
-				     "<stop offset=\"%f\" "
-				     "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
-				     "stop-opacity=\"%f\"/>\n",
-				     pattern->stops[0].offset,
-				     pattern->stops[0].color.red * 100.0,
-				     pattern->stops[0].color.green * 100.0,
-				     pattern->stops[0].color.blue * 100.0,
-				     pattern->stops[0].color.alpha);
+	_cairo_svg_stream_printf (output,
+				  "<stop offset=\"%f\" "
+				  "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
+				  "stop-opacity=\"%f\"/>\n",
+				  pattern->stops[0].offset,
+				  pattern->stops[0].color.red * 100.0,
+				  pattern->stops[0].color.green * 100.0,
+				  pattern->stops[0].color.blue * 100.0,
+				  pattern->stops[0].color.alpha);
 	return CAIRO_STATUS_SUCCESS;
     }
 
@@ -2362,15 +2534,15 @@ _cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t *output,
 
     if (start_offset >= 0.0) {
 	for (unsigned int i = 0; i < n_stops; i++) {
-	    _cairo_output_stream_printf (output,
-					 "<stop offset=\"%f\" "
-					 "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
-					 "stop-opacity=\"%f\"/>\n",
-					 start_offset + (1.0 - start_offset) * stops[i].offset,
-					 stops[i].color.red * 100.0,
-					 stops[i].color.green * 100.0,
-					 stops[i].color.blue * 100.0,
-					 stops[i].color.alpha);
+	    _cairo_svg_stream_printf (output,
+				      "<stop offset=\"%f\" "
+				      "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
+				      "stop-opacity=\"%f\"/>\n",
+				      start_offset + (1.0 - start_offset) * stops[i].offset,
+				      stops[i].color.red * 100.0,
+				      stops[i].color.green * 100.0,
+				      stops[i].color.blue * 100.0,
+				      stops[i].color.alpha);
 	}
     } else {
 	cairo_bool_t found = FALSE;
@@ -2412,45 +2584,45 @@ _cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t *output,
 	    offset_color_stop = offset_color_start = stops[offset_index].color;
 	}
 
-	_cairo_output_stream_printf (output,
-				     "<stop offset=\"0\" "
-				     "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
-				     "stop-opacity=\"%f\"/>\n",
-				     offset_color_start.red * 100.0,
-				     offset_color_start.green * 100.0,
-				     offset_color_start.blue * 100.0,
-				     offset_color_start.alpha);
+	_cairo_svg_stream_printf (output,
+				  "<stop offset=\"0\" "
+				  "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
+				  "stop-opacity=\"%f\"/>\n",
+				  offset_color_start.red * 100.0,
+				  offset_color_start.green * 100.0,
+				  offset_color_start.blue * 100.0,
+				  offset_color_start.alpha);
 	for (unsigned int i = offset_index; i < n_stops; i++) {
-	    _cairo_output_stream_printf (output,
-					 "<stop offset=\"%f\" "
-					 "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
-					 "stop-opacity=\"%f\"/>\n",
-					 stops[i].offset + start_offset,
-					 stops[i].color.red * 100.0,
-					 stops[i].color.green * 100.0,
-					 stops[i].color.blue * 100.0,
-					 stops[i].color.alpha);
+	    _cairo_svg_stream_printf (output,
+				      "<stop offset=\"%f\" "
+				      "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
+				      "stop-opacity=\"%f\"/>\n",
+				      stops[i].offset + start_offset,
+				      stops[i].color.red * 100.0,
+				      stops[i].color.green * 100.0,
+				      stops[i].color.blue * 100.0,
+				      stops[i].color.alpha);
 	}
 	for (unsigned int i = 0; i < offset_index; i++) {
-	    _cairo_output_stream_printf (output,
-					 "<stop offset=\"%f\" "
-					 "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
-					 "stop-opacity=\"%f\"/>\n",
-					 1.0 + stops[i].offset + start_offset,
-					 stops[i].color.red * 100.0,
-					 stops[i].color.green * 100.0,
-					 stops[i].color.blue * 100.0,
-					 stops[i].color.alpha);
+	    _cairo_svg_stream_printf (output,
+				      "<stop offset=\"%f\" "
+				      "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
+				      "stop-opacity=\"%f\"/>\n",
+				      1.0 + stops[i].offset + start_offset,
+				      stops[i].color.red * 100.0,
+				      stops[i].color.green * 100.0,
+				      stops[i].color.blue * 100.0,
+				      stops[i].color.alpha);
 	}
 
-	_cairo_output_stream_printf (output,
-				     "<stop offset=\"1\" "
-				     "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
-				     "stop-opacity=\"%f\"/>\n",
-				     offset_color_stop.red * 100.0,
-				     offset_color_stop.green * 100.0,
-				     offset_color_stop.blue * 100.0,
-				     offset_color_stop.alpha);
+	_cairo_svg_stream_printf (output,
+				  "<stop offset=\"1\" "
+				  "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
+				  "stop-opacity=\"%f\"/>\n",
+				  offset_color_stop.red * 100.0,
+				  offset_color_stop.green * 100.0,
+				  offset_color_stop.blue * 100.0,
+				  offset_color_stop.alpha);
 
     }
 
@@ -2462,15 +2634,15 @@ _cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t *output,
 }
 
 static void
-_cairo_svg_surface_emit_pattern_extend (cairo_output_stream_t *output,
+_cairo_svg_surface_emit_pattern_extend (cairo_svg_stream_t *output,
 					cairo_pattern_t *pattern)
 {
     switch (pattern->extend) {
     case CAIRO_EXTEND_REPEAT:
-	_cairo_output_stream_printf (output, " spreadMethod=\"repeat\"");
+	_cairo_svg_stream_printf (output, " spreadMethod=\"repeat\"");
 	break;
     case CAIRO_EXTEND_REFLECT:
-	_cairo_output_stream_printf (output, " spreadMethod=\"reflect\"");
+	_cairo_svg_stream_printf (output, " spreadMethod=\"reflect\"");
 	break;
     case CAIRO_EXTEND_NONE:
     case CAIRO_EXTEND_PAD:
@@ -2481,7 +2653,7 @@ _cairo_svg_surface_emit_pattern_extend (cairo_output_stream_t *output,
 static cairo_status_t
 _cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t *surface,
 					cairo_linear_pattern_t *pattern,
-					cairo_output_stream_t *output,
+					cairo_svg_stream_t *output,
 					cairo_bool_t is_stroke,
 					const cairo_matrix_t *parent_matrix)
 {
@@ -2495,19 +2667,19 @@ _cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t *surface,
 
     unsigned int linear_pattern_id = document->linear_pattern_id++;
 
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<linearGradient id=\"linear-pattern-%d\" "
-				 "gradientUnits=\"userSpaceOnUse\" "
-				 "x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\"",
-				 linear_pattern_id,
-				 pattern->pd1.x, pattern->pd1.y,
-				 pattern->pd2.x, pattern->pd2.y);
+    _cairo_svg_stream_printf (&document->xml_node_defs,
+			      "<linearGradient id=\"linear-pattern-%d\" "
+			      "gradientUnits=\"userSpaceOnUse\" "
+			      "x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\"",
+			      linear_pattern_id,
+			      pattern->pd1.x, pattern->pd1.y,
+			      pattern->pd2.x, pattern->pd2.y);
 
-    _cairo_svg_surface_emit_pattern_extend (document->xml_node_defs, &pattern->base.base);
-    _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u, parent_matrix);
-    _cairo_output_stream_printf (document->xml_node_defs, ">\n");
+    _cairo_svg_surface_emit_pattern_extend (&document->xml_node_defs, &pattern->base.base);
+    _cairo_svg_surface_emit_transform (&document->xml_node_defs, "gradientTransform", &p2u, parent_matrix);
+    _cairo_svg_stream_printf (&document->xml_node_defs, ">\n");
 
-    status = _cairo_svg_surface_emit_pattern_stops (document->xml_node_defs,
+    status = _cairo_svg_surface_emit_pattern_stops (&document->xml_node_defs,
 						    &pattern->base,
 						    0.0,
 						    FALSE,
@@ -2515,13 +2687,13 @@ _cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t *surface,
     if (unlikely (status))
 	return status;
 
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "</linearGradient>\n");
+    _cairo_svg_stream_printf (&document->xml_node_defs,
+			      "</linearGradient>\n");
 
-    _cairo_output_stream_printf (output,
-				 is_stroke ? " stroke=\"url(#linear-pattern-%d)\""
-					   : " fill=\"url(#linear-pattern-%d)\"",
-				 linear_pattern_id);
+    _cairo_svg_stream_printf (output,
+			      is_stroke ? " stroke=\"url(#linear-pattern-%d)\""
+					: " fill=\"url(#linear-pattern-%d)\"",
+			      linear_pattern_id);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -2529,7 +2701,7 @@ _cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t *surface,
 static cairo_status_t
 _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface,
 					cairo_radial_pattern_t *pattern,
-					cairo_output_stream_t *output,
+					cairo_svg_stream_t *output,
 					cairo_bool_t is_stroke,
 					const cairo_matrix_t *parent_matrix)
 {
@@ -2604,40 +2776,40 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface,
 	start_offset = r0 / r1;
     }
 
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<radialGradient id=\"radial-pattern-%d\" "
-				 "gradientUnits=\"userSpaceOnUse\" "
-				 "cx=\"%f\" cy=\"%f\" "
-				 "fx=\"%f\" fy=\"%f\" r=\"%f\"",
-				 radial_pattern_id,
-				 x1, y1,
-				 fx, fy, r1);
+    _cairo_svg_stream_printf (&document->xml_node_defs,
+			      "<radialGradient id=\"radial-pattern-%d\" "
+			      "gradientUnits=\"userSpaceOnUse\" "
+			      "cx=\"%f\" cy=\"%f\" "
+			      "fx=\"%f\" fy=\"%f\" r=\"%f\"",
+			      radial_pattern_id,
+			      x1, y1,
+			      fx, fy, r1);
 
     if (emulate_reflect) {
-	_cairo_output_stream_printf (document->xml_node_defs, " spreadMethod=\"repeat\"");
+	_cairo_svg_stream_printf (&document->xml_node_defs, " spreadMethod=\"repeat\"");
     } else {
-	_cairo_svg_surface_emit_pattern_extend (document->xml_node_defs, &pattern->base.base);
+	_cairo_svg_surface_emit_pattern_extend (&document->xml_node_defs, &pattern->base.base);
     }
-    _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u, parent_matrix);
-    _cairo_output_stream_printf (document->xml_node_defs, ">\n");
+    _cairo_svg_surface_emit_transform (&document->xml_node_defs, "gradientTransform", &p2u, parent_matrix);
+    _cairo_svg_stream_printf (&document->xml_node_defs, ">\n");
 
     /* To support cairo's EXTEND_NONE, (for which SVG has no similar
      * notion), we add transparent color stops on either end of the
      * user-provided stops. */
     if (extend == CAIRO_EXTEND_NONE) {
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<stop offset=\"0\" "
-				     "stop-color=\"rgb(0%%, 0%%, 0%%)\" "
-				     "stop-opacity=\"0\"/>\n");
+	_cairo_svg_stream_printf (&document->xml_node_defs,
+				  "<stop offset=\"0\" "
+				  "stop-color=\"rgb(0%%, 0%%, 0%%)\" "
+				  "stop-opacity=\"0\"/>\n");
 	if (r0 != 0.0) {
-	    _cairo_output_stream_printf (document->xml_node_defs,
-					 "<stop offset=\"%f\" "
-					 "stop-color=\"rgb(0%%, 0%%, 0%%)\" "
-					 "stop-opacity=\"0\"/>\n",
-					 r0 / r1);
+	    _cairo_svg_stream_printf (&document->xml_node_defs,
+				      "<stop offset=\"%f\" "
+				      "stop-color=\"rgb(0%%, 0%%, 0%%)\" "
+				      "stop-opacity=\"0\"/>\n",
+				      r0 / r1);
 	}
     }
-    status = _cairo_svg_surface_emit_pattern_stops (document->xml_node_defs,
+    status = _cairo_svg_surface_emit_pattern_stops (&document->xml_node_defs,
 						    &pattern->base,
 						    start_offset,
 						    reverse_stops,
@@ -2647,19 +2819,19 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface,
     }
 
     if (pattern->base.base.extend == CAIRO_EXTEND_NONE) {
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<stop offset=\"1\" "
-				     "stop-color=\"rgb(0%%, 0%%, 0%%)\" "
-				     "stop-opacity=\"0\"/>\n");
+	_cairo_svg_stream_printf (&document->xml_node_defs,
+				  "<stop offset=\"1\" "
+				  "stop-color=\"rgb(0%%, 0%%, 0%%)\" "
+				  "stop-opacity=\"0\"/>\n");
     }
 
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "</radialGradient>\n");
+    _cairo_svg_stream_printf (&document->xml_node_defs,
+			      "</radialGradient>\n");
 
-    _cairo_output_stream_printf (output,
-				 is_stroke ? " stroke=\"url(#radial-pattern-%d)\""
-					   : " fill=\"url(#radial-pattern-%d)\"",
-				 radial_pattern_id);
+    _cairo_svg_stream_printf (output,
+			      is_stroke ? " stroke=\"url(#radial-pattern-%d)\""
+					: " fill=\"url(#radial-pattern-%d)\"",
+			      radial_pattern_id);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -2667,7 +2839,7 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface,
 static cairo_status_t
 _cairo_svg_surface_emit_pattern (cairo_svg_surface_t *surface,
 				 const cairo_pattern_t *pattern,
-				 cairo_output_stream_t *output,
+				 cairo_svg_stream_t *output,
 				 cairo_bool_t is_stroke,
 				 const cairo_matrix_t *parent_matrix)
 {
@@ -2696,20 +2868,20 @@ _cairo_svg_surface_emit_pattern (cairo_svg_surface_t *surface,
 }
 
 static cairo_status_t
-_cairo_svg_surface_emit_fill_style (cairo_output_stream_t *output,
+_cairo_svg_surface_emit_fill_style (cairo_svg_stream_t *output,
 				    cairo_svg_surface_t *surface,
 				    const cairo_pattern_t *source,
 				    cairo_fill_rule_t fill_rule,
 				    const cairo_matrix_t *parent_matrix)
 {
-    _cairo_output_stream_printf (output,
-				 " fill-rule=\"%s\"",
-				 fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero");
+    _cairo_svg_stream_printf (output,
+			      " fill-rule=\"%s\"",
+			      fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero");
     return _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, parent_matrix);
 }
 
 static cairo_status_t
-_cairo_svg_surface_emit_stroke_style (cairo_output_stream_t *output,
+_cairo_svg_surface_emit_stroke_style (cairo_svg_stream_t *output,
 				      cairo_svg_surface_t *surface,
 				      const cairo_pattern_t *source,
 				      const cairo_stroke_style_t *stroke_style,
@@ -2747,13 +2919,13 @@ _cairo_svg_surface_emit_stroke_style (cairo_output_stream_t *output,
 	ASSERT_NOT_REACHED;
     }
 
-    _cairo_output_stream_printf (output,
-				 " stroke-width=\"%f\""
-				 " stroke-linecap=\"%s\""
-				 " stroke-linejoin=\"%s\"",
-				 stroke_style->line_width,
-				 line_cap,
-				 line_join);
+    _cairo_svg_stream_printf (output,
+			      " stroke-width=\"%f\""
+			      " stroke-linecap=\"%s\""
+			      " stroke-linejoin=\"%s\"",
+			      stroke_style->line_width,
+			      line_cap,
+			      line_join);
 
     status = _cairo_svg_surface_emit_pattern (surface, source, output, TRUE, parent_matrix);
     if (unlikely (status)) {
@@ -2761,23 +2933,23 @@ _cairo_svg_surface_emit_stroke_style (cairo_output_stream_t *output,
     }
 
     if (stroke_style->num_dashes > 0) {
-	_cairo_output_stream_printf (output, " stroke-dasharray=\"");
+	_cairo_svg_stream_printf (output, " stroke-dasharray=\"");
 	for (i = 0; i < stroke_style->num_dashes; i++) {
-	    _cairo_output_stream_printf (output,
-					 "%f",
-					 stroke_style->dash[i]);
-	    _cairo_output_stream_printf (output, i + 1 < stroke_style->num_dashes ? " " : "\"");
+	    _cairo_svg_stream_printf (output,
+				      "%f",
+				      stroke_style->dash[i]);
+	    _cairo_svg_stream_printf (output, i + 1 < stroke_style->num_dashes ? " " : "\"");
 	}
 	if (stroke_style->dash_offset != 0.0) {
-	    _cairo_output_stream_printf (output,
-					 " stroke-dashoffset=\"%f\"",
-					 stroke_style->dash_offset);
+	    _cairo_svg_stream_printf (output,
+				      " stroke-dashoffset=\"%f\"",
+				      stroke_style->dash_offset);
 	}
     }
 
-    _cairo_output_stream_printf (output,
-				 " stroke-miterlimit=\"%f\"",
-				 stroke_style->miter_limit);
+    _cairo_svg_stream_printf (output,
+			      " stroke-miterlimit=\"%f\"",
+			      stroke_style->miter_limit);
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -2802,7 +2974,7 @@ _cairo_svg_surface_get_extents (void		        *abstract_surface,
 }
 
 static cairo_status_t
-_cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
+_cairo_svg_surface_emit_paint (cairo_svg_stream_t *output,
 			       cairo_svg_surface_t *surface,
 			       const cairo_pattern_t *source)
 {
@@ -2816,29 +2988,27 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
 							  NULL);
     }
 
-    surface->paint_used = TRUE;
     surface->transitive_paint_used = TRUE;
 
-    _cairo_output_stream_printf (output,
-				 "<use xlink:href=\"#paint-%d\"",
-				 surface->source_id);
+    _cairo_svg_stream_printf (output, "<rect");
+    _cairo_svg_stream_append_rectangle (output, surface->source_id);
     status = _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, NULL);
     if (unlikely (status)) {
 	return status;
     }
-    _cairo_output_stream_printf (output, "/>\n");
+    _cairo_svg_stream_printf (output, "/>\n");
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
-_cairo_svg_surface_do_operator (cairo_output_stream_t *output,
+_cairo_svg_surface_do_operator (cairo_svg_stream_t *output,
 				cairo_svg_surface_t *surface,
 				cairo_operator_t op,
 				const cairo_clip_t *clip,
-				cairo_output_stream_t *mask_stream,
-				cairo_output_stream_t *source_stream,
-				cairo_output_stream_t *destination_stream)
+				cairo_svg_stream_t *mask_stream,
+				cairo_svg_stream_t *source_stream,
+				cairo_svg_stream_t *destination_stream)
 {
     cairo_status_t status;
     cairo_svg_document_t *document = surface->document;
@@ -2862,18 +3032,19 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 	 * but with an empty source.
 	 */
 
-	status = _cairo_output_stream_destroy (source_stream);
+	status = _cairo_svg_stream_destroy (source_stream);
 	if (unlikely (status)) {
-	    (void) _cairo_output_stream_destroy (destination_stream);
-	    (void) _cairo_output_stream_destroy (mask_stream);
+	    (void) _cairo_svg_stream_destroy (destination_stream);
+	    (void) _cairo_svg_stream_destroy (mask_stream);
 	    return status;
 	}
+	cairo_svg_stream_t empty_stream = _cairo_svg_stream_create ();
 	return _cairo_svg_surface_do_operator (output,
 					       surface,
 					       CAIRO_OPERATOR_SOURCE,
 					       clip,
 					       mask_stream,
-					       _cairo_memory_stream_create (),
+					       &empty_stream,
 					       destination_stream);
     }
 
@@ -2896,83 +3067,83 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 	 */
 
 	unsigned int lerp_compositing_group_id = document->compositing_group_id++;
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<g id=\"compositing-group-%d\">\n",
-				     lerp_compositing_group_id);
-	_cairo_svg_surface_emit_paint (document->xml_node_defs, surface, &_cairo_pattern_clear.base);
-	status = _cairo_svg_surface_set_clip (surface, document->xml_node_defs, clip);
+	_cairo_svg_stream_printf (&document->xml_node_defs,
+				  "<g id=\"compositing-group-%d\">\n",
+				  lerp_compositing_group_id);
+	_cairo_svg_surface_emit_paint (&document->xml_node_defs, surface, &_cairo_pattern_clear.base);
+	status = _cairo_svg_surface_set_clip (surface, &document->xml_node_defs, clip);
 	if (unlikely (status)) {
-	    (void) _cairo_output_stream_destroy (destination_stream);
-	    (void) _cairo_output_stream_destroy (source_stream);
-	    (void) _cairo_output_stream_destroy (mask_stream);
+	    (void) _cairo_svg_stream_destroy (destination_stream);
+	    (void) _cairo_svg_stream_destroy (source_stream);
+	    (void) _cairo_svg_stream_destroy (mask_stream);
 	    return status;
 	}
-	_cairo_memory_stream_copy (mask_stream, document->xml_node_defs);
-	status = _cairo_output_stream_destroy (mask_stream);
+	_cairo_svg_stream_copy (mask_stream, &document->xml_node_defs);
+	status = _cairo_svg_stream_destroy (mask_stream);
 	if (unlikely (status)) {
-	    (void) _cairo_output_stream_destroy (destination_stream);
-	    (void) _cairo_output_stream_destroy (source_stream);
+	    (void) _cairo_svg_stream_destroy (destination_stream);
+	    (void) _cairo_svg_stream_destroy (source_stream);
 	    return status;
 	}
 	_cairo_svg_surface_reset_clip (surface);
-	_cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
+	_cairo_svg_stream_printf (&document->xml_node_defs, "</g>\n");
 
 	unsigned int positive_lerp_mask_id = document->mask_id++;
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<mask id=\"mask-%d\">\n",
-				     positive_lerp_mask_id);
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<use xlink:href=\"#compositing-group-%d\"/>\n",
-				     lerp_compositing_group_id);
-	_cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
+	_cairo_svg_stream_printf (&document->xml_node_defs,
+				  "<mask id=\"mask-%d\">\n",
+				  positive_lerp_mask_id);
+	_cairo_svg_stream_printf (&document->xml_node_defs,
+				  "<use xlink:href=\"#compositing-group-%d\"/>\n",
+				  lerp_compositing_group_id);
+	_cairo_svg_stream_printf (&document->xml_node_defs, "</mask>\n");
 
 	unsigned int negative_lerp_mask_id = document->mask_id++;
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<mask id=\"mask-%d\">\n",
-				     negative_lerp_mask_id);
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<use xlink:href=\"#compositing-group-%d\" filter=\"url(#filter-%s)\"/>\n",
-				     lerp_compositing_group_id,
-				     _cairo_svg_surface_emit_static_filter (document,
-									    CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA));
-	_cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
+	_cairo_svg_stream_printf (&document->xml_node_defs,
+				  "<mask id=\"mask-%d\">\n",
+				  negative_lerp_mask_id);
+	_cairo_svg_stream_printf (&document->xml_node_defs,
+				  "<use xlink:href=\"#compositing-group-%d\" filter=\"url(#filter-%s)\"/>\n",
+				  lerp_compositing_group_id,
+				  _cairo_svg_surface_emit_static_filter (document,
+									 CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA));
+	_cairo_svg_stream_printf (&document->xml_node_defs, "</mask>\n");
 
 	unsigned int lerped_source_compositing_group_id = document->compositing_group_id++;
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<g id=\"compositing-group-%d\" mask=\"url(#mask-%d)\">\n",
-				     lerped_source_compositing_group_id,
-				     positive_lerp_mask_id);
-	_cairo_memory_stream_copy (source_stream, document->xml_node_defs);
-	status = _cairo_output_stream_destroy (source_stream);
+	_cairo_svg_stream_printf (&document->xml_node_defs,
+				  "<g id=\"compositing-group-%d\" mask=\"url(#mask-%d)\">\n",
+				  lerped_source_compositing_group_id,
+				  positive_lerp_mask_id);
+	_cairo_svg_stream_copy (source_stream, &document->xml_node_defs);
+	status = _cairo_svg_stream_destroy (source_stream);
 	if (unlikely (status)) {
-	    (void) _cairo_output_stream_destroy (destination_stream);
+	    (void) _cairo_svg_stream_destroy (destination_stream);
 	    return status;
 	}
-	_cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
+	_cairo_svg_stream_printf (&document->xml_node_defs, "</g>\n");
 
 	unsigned int lerped_destination_compositing_group_id = document->compositing_group_id++;
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<g id=\"compositing-group-%d\" mask=\"url(#mask-%d)\">\n",
-				     lerped_destination_compositing_group_id,
-				     negative_lerp_mask_id);
-	_cairo_memory_stream_copy (destination_stream, document->xml_node_defs);
-	status = _cairo_output_stream_destroy (destination_stream);
+	_cairo_svg_stream_printf (&document->xml_node_defs,
+				  "<g id=\"compositing-group-%d\" mask=\"url(#mask-%d)\">\n",
+				  lerped_destination_compositing_group_id,
+				  negative_lerp_mask_id);
+	_cairo_svg_stream_copy (destination_stream, &document->xml_node_defs);
+	status = _cairo_svg_stream_destroy (destination_stream);
 	if (unlikely (status)) {
 	    return status;
 	}
-	_cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
-
-	_cairo_output_stream_printf (surface->xml_node,
-				     "<g filter=\"url(#filter-%d)\">\n",
-				     _cairo_svg_surface_emit_parametric_filter (document,
-										CAIRO_SVG_FILTER_ADD,
-										lerped_source_compositing_group_id,
-										lerped_destination_compositing_group_id));
-	status = _cairo_svg_surface_emit_paint (surface->xml_node, surface, &_cairo_pattern_black.base);
+	_cairo_svg_stream_printf (&document->xml_node_defs, "</g>\n");
+
+	_cairo_svg_stream_printf (&surface->xml_node,
+				  "<g filter=\"url(#filter-%d)\">\n",
+				  _cairo_svg_surface_emit_parametric_filter (document,
+									     CAIRO_SVG_FILTER_ADD,
+									     lerped_source_compositing_group_id,
+									     lerped_destination_compositing_group_id));
+	status = _cairo_svg_surface_emit_paint (&surface->xml_node, surface, &_cairo_pattern_black.base);
 	if (unlikely (status)) {
 	    return status;
 	}
-	_cairo_output_stream_printf (surface->xml_node, "</g>\n");
+	_cairo_svg_stream_printf (&surface->xml_node, "</g>\n");
 
 	return CAIRO_STATUS_SUCCESS;
     }
@@ -2982,19 +3153,19 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 	 * The result is the destination.
 	 */
 
-	_cairo_memory_stream_copy (destination_stream, surface->xml_node);
-	status = _cairo_output_stream_destroy (destination_stream);
+	_cairo_svg_stream_copy (destination_stream, &surface->xml_node);
+	status = _cairo_svg_stream_destroy (destination_stream);
 	if (unlikely (status)) {
-	    (void) _cairo_output_stream_destroy (source_stream);
-	    (void) _cairo_output_stream_destroy (mask_stream);
+	    (void) _cairo_svg_stream_destroy (source_stream);
+	    (void) _cairo_svg_stream_destroy (mask_stream);
 	    return status;
 	}
-	status = _cairo_output_stream_destroy (source_stream);
+	status = _cairo_svg_stream_destroy (source_stream);
 	if (unlikely (status)) {
-	    (void) _cairo_output_stream_destroy (source_stream);
+	    (void) _cairo_svg_stream_destroy (source_stream);
 	    return status;
 	}
-	status = _cairo_output_stream_destroy (source_stream);
+	status = _cairo_svg_stream_destroy (source_stream);
 	if (unlikely (status)) {
 	    return status;
 	}
@@ -3024,88 +3195,88 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
      */
 
     unsigned int lerp_compositing_group_id = document->compositing_group_id++;
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<g id=\"compositing-group-%d\">\n",
-				 lerp_compositing_group_id);
-    _cairo_svg_surface_emit_paint (document->xml_node_defs, surface, &_cairo_pattern_clear.base);
-    status = _cairo_svg_surface_set_clip (surface, document->xml_node_defs, clip);
+    _cairo_svg_stream_printf (&document->xml_node_defs,
+			      "<g id=\"compositing-group-%d\">\n",
+			      lerp_compositing_group_id);
+    _cairo_svg_surface_emit_paint (&document->xml_node_defs, surface, &_cairo_pattern_clear.base);
+    status = _cairo_svg_surface_set_clip (surface, &document->xml_node_defs, clip);
     if (unlikely (status)) {
-	(void) _cairo_output_stream_destroy (destination_stream);
-	(void) _cairo_output_stream_destroy (source_stream);
-	(void) _cairo_output_stream_destroy (mask_stream);
+	(void) _cairo_svg_stream_destroy (destination_stream);
+	(void) _cairo_svg_stream_destroy (source_stream);
+	(void) _cairo_svg_stream_destroy (mask_stream);
 	return status;
     }
-    status = _cairo_svg_surface_emit_paint (document->xml_node_defs, surface, &_cairo_pattern_white.base);
+    status = _cairo_svg_surface_emit_paint (&document->xml_node_defs, surface, &_cairo_pattern_white.base);
     if (unlikely (status)) {
-	(void) _cairo_output_stream_destroy (destination_stream);
-	(void) _cairo_output_stream_destroy (source_stream);
-	(void) _cairo_output_stream_destroy (mask_stream);
+	(void) _cairo_svg_stream_destroy (destination_stream);
+	(void) _cairo_svg_stream_destroy (source_stream);
+	(void) _cairo_svg_stream_destroy (mask_stream);
 	return status;
     }
     _cairo_svg_surface_reset_clip (surface);
-    _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
+    _cairo_svg_stream_printf (&document->xml_node_defs, "</g>\n");
 
     unsigned int positive_lerp_mask_id = document->mask_id++;
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<mask id=\"mask-%d\">\n",
-				 positive_lerp_mask_id);
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<use xlink:href=\"#compositing-group-%d\"/>\n",
-				 lerp_compositing_group_id);
-    _cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
+    _cairo_svg_stream_printf (&document->xml_node_defs,
+			      "<mask id=\"mask-%d\">\n",
+			      positive_lerp_mask_id);
+    _cairo_svg_stream_printf (&document->xml_node_defs,
+			      "<use xlink:href=\"#compositing-group-%d\"/>\n",
+			      lerp_compositing_group_id);
+    _cairo_svg_stream_printf (&document->xml_node_defs, "</mask>\n");
 
     unsigned int negative_lerp_mask_id = document->mask_id++;
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<mask id=\"mask-%d\">\n",
-				 negative_lerp_mask_id);
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<use xlink:href=\"#compositing-group-%d\" filter=\"url(#filter-%s)\"/>\n",
-				 lerp_compositing_group_id,
-				 _cairo_svg_surface_emit_static_filter (document,
-									CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA));
-    _cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
+    _cairo_svg_stream_printf (&document->xml_node_defs,
+			      "<mask id=\"mask-%d\">\n",
+			      negative_lerp_mask_id);
+    _cairo_svg_stream_printf (&document->xml_node_defs,
+			      "<use xlink:href=\"#compositing-group-%d\" filter=\"url(#filter-%s)\"/>\n",
+			      lerp_compositing_group_id,
+			      _cairo_svg_surface_emit_static_filter (document,
+								     CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA));
+    _cairo_svg_stream_printf (&document->xml_node_defs, "</mask>\n");
 
     unsigned int mask_mask_id = document->mask_id++;
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<mask id=\"mask-%d\">\n",
-				 mask_mask_id);
-    _cairo_memory_stream_copy (mask_stream, document->xml_node_defs);
-    status = _cairo_output_stream_destroy (mask_stream);
+    _cairo_svg_stream_printf (&document->xml_node_defs,
+			      "<mask id=\"mask-%d\">\n",
+			      mask_mask_id);
+    _cairo_svg_stream_copy (mask_stream, &document->xml_node_defs);
+    status = _cairo_svg_stream_destroy (mask_stream);
     if (unlikely (status)) {
-	(void) _cairo_output_stream_destroy (source_stream);
-	(void) _cairo_output_stream_destroy (destination_stream);
+	(void) _cairo_svg_stream_destroy (source_stream);
+	(void) _cairo_svg_stream_destroy (destination_stream);
 	return status;
     }
-    _cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
+    _cairo_svg_stream_printf (&document->xml_node_defs, "</mask>\n");
 
     unsigned int masked_source_compositing_group_id = document->compositing_group_id++;
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<g id=\"compositing-group-%d\" mask=\"url(#mask-%d)\">\n",
-				 masked_source_compositing_group_id,
-				 mask_mask_id);
-    _cairo_memory_stream_copy (source_stream, document->xml_node_defs);
-    status = _cairo_output_stream_destroy (source_stream);
+    _cairo_svg_stream_printf (&document->xml_node_defs,
+			      "<g id=\"compositing-group-%d\" mask=\"url(#mask-%d)\">\n",
+			      masked_source_compositing_group_id,
+			      mask_mask_id);
+    _cairo_svg_stream_copy (source_stream, &document->xml_node_defs);
+    status = _cairo_svg_stream_destroy (source_stream);
     if (unlikely (status)) {
-	(void) _cairo_output_stream_destroy (destination_stream);
+	(void) _cairo_svg_stream_destroy (destination_stream);
 	return status;
     }
-    _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
+    _cairo_svg_stream_printf (&document->xml_node_defs, "</g>\n");
 
     unsigned int destination_compositing_group_id = document->compositing_group_id++;
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<g id=\"compositing-group-%d\">\n",
-				 destination_compositing_group_id);
-    _cairo_memory_stream_copy (destination_stream, document->xml_node_defs);
-    status = _cairo_output_stream_destroy (destination_stream);
+    _cairo_svg_stream_printf (&document->xml_node_defs,
+			      "<g id=\"compositing-group-%d\">\n",
+			      destination_compositing_group_id);
+    _cairo_svg_stream_copy (destination_stream, &document->xml_node_defs);
+    status = _cairo_svg_stream_destroy (destination_stream);
     if (unlikely (status)) {
 	return status;
     }
-    _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
+    _cairo_svg_stream_printf (&document->xml_node_defs, "</g>\n");
 
     unsigned int lerped_operation_compositing_group_id = document->compositing_group_id++;
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<g id=\"compositing-group-%d\" ",
-				 lerped_operation_compositing_group_id);
+    _cairo_svg_stream_printf (&document->xml_node_defs,
+			      "<g id=\"compositing-group-%d\" ",
+			      lerped_operation_compositing_group_id);
     unsigned int filter_id;
     switch (op) {
     case CAIRO_OPERATOR_CLEAR:
@@ -3263,78 +3434,78 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
     default:
 	ASSERT_NOT_REACHED;
     }
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "filter=\"url(#filter-%d)\" mask=\"url(#mask-%d)\">\n",
-				 filter_id,
-				 positive_lerp_mask_id);
-    status = _cairo_svg_surface_emit_paint (document->xml_node_defs, surface, &_cairo_pattern_black.base);
+    _cairo_svg_stream_printf (&document->xml_node_defs,
+			      "filter=\"url(#filter-%d)\" mask=\"url(#mask-%d)\">\n",
+			      filter_id,
+			      positive_lerp_mask_id);
+    status = _cairo_svg_surface_emit_paint (&document->xml_node_defs, surface, &_cairo_pattern_black.base);
     if (unlikely (status)) {
 	return status;
     }
-    _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
+    _cairo_svg_stream_printf (&document->xml_node_defs, "</g>\n");
 
     unsigned int lerped_destination_compositing_group_id = document->compositing_group_id++;
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<g id=\"compositing-group-%d\" mask=\"url(#mask-%d)\">\n",
-				 lerped_destination_compositing_group_id,
-				 negative_lerp_mask_id);
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<use xlink:href=\"#compositing-group-%d\"/>\n",
-				 destination_compositing_group_id);
-    _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
-
-    _cairo_output_stream_printf (surface->xml_node,
-				 "<g filter=\"url(#filter-%d)\">\n",
-				 _cairo_svg_surface_emit_parametric_filter (document,
-									    CAIRO_SVG_FILTER_ADD,
-									    lerped_operation_compositing_group_id,
-									    lerped_destination_compositing_group_id));
-    status = _cairo_svg_surface_emit_paint (surface->xml_node, surface, &_cairo_pattern_black.base);
+    _cairo_svg_stream_printf (&document->xml_node_defs,
+			      "<g id=\"compositing-group-%d\" mask=\"url(#mask-%d)\">\n",
+			      lerped_destination_compositing_group_id,
+			      negative_lerp_mask_id);
+    _cairo_svg_stream_printf (&document->xml_node_defs,
+			      "<use xlink:href=\"#compositing-group-%d\"/>\n",
+			      destination_compositing_group_id);
+    _cairo_svg_stream_printf (&document->xml_node_defs, "</g>\n");
+
+    _cairo_svg_stream_printf (&surface->xml_node,
+			      "<g filter=\"url(#filter-%d)\">\n",
+			      _cairo_svg_surface_emit_parametric_filter (document,
+									 CAIRO_SVG_FILTER_ADD,
+									 lerped_operation_compositing_group_id,
+									 lerped_destination_compositing_group_id));
+    status = _cairo_svg_surface_emit_paint (&surface->xml_node, surface, &_cairo_pattern_black.base);
     if (unlikely (status)) {
 	return status;
     }
-    _cairo_output_stream_printf (surface->xml_node, "</g>\n");
+    _cairo_svg_stream_printf (&surface->xml_node, "</g>\n");
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 #define _CAIRO_SVG_SURFACE_CALL_OPERATOR_IMPL(OPERATOR_IMPL, SOURCE, ...) \
     if (op == CAIRO_OPERATOR_OVER) { \
-        status = _cairo_svg_surface_set_clip (surface, surface->xml_node, clip); \
+        status = _cairo_svg_surface_set_clip (surface, &surface->xml_node, clip); \
         if (unlikely (status)) { \
             return status; \
         } \
-        return OPERATOR_IMPL (surface->xml_node, surface, SOURCE, ## __VA_ARGS__); \
+        return OPERATOR_IMPL (&surface->xml_node, surface, SOURCE, ## __VA_ARGS__); \
     } else { \
         _cairo_svg_surface_reset_clip (surface); \
-        cairo_output_stream_t *mask_stream = _cairo_memory_stream_create (); \
-        status = OPERATOR_IMPL (mask_stream, surface, &_cairo_pattern_white.base, ## __VA_ARGS__); \
+        cairo_svg_stream_t mask_stream = _cairo_svg_stream_create (); \
+        status = OPERATOR_IMPL (&mask_stream, surface, &_cairo_pattern_white.base, ## __VA_ARGS__); \
         if (unlikely (status)) { \
-            (void) _cairo_output_stream_destroy (mask_stream); \
+            (void) _cairo_svg_stream_destroy (&mask_stream); \
             return status; \
         } \
-        cairo_output_stream_t *source_stream = _cairo_memory_stream_create (); \
-        status = _cairo_svg_surface_emit_paint (source_stream, \
+        cairo_svg_stream_t source_stream = _cairo_svg_stream_create (); \
+        status = _cairo_svg_surface_emit_paint (&source_stream, \
                                                 surface, \
                                                 SOURCE); \
         if (unlikely (status)) { \
-            (void) _cairo_output_stream_destroy (source_stream); \
-            (void) _cairo_output_stream_destroy (mask_stream); \
+            (void) _cairo_svg_stream_destroy (&source_stream); \
+            (void) _cairo_svg_stream_destroy (&mask_stream); \
             return status; \
         } \
-        cairo_output_stream_t *destination_stream = surface->xml_node; \
-        surface->xml_node = _cairo_memory_stream_create (); \
-        return _cairo_svg_surface_do_operator (surface->xml_node, \
+        cairo_svg_stream_t destination_stream = surface->xml_node; \
+        surface->xml_node = _cairo_svg_stream_create (); \
+        return _cairo_svg_surface_do_operator (&surface->xml_node, \
                                                surface, \
                                                op, \
                                                clip, \
-                                               mask_stream, \
-                                               source_stream, \
-                                               destination_stream); \
+                                               &mask_stream, \
+                                               &source_stream, \
+                                               &destination_stream); \
     }
 
 static cairo_int_status_t
-_cairo_svg_surface_paint_impl (cairo_output_stream_t *output,
+_cairo_svg_surface_paint_impl (cairo_svg_stream_t *output,
 			       cairo_svg_surface_t *surface,
 			       const cairo_pattern_t *source)
 {
@@ -3359,12 +3530,12 @@ _cairo_svg_surface_paint (void *abstract_surface,
 	case CAIRO_PAGINATED_MODE_ANALYZE:
 	    return CAIRO_STATUS_SUCCESS;
 	case CAIRO_PAGINATED_MODE_RENDER:
-	    status = _cairo_output_stream_destroy (surface->xml_node);
+	    status = _cairo_svg_stream_destroy (&surface->xml_node);
 	    if (unlikely (status)) {
 		return status;
 	    }
 
-	    surface->xml_node = _cairo_memory_stream_create ();
+	    surface->xml_node = _cairo_svg_stream_create ();
 
 	    if (op == CAIRO_OPERATOR_CLEAR) {
 		return CAIRO_STATUS_SUCCESS;
@@ -3384,7 +3555,7 @@ _cairo_svg_surface_paint (void *abstract_surface,
 }
 
 static cairo_int_status_t
-_cairo_svg_surface_mask_impl (cairo_output_stream_t *output,
+_cairo_svg_surface_mask_impl (cairo_svg_stream_t *output,
 			      cairo_svg_surface_t *surface,
 			      const cairo_pattern_t *source,
 			      const cairo_pattern_t *mask)
@@ -3395,32 +3566,32 @@ _cairo_svg_surface_mask_impl (cairo_output_stream_t *output,
     /* _cairo_svg_surface_emit_paint() will output a pattern definition to
      * document->xml_node_defs so we need to write the mask element to
      * a temporary stream and then copy that to xml_node_defs. */
-    cairo_output_stream_t *temporary_stream = _cairo_memory_stream_create ();
+    cairo_svg_stream_t temporary_stream = _cairo_svg_stream_create ();
 
     unsigned int mask_id = document->mask_id++;
 
-    _cairo_output_stream_printf (temporary_stream,
+    _cairo_svg_stream_printf (&temporary_stream,
 				 "<mask id=\"mask-%d\">\n",
 				 mask_id);
-    _cairo_output_stream_printf (temporary_stream,
+    _cairo_svg_stream_printf (&temporary_stream,
 				 "<g filter=\"url(#filter-%s)\">\n",
 				 _cairo_svg_surface_emit_static_filter (document, CAIRO_SVG_FILTER_REMOVE_COLOR));
-    status = _cairo_svg_surface_emit_paint (temporary_stream, surface, mask);
+    status = _cairo_svg_surface_emit_paint (&temporary_stream, surface, mask);
     if (unlikely (status)) {
-	(void) _cairo_output_stream_destroy (temporary_stream);
+	(void) _cairo_svg_stream_destroy (&temporary_stream);
 	return status;
     }
-    _cairo_output_stream_printf (temporary_stream, "</g>\n");
-    _cairo_output_stream_printf (temporary_stream, "</mask>\n");
+    _cairo_svg_stream_printf (&temporary_stream, "</g>\n");
+    _cairo_svg_stream_printf (&temporary_stream, "</mask>\n");
 
-    _cairo_memory_stream_copy (temporary_stream, document->xml_node_defs);
+    _cairo_svg_stream_copy (&temporary_stream, &document->xml_node_defs);
 
-    status = _cairo_output_stream_destroy (temporary_stream);
+    status = _cairo_svg_stream_destroy (&temporary_stream);
     if (unlikely (status)) {
 	return status;
     }
 
-    _cairo_output_stream_printf (output,
+    _cairo_svg_stream_printf (output,
 				 "<g mask=\"url(#mask-%d)\">\n",
 				 mask_id);
 
@@ -3429,7 +3600,7 @@ _cairo_svg_surface_mask_impl (cairo_output_stream_t *output,
 	return status;
     }
 
-    _cairo_output_stream_printf (output, "</g>\n");
+    _cairo_svg_stream_printf (output, "</g>\n");
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -3457,7 +3628,7 @@ _cairo_svg_surface_mask (void *abstract_surface,
 }
 
 static cairo_int_status_t
-_cairo_svg_surface_stroke_impl (cairo_output_stream_t *output,
+_cairo_svg_surface_stroke_impl (cairo_svg_stream_t *output,
 				cairo_svg_surface_t *surface,
 				const cairo_pattern_t *source,
 				const cairo_path_fixed_t *path,
@@ -3471,18 +3642,18 @@ _cairo_svg_surface_stroke_impl (cairo_output_stream_t *output,
 
     cairo_bool_t svg_clip_or_svg_mask_should_be_used = _cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (source);
     unsigned int mask_id;
-    cairo_output_stream_t *output_stream = output;
+    cairo_svg_stream_t *output_stream = output;
     if (svg_clip_or_svg_mask_should_be_used) {
 	mask_id = surface->document->mask_id++;
 
-	output_stream = surface->document->xml_node_defs;
+	output_stream = &surface->document->xml_node_defs;
 
-	_cairo_output_stream_printf (output_stream,
-				     "<mask id=\"mask-%d\">\n",
-				     mask_id);
+	_cairo_svg_stream_printf (output_stream,
+				  "<mask id=\"mask-%d\">\n",
+				  mask_id);
     }
 
-    _cairo_output_stream_printf (output_stream, "<path fill=\"none\"");
+    _cairo_svg_stream_printf (output_stream, "<path fill=\"none\"");
     status = _cairo_svg_surface_emit_stroke_style (output_stream,
 						   surface,
 						   svg_clip_or_svg_mask_should_be_used ? &_cairo_pattern_white.base
@@ -3497,14 +3668,14 @@ _cairo_svg_surface_stroke_impl (cairo_output_stream_t *output,
     _cairo_svg_surface_emit_path (output_stream, path, ctm_inverse);
 
     _cairo_svg_surface_emit_transform (output_stream, "transform", ctm, NULL);
-    _cairo_output_stream_printf (output_stream, "/>\n");
+    _cairo_svg_stream_printf (output_stream, "/>\n");
 
     if (svg_clip_or_svg_mask_should_be_used) {
-	_cairo_output_stream_printf (output_stream, "</mask>\n");
+	_cairo_svg_stream_printf (output_stream, "</mask>\n");
 
-	_cairo_output_stream_printf (output,
-				     "<g mask=\"url(#mask-%d)\">\n",
-				     mask_id);
+	_cairo_svg_stream_printf (output,
+				  "<g mask=\"url(#mask-%d)\">\n",
+				  mask_id);
 
 	status = _cairo_svg_surface_emit_composite_pattern (output,
 							    surface,
@@ -3515,7 +3686,7 @@ _cairo_svg_surface_stroke_impl (cairo_output_stream_t *output,
 	    return status;
 	}
 
-	_cairo_output_stream_printf (output, "</g>\n");
+	_cairo_svg_stream_printf (output, "</g>\n");
     }
 
     return CAIRO_STATUS_SUCCESS;
@@ -3553,7 +3724,7 @@ _cairo_svg_surface_stroke (void *abstract_dst,
 }
 
 static cairo_int_status_t
-_cairo_svg_surface_fill_impl (cairo_output_stream_t *output,
+_cairo_svg_surface_fill_impl (cairo_svg_stream_t *output,
 			      cairo_svg_surface_t *surface,
 			      const cairo_pattern_t *source,
 			      const cairo_path_fixed_t *path,
@@ -3564,21 +3735,21 @@ _cairo_svg_surface_fill_impl (cairo_output_stream_t *output,
     cairo_status_t status;
 
     if (_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (source)) {
-	_cairo_output_stream_printf (surface->document->xml_node_defs,
-				     "<clipPath id=\"clip-%d\">\n",
-				     surface->document->clip_id);
+	_cairo_svg_stream_printf (&surface->document->xml_node_defs,
+				  "<clipPath id=\"clip-%d\">\n",
+				  surface->document->clip_id);
 
-	_cairo_output_stream_printf (surface->document->xml_node_defs,
-				     "<path clip-rule=\"%s\"",
-				     fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero");
-	_cairo_svg_surface_emit_path (surface->document->xml_node_defs, path, NULL);
-	_cairo_output_stream_printf (surface->document->xml_node_defs, "/>\n");
+	_cairo_svg_stream_printf (&surface->document->xml_node_defs,
+				  "<path clip-rule=\"%s\"",
+				  fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero");
+	_cairo_svg_surface_emit_path (&surface->document->xml_node_defs, path, NULL);
+	_cairo_svg_stream_printf (&surface->document->xml_node_defs, "/>\n");
 
-	_cairo_output_stream_printf (surface->document->xml_node_defs, "</clipPath>\n");
+	_cairo_svg_stream_printf (&surface->document->xml_node_defs, "</clipPath>\n");
 
-	_cairo_output_stream_printf (output,
-				     "<g clip-path=\"url(#clip-%d)\">\n",
-				     surface->document->clip_id++);
+	_cairo_svg_stream_printf (output,
+				  "<g clip-path=\"url(#clip-%d)\">\n",
+				  surface->document->clip_id++);
 
 	status = _cairo_svg_surface_emit_composite_pattern (output,
 							    surface,
@@ -3589,15 +3760,15 @@ _cairo_svg_surface_fill_impl (cairo_output_stream_t *output,
 	    return status;
 	}
 
-	_cairo_output_stream_printf (output, "</g>");
+	_cairo_svg_stream_printf (output, "</g>");
     } else {
-	_cairo_output_stream_printf (output, "<path");
+	_cairo_svg_stream_printf (output, "<path");
 	status = _cairo_svg_surface_emit_fill_style (output, surface, source, fill_rule, NULL);
 	if (unlikely (status)) {
 	    return status;
 	}
 	_cairo_svg_surface_emit_path (output, path, NULL);
-	_cairo_output_stream_printf (output, "/>\n");
+	_cairo_svg_stream_printf (output, "/>\n");
     }
 
     return CAIRO_STATUS_SUCCESS;
@@ -3664,35 +3835,35 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface,
 	       : CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    status = _cairo_svg_surface_set_clip (surface, surface->xml_node, clip);
+    status = _cairo_svg_surface_set_clip (surface, &surface->xml_node, clip);
     if (unlikely (status)) {
 	return status;
     }
 
-    _cairo_output_stream_printf (surface->xml_node, "<path");
-    status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface,
+    _cairo_svg_stream_printf (&surface->xml_node, "<path");
+    status = _cairo_svg_surface_emit_fill_style (&surface->xml_node, surface,
 						 fill_source, fill_rule, stroke_ctm_inverse);
     if (unlikely (status)) {
 	return status;
     }
 
-    status = _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface,
+    status = _cairo_svg_surface_emit_stroke_style (&surface->xml_node, surface,
 						   stroke_source, stroke_style, stroke_ctm_inverse);
     if (unlikely (status)) {
 	return status;
     }
 
-    _cairo_svg_surface_emit_path (surface->xml_node, path, stroke_ctm_inverse);
+    _cairo_svg_surface_emit_path (&surface->xml_node, path, stroke_ctm_inverse);
 
-    _cairo_svg_surface_emit_transform (surface->xml_node, "transform", stroke_ctm, NULL);
+    _cairo_svg_surface_emit_transform (&surface->xml_node, "transform", stroke_ctm, NULL);
 
-    _cairo_output_stream_printf (surface->xml_node, "/>\n");
+    _cairo_svg_stream_printf (&surface->xml_node, "/>\n");
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
-_cairo_svg_surface_show_glyphs_impl (cairo_output_stream_t *output,
+_cairo_svg_surface_show_glyphs_impl (cairo_svg_stream_t *output,
 				     cairo_svg_surface_t *surface,
 				     const cairo_pattern_t *source,
 				     cairo_glyph_t *glyphs,
@@ -3713,14 +3884,14 @@ _cairo_svg_surface_show_glyphs_impl (cairo_output_stream_t *output,
 	goto fallback;
     }
 
-    _cairo_output_stream_printf (output, "<g");
+    _cairo_svg_stream_printf (output, "<g");
 
     status = _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, NULL);
     if (unlikely (status)) {
 	return status;
     }
 
-    _cairo_output_stream_printf (output, ">\n");
+    _cairo_svg_stream_printf (output, ">\n");
 
     for (int i = 0; i < num_glyphs; i++) {
 	cairo_scaled_font_subsets_glyph_t subset_glyph;
@@ -3732,7 +3903,7 @@ _cairo_svg_surface_show_glyphs_impl (cairo_output_stream_t *output,
 						       0,
 						       &subset_glyph);
 	if ((cairo_int_status_t) status == CAIRO_INT_STATUS_UNSUPPORTED) {
-	    _cairo_output_stream_printf (output, "</g>\n");
+	    _cairo_svg_stream_printf (output, "</g>\n");
 
 	    glyphs += i;
 	    num_glyphs -= i;
@@ -3743,14 +3914,14 @@ _cairo_svg_surface_show_glyphs_impl (cairo_output_stream_t *output,
 	    return status;
 	}
 
-	_cairo_output_stream_printf (output,
-				     "<use xlink:href=\"#glyph-%d-%d\" x=\"%f\" y=\"%f\"/>\n",
-				     subset_glyph.font_id,
-				     subset_glyph.subset_glyph_index,
-				     glyphs[i].x, glyphs[i].y);
+	_cairo_svg_stream_printf (output,
+				  "<use xlink:href=\"#glyph-%d-%d\" x=\"%f\" y=\"%f\"/>\n",
+				  subset_glyph.font_id,
+				  subset_glyph.subset_glyph_index,
+				  glyphs[i].x, glyphs[i].y);
     }
 
-    _cairo_output_stream_printf (output, "</g>\n");
+    _cairo_svg_stream_printf (output, "</g>\n");
 
     return CAIRO_STATUS_SUCCESS;
 
@@ -3887,9 +4058,9 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream,
     document->height = height;
     document->unit = CAIRO_SVG_UNIT_USER;
 
-    document->xml_node_defs = _cairo_memory_stream_create ();
-    document->xml_node_glyphs = _cairo_memory_stream_create ();
-    document->xml_node_filters = _cairo_memory_stream_create ();
+    document->xml_node_defs = _cairo_svg_stream_create ();
+    document->xml_node_glyphs = _cairo_svg_stream_create ();
+    document->xml_node_filters = _cairo_svg_stream_create ();
 
     document->linear_pattern_id = 0;
     document->radial_pattern_id = 0;
@@ -3908,18 +4079,18 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream,
     /* The use of defs for font glyphs imposes no per-subset limit. */
     document->font_subsets = _cairo_scaled_font_subsets_create_scaled ();
     if (unlikely (document->font_subsets == NULL)) {
-	(void) _cairo_output_stream_destroy(document->xml_node_defs);
-	(void) _cairo_output_stream_destroy(document->xml_node_glyphs);
-	(void) _cairo_output_stream_destroy(document->xml_node_filters);
+	(void) _cairo_svg_stream_destroy(&document->xml_node_defs);
+	(void) _cairo_svg_stream_destroy(&document->xml_node_glyphs);
+	(void) _cairo_svg_stream_destroy(&document->xml_node_filters);
 	free (document);
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     }
 
     document->paints = _cairo_hash_table_create (_cairo_svg_paint_equal);
     if (unlikely (document->paints == NULL)) {
-	(void) _cairo_output_stream_destroy(document->xml_node_defs);
-	(void) _cairo_output_stream_destroy(document->xml_node_glyphs);
-	(void) _cairo_output_stream_destroy(document->xml_node_filters);
+	(void) _cairo_svg_stream_destroy(&document->xml_node_defs);
+	(void) _cairo_svg_stream_destroy(&document->xml_node_glyphs);
+	(void) _cairo_svg_stream_destroy(&document->xml_node_filters);
 	_cairo_scaled_font_subsets_destroy (document->font_subsets);
 	free (document);
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -4006,7 +4177,7 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
     if (document->owner != NULL) {
 	surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (document->owner);
 
-	if (surface->xml_node != NULL && _cairo_memory_stream_length (surface->xml_node) > 0) {
+	if (surface->xml_node.elements.num_elements > 0) {
 	    cairo_svg_page_t *page = _cairo_svg_surface_store_page (surface);
 	    if (final_status == CAIRO_STATUS_SUCCESS && page == NULL) {
 		final_status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -4019,7 +4190,6 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
 		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	    }
 	    paint_entry->source_id = surface->source_id;
-	    paint_entry->paint_used = surface->paint_used;
 	    paint_entry->box.p1.x = 0;
 	    paint_entry->box.p1.y = 0;
 	    paint_entry->box.p2.x = document->width;
@@ -4036,32 +4206,30 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
 
     _cairo_hash_table_foreach (document->paints, _cairo_svg_paint_compute_func, document);
 
-    if (_cairo_memory_stream_length (document->xml_node_filters) > 0 ||
-	_cairo_memory_stream_length (document->xml_node_glyphs) > 0 ||
-	_cairo_memory_stream_length (document->xml_node_defs) > 0 ||
-	_cairo_hash_table_size (document->paints) != 0) {
+    if (document->xml_node_filters.elements.num_elements > 0 ||
+	document->xml_node_glyphs.elements.num_elements > 0 ||
+	document->xml_node_defs.elements.num_elements > 0) {
 	_cairo_output_stream_printf (output, "<defs>\n");
-	_cairo_memory_stream_copy (document->xml_node_filters, output);
-	if (_cairo_memory_stream_length (document->xml_node_glyphs) > 0) {
+	_cairo_svg_stream_copy_to_output_stream (&document->xml_node_filters, output, document->paints);
+	if (document->xml_node_glyphs.elements.num_elements > 0) {
 	    _cairo_output_stream_printf (output, "<g>\n");
-	    _cairo_memory_stream_copy (document->xml_node_glyphs, output);
+	    _cairo_svg_stream_copy_to_output_stream (&document->xml_node_glyphs, output, document->paints);
 	    _cairo_output_stream_printf (output, "</g>\n");
 	}
-	_cairo_memory_stream_copy (document->xml_node_defs, output);
-	_cairo_hash_table_foreach (document->paints, _cairo_svg_paint_emit_func, output);
+	_cairo_svg_stream_copy_to_output_stream (&document->xml_node_defs, output, document->paints);
 	_cairo_output_stream_printf (output, "</defs>\n");
     }
 
     if (document->owner != NULL) {
 	if (surface->page_set.num_elements == 1) {
 	    cairo_svg_page_t *page = _cairo_array_index (&surface->page_set, 0);
-	    _cairo_memory_stream_copy (page->xml_node, output);
+	    _cairo_svg_stream_copy_to_output_stream (&page->xml_node, output, document->paints);
 	} else if (surface->page_set.num_elements > 1) {
 	    _cairo_output_stream_printf (output, "<pageSet>\n");
 	    for (unsigned int i = 0; i < surface->page_set.num_elements; i++) {
 		cairo_svg_page_t *page = _cairo_array_index (&surface->page_set, i);
 		_cairo_output_stream_printf (output, "<page>\n");
-		_cairo_memory_stream_copy (page->xml_node, output);
+		_cairo_svg_stream_copy_to_output_stream (&page->xml_node, output, document->paints);
 		_cairo_output_stream_printf (output, "</page>\n");
 	    }
 	    _cairo_output_stream_printf (output, "</pageSet>\n");
@@ -4070,17 +4238,17 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
 
     _cairo_output_stream_printf (output, "</svg>\n");
 
-    status = _cairo_output_stream_destroy (document->xml_node_defs);
+    status = _cairo_svg_stream_destroy (&document->xml_node_defs);
     if (final_status == CAIRO_STATUS_SUCCESS) {
 	final_status = status;
     }
 
-    status = _cairo_output_stream_destroy (document->xml_node_glyphs);
+    status = _cairo_svg_stream_destroy (&document->xml_node_glyphs);
     if (final_status == CAIRO_STATUS_SUCCESS) {
 	final_status = status;
     }
 
-    status = _cairo_output_stream_destroy (document->xml_node_filters);
+    status = _cairo_svg_stream_destroy (&document->xml_node_filters);
     if (final_status == CAIRO_STATUS_SUCCESS) {
 	final_status = status;
     }
commit 56378ee69e599b553f15ccf12fef41f6f3e6d8b8
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sun May 2 19:28:55 2021 +0200

    Do not try to emulate the fill_stroke operations ourselves

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 59173eab1..92db887c4 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -3654,20 +3654,7 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface,
 	_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (stroke_source) ||
 	fill_op != CAIRO_OPERATOR_OVER ||
 	stroke_op != CAIRO_OPERATOR_OVER) {
-	status = _cairo_svg_surface_fill (abstract_surface, fill_op, fill_source, path,
-					  fill_rule, fill_tolerance, fill_antialias,
-					  clip);
-	if (unlikely (status)) {
-	    return status;
-	}
-
-	status = _cairo_svg_surface_stroke (abstract_surface, stroke_op, stroke_source, path,
-					    stroke_style, stroke_ctm, stroke_ctm_inverse,
-					    stroke_tolerance, stroke_antialias,
-					    clip);
-	if (unlikely (status)) {
-	    return status;
-	}
+	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
commit 8f4668b4bfb1dcdee6e600a16a6fcc9edb8422be
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sat May 1 23:40:02 2021 +0200

    Disable support for SVG 2 operators

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 782f08f01..59173eab1 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -1368,6 +1368,22 @@ _cairo_svg_surface_are_operation_and_pattern_supported (cairo_svg_surface_t *sur
         return FALSE;
     }
 
+    /* SVG 1.1 does not support these operators. We already have code for them for SVG 2
+     * that can be enabled when SVG 2 becomes widespread.  */
+    if (op == CAIRO_OPERATOR_OVERLAY ||
+	op == CAIRO_OPERATOR_COLOR_DODGE ||
+	op == CAIRO_OPERATOR_COLOR_BURN ||
+	op == CAIRO_OPERATOR_HARD_LIGHT ||
+	op == CAIRO_OPERATOR_SOFT_LIGHT ||
+	op == CAIRO_OPERATOR_DIFFERENCE ||
+	op == CAIRO_OPERATOR_EXCLUSION ||
+	op == CAIRO_OPERATOR_HSL_HUE ||
+	op == CAIRO_OPERATOR_HSL_SATURATION ||
+	op == CAIRO_OPERATOR_HSL_COLOR ||
+	op == CAIRO_OPERATOR_HSL_LUMINOSITY) {
+	return FALSE;
+    }
+
     if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
         /* Do not cause stack overflow because of too deep or infinite recording surfaces. */
 	if (((cairo_surface_pattern_t *) pattern)->surface->type == CAIRO_SURFACE_TYPE_RECORDING &&
@@ -1555,7 +1571,7 @@ _cairo_svg_surface_emit_parametric_filter (cairo_svg_document_t *document,
 	_CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("xor");
 	break;
     case CAIRO_SVG_FILTER_ADD:
-	// This can also be done with <feComposite operator="lighter"/>, but it is not from SVG 1.1
+	// This can also be done with <feComposite operator="lighter"/>, but it is not in SVG 1.1
 	_cairo_output_stream_printf (document->xml_node_filters,
 				     "<filter id=\"filter-%d\" "
 				     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
commit bd487e64fc3680abf2dd9e165c7506043132229d
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sat May 1 23:11:13 2021 +0200

    Add support for CAIRO_CONTENT_COLOR

diff --git a/boilerplate/cairo-boilerplate-svg.c b/boilerplate/cairo-boilerplate-svg.c
index 2787e8567..0c9a3833e 100644
--- a/boilerplate/cairo-boilerplate-svg.c
+++ b/boilerplate/cairo-boilerplate-svg.c
@@ -218,8 +218,6 @@ _cairo_boilerplate_svg_get_image_surface (cairo_surface_t *surface,
     cairo_surface_t *image;
     double x_offset, y_offset;
     double x_scale, y_scale;
-    svg_target_closure_t *ptc = cairo_surface_get_user_data (surface,
-							     &svg_closure_key);
 
     if (page != 0)
 	return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
@@ -230,15 +228,6 @@ _cairo_boilerplate_svg_get_image_surface (cairo_surface_t *surface,
     cairo_surface_set_device_offset (image, x_offset, y_offset);
     cairo_surface_set_device_scale (image, x_scale, y_scale);
     surface = _cairo_boilerplate_get_image_surface (image, 0, width, height);
-    if (ptc->target) {
-	cairo_surface_t *old_surface = surface;
-	surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height);
-	cairo_t *cr = cairo_create (surface);
-	cairo_set_source_surface (cr, old_surface, 0, 0);
-	cairo_paint (cr);
-	cairo_destroy (cr);
-	cairo_surface_destroy (old_surface);
-    }
     cairo_surface_destroy (image);
 
     return surface;
@@ -293,6 +282,19 @@ static const cairo_boilerplate_target_t targets[] = {
 	_cairo_boilerplate_svg_cleanup,
 	NULL, NULL, FALSE, TRUE, TRUE
     },
+    {
+	"svg11", "svg", ".svg", NULL,
+	CAIRO_SURFACE_TYPE_RECORDING, CAIRO_CONTENT_COLOR, 1,
+	"cairo_svg_surface_create",
+	_cairo_boilerplate_svg11_create_surface,
+	cairo_surface_create_similar,
+	_cairo_boilerplate_svg_force_fallbacks,
+	_cairo_boilerplate_svg_finish_surface,
+	_cairo_boilerplate_svg_get_image_surface,
+	_cairo_boilerplate_svg_surface_write_to_png,
+	_cairo_boilerplate_svg_cleanup,
+	NULL, NULL, FALSE, TRUE, TRUE
+    },
 };
 CAIRO_BOILERPLATE (svg, targets)
 
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 8b1339335..782f08f01 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -218,8 +218,6 @@ typedef struct _cairo_svg_surface {
     unsigned int source_id;
     unsigned int depth;
 
-    cairo_content_t content;
-
     double width;
     double height;
     cairo_bool_t surface_bounded;
@@ -277,6 +275,11 @@ _cairo_svg_surface_emit_composite_pattern (cairo_output_stream_t *output,
 					   unsigned int pattern_id,
 					   const cairo_matrix_t *parent_matrix);
 
+static cairo_status_t
+_cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
+			       cairo_svg_surface_t *surface,
+			       const cairo_pattern_t *source);
+
 static const cairo_surface_backend_t cairo_svg_surface_backend;
 static const cairo_paginated_surface_backend_t cairo_svg_surface_paginated_backend;
 
@@ -621,10 +624,10 @@ _cairo_svg_paint_box_add_padding (cairo_box_double_t *box)
     double width = box->p2.x - box->p1.x;
     double height = box->p2.y - box->p1.y;
 
-    box->p1.x -= width / 10;
-    box->p1.y -= height / 10;
-    box->p2.x += width / 10;
-    box->p2.y += height / 10;
+    box->p1.x -= width / 10.0;
+    box->p1.y -= height / 10.0;
+    box->p2.x += width / 10.0;
+    box->p2.y += height / 10.0;
 }
 
 static void
@@ -858,8 +861,6 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
     surface->source_id = surface->base.unique_id;
     surface->depth = 0;
 
-    surface->content = content;
-
     surface->width = width;
     surface->height = height;
     surface->surface_bounded = bounded;
@@ -887,7 +888,7 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
 
 
     paginated = _cairo_paginated_surface_create (&surface->base,
-						 surface->content,
+						 surface->base.content,
 						 &cairo_svg_surface_paginated_backend);
     status = paginated->status;
     if (status == CAIRO_STATUS_SUCCESS) {
@@ -1996,6 +1997,9 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_surface_t *surface,
 					   document->owner->x_fallback_resolution,
 					   document->owner->y_fallback_resolution);
 
+    if (source->base.content == CAIRO_CONTENT_COLOR) {
+	_cairo_svg_surface_emit_paint (svg_surface->xml_node, svg_surface, &_cairo_pattern_black.base);
+    }
     status = _cairo_recording_surface_replay (&source->base, paginated_surface);
     if (unlikely (status)) {
 	cairo_surface_destroy (paginated_surface);
@@ -2683,7 +2687,7 @@ _cairo_svg_surface_emit_fill_style (cairo_output_stream_t *output,
 				    const cairo_matrix_t *parent_matrix)
 {
     _cairo_output_stream_printf (output,
-				 " fill-rule=\"%s\" ",
+				 " fill-rule=\"%s\"",
 				 fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero");
     return _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, parent_matrix);
 }
@@ -2823,6 +2827,19 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
     cairo_status_t status;
     cairo_svg_document_t *document = surface->document;
 
+    // For operators that do not always produce opaque output, we first need to emit a black paint
+    // if the content does not have alpha
+    if (surface->base.content == CAIRO_CONTENT_COLOR && (op == CAIRO_OPERATOR_CLEAR ||
+							 op == CAIRO_OPERATOR_SOURCE ||
+							 op == CAIRO_OPERATOR_IN ||
+							 op == CAIRO_OPERATOR_OUT ||
+							 op == CAIRO_OPERATOR_DEST_IN ||
+							 op == CAIRO_OPERATOR_DEST_OUT ||
+							 op == CAIRO_OPERATOR_DEST_ATOP ||
+							 op == CAIRO_OPERATOR_XOR)) {
+	_cairo_svg_surface_emit_paint (output, surface, &_cairo_pattern_black.base);
+    }
+
     if (op == CAIRO_OPERATOR_CLEAR) {
 	/*
 	 * The result is the same as one of the SOURCE operation application with the same arguments,
diff --git a/test/operator-www.c b/test/operator-www.c
index 3e863040a..8657980ff 100644
--- a/test/operator-www.c
+++ b/test/operator-www.c
@@ -32,7 +32,7 @@ void
 example (cairo_t *cr, char *name)
 {
     cairo_save (cr);
-    cairo_push_group (cr);
+    cairo_push_group_with_content (cr, cairo_surface_get_content (cairo_get_target (cr)));
 
     cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT);
     cairo_clip (cr);
@@ -107,14 +107,23 @@ example (cairo_t *cr, char *name)
     cairo_set_source_rgba (cr, 0, 0, 0.9, 0.4);
     cairo_fill (cr);
 
-    cairo_pop_group_to_source (cr);
+    cairo_pattern_t *pattern = cairo_pop_group (cr);
+    cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT);
+    cairo_clip (cr);
+    // Make problems with CAIRO_CONTENT_COLOR visible
+    if (cairo_surface_get_content (cairo_get_target (cr)) == CAIRO_CONTENT_COLOR) {
+	cairo_set_source_rgb (cr, 1, 1, 1);
+	cairo_paint (cr);
+    }
+    cairo_set_source (cr, pattern);
+    cairo_pattern_destroy (pattern);
     cairo_paint (cr);
     cairo_restore (cr);
 
     cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans",
 			    CAIRO_FONT_SLANT_NORMAL,
 			    CAIRO_FONT_WEIGHT_NORMAL);
-    cairo_set_font_size(cr, 17);
+    cairo_set_font_size (cr, 17);
     cairo_move_to (cr, WIDTH + 20, 70);
     cairo_set_source_rgb (cr, 1, 1, 0);
     cairo_show_text (cr, name);
diff --git a/test/reference/operator-www.image.rgb24.ref.png b/test/reference/operator-www.rgb24.ref.png
similarity index 100%
rename from test/reference/operator-www.image.rgb24.ref.png
rename to test/reference/operator-www.rgb24.ref.png
commit a3e01d9e8c79c4dddd401af15bf37db7d75435ec
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sat May 1 23:05:03 2021 +0200

    Emit a transparent paint in "lerp_compositing_group"s to extends the bounds of the REMOVE_COLOR_AND_INVERT_ALPHA filter

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index a3c82eefc..8b1339335 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -2866,6 +2866,7 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 	_cairo_output_stream_printf (document->xml_node_defs,
 				     "<g id=\"compositing-group-%d\">\n",
 				     lerp_compositing_group_id);
+	_cairo_svg_surface_emit_paint (document->xml_node_defs, surface, &_cairo_pattern_clear.base);
 	status = _cairo_svg_surface_set_clip (surface, document->xml_node_defs, clip);
 	if (unlikely (status)) {
 	    (void) _cairo_output_stream_destroy (destination_stream);
@@ -2993,6 +2994,7 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
     _cairo_output_stream_printf (document->xml_node_defs,
 				 "<g id=\"compositing-group-%d\">\n",
 				 lerp_compositing_group_id);
+    _cairo_svg_surface_emit_paint (document->xml_node_defs, surface, &_cairo_pattern_clear.base);
     status = _cairo_svg_surface_set_clip (surface, document->xml_node_defs, clip);
     if (unlikely (status)) {
 	(void) _cairo_output_stream_destroy (destination_stream);
commit cd0082338e1fb2a4455f11523fd3b60fbcf29e15
Merge: 898021ba3 8f6cfe417
Author: afdw <afdw at yandex.ru>
Date:   Sat May 1 14:40:52 2021 +0000

    Merge branch 'master' into 'svg-backend-work'
    
    # Conflicts:
    #   src/cairo-gstate.c

commit 898021ba3953f1125e9eca42d59f7346ab33cc60
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sat Apr 24 14:36:14 2021 +0200

    Simplify _cairo_hash_table_size

diff --git a/src/cairo-hash.c b/src/cairo-hash.c
index 564ca0732..6dc978bd4 100644
--- a/src/cairo-hash.c
+++ b/src/cairo-hash.c
@@ -588,12 +588,5 @@ _cairo_hash_table_foreach (cairo_hash_table_t	      *hash_table,
 unsigned long
 _cairo_hash_table_size (cairo_hash_table_t *hash_table)
 {
-    unsigned long size = 0;
-    for (unsigned long i = 0; i < *hash_table->table_size; i++) {
-	cairo_hash_entry_t *entry = hash_table->entries[i];
-	if (ENTRY_IS_LIVE(entry)) {
-	    size++;
-	}
-    }
-    return size;
+    return hash_table->live_entries;
 }
commit 0cc63f5d49630d579d97cb22a7c39f1ea31c728e
Merge: 9f44a2a1b de2a71b23
Author: afdw <afdw at yandex.ru>
Date:   Sat Apr 24 12:30:44 2021 +0000

    Merge branch 'master' into 'svg-backend-work'
    
    # Conflicts:
    #   src/cairo-malloc-private.h
    #   src/cairo-svg-surface.c

commit 9f44a2a1b63ca0b63299b2b3291c8942cb368793
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Tue Apr 13 20:58:49 2021 +0200

    Add a small padding around paints

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index bbf2fbb9d..a3c82eefc 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -615,6 +615,18 @@ _cairo_svg_paint_pluck (void *entry, void *closure)
     free (paint);
 }
 
+static void
+_cairo_svg_paint_box_add_padding (cairo_box_double_t *box)
+{
+    double width = box->p2.x - box->p1.x;
+    double height = box->p2.y - box->p1.y;
+
+    box->p1.x -= width / 10;
+    box->p1.y -= height / 10;
+    box->p2.x += width / 10;
+    box->p2.y += height / 10;
+}
+
 static void
 _cairo_svg_paint_compute (cairo_svg_document_t *document, cairo_svg_paint_t *paint) {
     for (unsigned int i = 0; i < paint->paint_elements.num_elements; i++) {
@@ -635,6 +647,7 @@ _cairo_svg_paint_compute (cairo_svg_document_t *document, cairo_svg_paint_t *pai
 					      &box.p1.x, &box.p1.y,
 					      &box.p2.x, &box.p2.y,
 					      NULL);
+	_cairo_svg_paint_box_add_padding (&box);
 
 	if (i == 0) {
 	    paint->box = box;
@@ -1247,6 +1260,7 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document,
 					      &paint_entry->box.p2.x, &paint_entry->box.p2.y,
 					      NULL);
     }
+    _cairo_svg_paint_box_add_padding (&paint_entry->box);
     _cairo_array_init (&paint_entry->paint_elements, sizeof (cairo_svg_paint_element_t));
     _cairo_svg_paint_init_key (paint_entry);
     status = _cairo_hash_table_insert (document->paints, &paint_entry->base);
@@ -3988,6 +4002,7 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
 	    paint_entry->box.p1.y = 0;
 	    paint_entry->box.p2.x = document->width;
 	    paint_entry->box.p2.y = document->height;
+	    _cairo_svg_paint_box_add_padding (&paint_entry->box);
 	    _cairo_array_init (&paint_entry->paint_elements, sizeof (cairo_svg_paint_element_t));
 	    _cairo_svg_paint_init_key (paint_entry);
 	    status = _cairo_hash_table_insert (document->paints, &paint_entry->base);
commit 43a602b18561631b992944d2440c929e225084f6
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Tue Apr 13 18:31:23 2021 +0200

    Skip the color to alpha filter when possible

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 41d5cf0ea..bbf2fbb9d 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -1923,10 +1923,19 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output
 				 "<use xlink:href=\"#source-%d\"",
 				 source_id);
     if (pattern->surface->content == CAIRO_CONTENT_ALPHA) {
-	_cairo_output_stream_printf (output,
-				     " filter=\"url(#filter-%s)\"",
-				     _cairo_svg_surface_emit_static_filter (surface->document,
-									    CAIRO_SVG_FILTER_COLOR_TO_ALPHA));
+	cairo_bool_t can_skip_filter = FALSE;
+	if (pattern->surface->backend &&
+	    pattern->surface->backend->type == CAIRO_SURFACE_TYPE_IMAGE &&
+	    (((cairo_image_surface_t *) pattern->surface)->format == CAIRO_FORMAT_A1 ||
+	     ((cairo_image_surface_t *) pattern->surface)->format == CAIRO_FORMAT_A8)) {
+	    can_skip_filter = TRUE;
+	}
+	if (!can_skip_filter) {
+	    _cairo_output_stream_printf (output,
+					 " filter=\"url(#filter-%s)\"",
+					 _cairo_svg_surface_emit_static_filter (surface->document,
+										CAIRO_SVG_FILTER_COLOR_TO_ALPHA));
+	}
     }
     if (pattern_id == invalid_pattern_id) {
 	_cairo_svg_surface_emit_transform (output,
commit 69d90f3e62902fd5e5f8a9bd50711b3da743839e
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Tue Apr 13 18:03:40 2021 +0200

    Implement attempting to recognize a common pattern for a bitmap font and extract the original glyph image from it

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 594d5a1a2..41d5cf0ea 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -1137,6 +1137,40 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document,
     }
 
     cairo_bool_t use_recording_surface = (scaled_glyph->has_info & CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE) != 0;
+    cairo_matrix_t glyph_matrix = scaled_glyph->surface->base.device_transform_inverse;
+    cairo_image_surface_t *glyph_image_surface = scaled_glyph->surface;
+
+    // Attempt to recognize a common pattern for a bitmap font and extract the original glyph image from it
+    cairo_surface_t *extracted_surface;
+    cairo_image_surface_t *extracted_image = NULL;
+    void *extracted_image_extra;
+    if (use_recording_surface) {
+	cairo_recording_surface_t *recording_surface = (cairo_recording_surface_t *) scaled_glyph->recording_surface;
+	if (recording_surface->commands.num_elements == 1) {
+	    cairo_command_t *command = *((cairo_command_t **) _cairo_array_index (&recording_surface->commands, 0));
+	    if (command->header.type == CAIRO_COMMAND_MASK &&
+		command->header.op == CAIRO_OPERATOR_OVER &&
+		command->header.clip == NULL &&
+		command->mask.source.base.type == CAIRO_PATTERN_TYPE_SOLID &&
+		_cairo_color_equal (&command->mask.source.solid.color, _cairo_stock_color (CAIRO_STOCK_BLACK)) &&
+		command->mask.mask.base.extend == CAIRO_EXTEND_NONE &&
+		command->mask.mask.base.type == CAIRO_PATTERN_TYPE_SURFACE &&
+		command->mask.mask.surface.surface->type == CAIRO_SURFACE_TYPE_IMAGE) {
+		extracted_surface = command->mask.mask.surface.surface;
+		if (_cairo_surface_acquire_source_image (extracted_surface,
+							 &extracted_image,
+							 &extracted_image_extra) == CAIRO_STATUS_SUCCESS) {
+		    if (extracted_image->format == CAIRO_FORMAT_A1 || extracted_image->format == CAIRO_FORMAT_A8) {
+			use_recording_surface = FALSE;
+			glyph_image_surface = extracted_image;
+			glyph_matrix = command->mask.mask.base.matrix;
+			status = cairo_matrix_invert (&glyph_matrix);
+			assert (status == CAIRO_STATUS_SUCCESS);
+		    }
+		}
+	    }
+	}
+    }
 
     cairo_surface_t *paginated_surface = _cairo_svg_surface_create_for_document (document,
 										 CAIRO_CONTENT_COLOR_ALPHA,
@@ -1144,8 +1178,9 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document,
 										 0,
 										 FALSE);
     cairo_svg_surface_t *svg_surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (paginated_surface);
-    if (unlikely (paginated_surface->status)) {
-	return paginated_surface->status;
+    status = paginated_surface->status;
+    if (unlikely (status)) {
+	goto cleanup;
     }
 
     unsigned int source_id = svg_surface->base.unique_id;
@@ -1163,7 +1198,7 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document,
 				 mask_id);
 
     cairo_pattern_t *pattern = cairo_pattern_create_for_surface (use_recording_surface ? scaled_glyph->recording_surface
-										       : &scaled_glyph->surface->base);
+										       : &glyph_image_surface->base);
     _cairo_svg_surface_emit_composite_pattern (temporary_stream,
 					       svg_surface,
 					       (cairo_surface_pattern_t *) pattern,
@@ -1177,7 +1212,7 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document,
 
     status = _cairo_output_stream_destroy (temporary_stream);
     if (unlikely (status)) {
-	return status;
+	goto cleanup;
     }
 
     svg_surface->paint_used = TRUE;
@@ -1190,23 +1225,24 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document,
     if (!use_recording_surface) {
 	_cairo_svg_surface_emit_transform (document->xml_node_glyphs,
 					   "transform",
-					   &scaled_glyph->surface->base.device_transform_inverse,
+					   &glyph_matrix,
 					   NULL);
     }
     _cairo_output_stream_printf (document->xml_node_glyphs, "/>\n");
 
     cairo_svg_paint_t *paint_entry = malloc (sizeof (cairo_svg_paint_t));
     if (paint_entry == NULL) {
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto cleanup;
     }
     paint_entry->source_id = source_id;
     paint_entry->paint_used = svg_surface->paint_used;
     paint_entry->box.p1.x = 0;
     paint_entry->box.p1.y = 0;
-    paint_entry->box.p2.x = scaled_glyph->surface->width;
-    paint_entry->box.p2.y = scaled_glyph->surface->height;
+    paint_entry->box.p2.x = glyph_image_surface->width;
+    paint_entry->box.p2.y = glyph_image_surface->height;
     if (use_recording_surface) {
-	_cairo_matrix_transform_bounding_box (&scaled_glyph->surface->base.device_transform_inverse,
+	_cairo_matrix_transform_bounding_box (&glyph_matrix,
 					      &paint_entry->box.p1.x, &paint_entry->box.p1.y,
 					      &paint_entry->box.p2.x, &paint_entry->box.p2.y,
 					      NULL);
@@ -1215,12 +1251,19 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document,
     _cairo_svg_paint_init_key (paint_entry);
     status = _cairo_hash_table_insert (document->paints, &paint_entry->base);
     if (unlikely (status)) {
-	return status;
+	goto cleanup;
     }
 
-    status = cairo_surface_status (paginated_surface);
+    cleanup:
+    if (status == CAIRO_STATUS_SUCCESS) {
+	status = cairo_surface_status (paginated_surface);
+    }
     cairo_surface_destroy (paginated_surface);
 
+    if (extracted_image != NULL) {
+	_cairo_surface_release_source_image (extracted_surface, extracted_image, extracted_image_extra);
+    }
+
     return status;
 }
 
@@ -2904,6 +2947,7 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
     /*
      * Below we use the "XRender" equation from the "Clipping and masking" section
      * of https://cairographics.org/operators/:
+     * result = ((source IN mask) OP destination) LERP_clip destination
      *
      * It is equivalent to:
      * result = (((source IN mask) OP destination) IN clip) ADD (destination IN (NOT clip))
commit 982c37f5446965c4bcd5754e8b89bca5284469c8
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Tue Apr 13 11:49:32 2021 +0200

    Fix warnings and pipeline failure

diff --git a/src/cairo-svg-surface-private.h b/src/cairo-svg-surface-private.h
index a6e4ea943..e2a194081 100644
--- a/src/cairo-svg-surface-private.h
+++ b/src/cairo-svg-surface-private.h
@@ -41,10 +41,23 @@
 #ifndef CAIRO_SVG_SURFACE_PRIVATE_H
 #define CAIRO_SVG_SURFACE_PRIVATE_H
 
-#include <cairo.h>
+#include "cairo-svg.h"
 
-void
+#include "cairo-surface-private.h"
+
+struct _cairo_svg_surface_start {
+    cairo_surface_t base;
+
+    cairo_bool_t force_fallbacks;
+};
+
+static inline void
 _cairo_svg_surface_set_force_fallbacks (void *abstract_surface,
-					cairo_bool_t force_fallbacks);
+					cairo_bool_t force_fallbacks)
+{
+    struct _cairo_svg_surface_start *surface = (struct _cairo_svg_surface_start *) abstract_surface;
+
+    surface->force_fallbacks = force_fallbacks;
+}
 
 #endif /* CAIRO_SVG_SURFACE_PRIVATE_H */
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index d45a6201a..594d5a1a2 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -77,7 +77,7 @@
  * Since: 1.2
  **/
 
-static const int invalid_pattern_id = -1;
+static const unsigned int invalid_pattern_id = -1;
 
 static const cairo_svg_version_t _cairo_svg_versions[] =
 {
@@ -209,9 +209,12 @@ typedef struct _cairo_svg_document {
     cairo_hash_table_t *paints;
 } cairo_svg_document_t;
 
+// Must be compatible with the struct _cairo_svg_surface_start.
 typedef struct _cairo_svg_surface {
     cairo_surface_t base;
 
+    cairo_bool_t force_fallbacks;
+
     unsigned int source_id;
     unsigned int depth;
 
@@ -236,8 +239,6 @@ typedef struct _cairo_svg_surface {
     cairo_bool_t transitive_paint_used;
 
     cairo_paginated_mode_t paginated_mode;
-
-    cairo_bool_t force_fallbacks;
 } cairo_svg_surface_t;
 
 static cairo_status_t
@@ -419,15 +420,6 @@ _extract_svg_surface (cairo_surface_t *surface,
     return TRUE;
 }
 
-void
-_cairo_svg_surface_set_force_fallbacks (void *abstract_surface,
-					cairo_bool_t force_fallbacks)
-{
-    cairo_svg_surface_t *surface = (cairo_svg_surface_t *) abstract_surface;
-
-    surface->force_fallbacks = force_fallbacks;
-}
-
 /**
  * cairo_svg_surface_restrict_to_version:
  * @surface: a SVG #cairo_surface_t
@@ -1397,7 +1389,7 @@ _cairo_svg_surface_finish (void *abstract_surface)
     return status;
 }
 
-static char *
+static const char *
 _cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cairo_svg_filter filter)
 {
     if (!document->filters_emitted[filter]) {
commit 3cb6377c08182114f15e1fd0e358fe4e92fb8b90
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Tue Apr 13 04:27:26 2021 +0200

    Revert "Fix filter being used on the use element causing the content to be clipped"
    
    This reverts commit 2a8672d06ef98b5375c6eee825791c2797bef078.

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index c444969eb..d45a6201a 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -1884,16 +1884,15 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output
 	_cairo_output_stream_printf (output, ">\n");
     }
 
+    _cairo_output_stream_printf (output,
+				 "<use xlink:href=\"#source-%d\"",
+				 source_id);
     if (pattern->surface->content == CAIRO_CONTENT_ALPHA) {
 	_cairo_output_stream_printf (output,
-				     "<g filter=\"url(#filter-%s)\">\n",
+				     " filter=\"url(#filter-%s)\"",
 				     _cairo_svg_surface_emit_static_filter (surface->document,
 									    CAIRO_SVG_FILTER_COLOR_TO_ALPHA));
     }
-
-    _cairo_output_stream_printf (output,
-				 "<use xlink:href=\"#source-%d\"",
-				 source_id);
     if (pattern_id == invalid_pattern_id) {
 	_cairo_svg_surface_emit_transform (output,
 					   "transform",
@@ -1902,10 +1901,6 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output
     }
     _cairo_output_stream_printf (output, "/>\n");
 
-    if (pattern->surface->content == CAIRO_CONTENT_ALPHA) {
-	_cairo_output_stream_printf (output, "</g>\n");
-    }
-
     if (pattern_id != invalid_pattern_id) {
 	_cairo_output_stream_printf (output, "</pattern>\n");
     }
commit 90aa943555f1861583138b88694012bb93da7b0a
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Tue Apr 13 04:24:43 2021 +0200

    Add support for PDF Type 3 fonts

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index e1ebbc08e..c444969eb 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -1144,6 +1144,8 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document,
 	return status;
     }
 
+    cairo_bool_t use_recording_surface = (scaled_glyph->has_info & CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE) != 0;
+
     cairo_surface_t *paginated_surface = _cairo_svg_surface_create_for_document (document,
 										 CAIRO_CONTENT_COLOR_ALPHA,
 										 0,
@@ -1154,30 +1156,76 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document,
 	return paginated_surface->status;
     }
 
+    unsigned int source_id = svg_surface->base.unique_id;
+
+    cairo_surface_set_fallback_resolution (paginated_surface,
+					   document->owner->x_fallback_resolution,
+					   document->owner->y_fallback_resolution);
+
+    cairo_output_stream_t *temporary_stream = _cairo_memory_stream_create ();
+
     unsigned int mask_id = document->mask_id++;
 
-    _cairo_output_stream_printf (document->xml_node_defs,
+    _cairo_output_stream_printf (temporary_stream,
 				 "<mask id=\"mask-%d\">\n",
 				 mask_id);
 
-    cairo_pattern_t *pattern = cairo_pattern_create_for_surface (&scaled_glyph->surface->base);
-    _cairo_svg_surface_emit_composite_pattern (document->xml_node_glyphs,
+    cairo_pattern_t *pattern = cairo_pattern_create_for_surface (use_recording_surface ? scaled_glyph->recording_surface
+										       : &scaled_glyph->surface->base);
+    _cairo_svg_surface_emit_composite_pattern (temporary_stream,
 					       svg_surface,
 					       (cairo_surface_pattern_t *) pattern,
 					       invalid_pattern_id,
 					       NULL);
     cairo_pattern_destroy (pattern);
 
-    _cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
+    _cairo_output_stream_printf (temporary_stream, "</mask>\n");
+
+    _cairo_memory_stream_copy (temporary_stream, document->xml_node_defs);
+
+    status = _cairo_output_stream_destroy (temporary_stream);
+    if (unlikely (status)) {
+	return status;
+    }
+
+    svg_surface->paint_used = TRUE;
+    svg_surface->transitive_paint_used = TRUE;
 
     _cairo_output_stream_printf (document->xml_node_glyphs,
-				 "<rect x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" mask=\"url(#mask-%d)\"",
-				 scaled_glyph->surface->width, scaled_glyph->surface->height,
+				 "<use xlink:href=\"#paint-%d\" mask=\"url(#mask-%d)\"",
+				 source_id,
 				 mask_id);
-    _cairo_svg_surface_emit_transform (document->xml_node_glyphs, "transform",
-				       &scaled_glyph->surface->base.device_transform_inverse, NULL);
+    if (!use_recording_surface) {
+	_cairo_svg_surface_emit_transform (document->xml_node_glyphs,
+					   "transform",
+					   &scaled_glyph->surface->base.device_transform_inverse,
+					   NULL);
+    }
     _cairo_output_stream_printf (document->xml_node_glyphs, "/>\n");
 
+    cairo_svg_paint_t *paint_entry = malloc (sizeof (cairo_svg_paint_t));
+    if (paint_entry == NULL) {
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+    paint_entry->source_id = source_id;
+    paint_entry->paint_used = svg_surface->paint_used;
+    paint_entry->box.p1.x = 0;
+    paint_entry->box.p1.y = 0;
+    paint_entry->box.p2.x = scaled_glyph->surface->width;
+    paint_entry->box.p2.y = scaled_glyph->surface->height;
+    if (use_recording_surface) {
+	_cairo_matrix_transform_bounding_box (&scaled_glyph->surface->base.device_transform_inverse,
+					      &paint_entry->box.p1.x, &paint_entry->box.p1.y,
+					      &paint_entry->box.p2.x, &paint_entry->box.p2.y,
+					      NULL);
+    }
+    _cairo_array_init (&paint_entry->paint_elements, sizeof (cairo_svg_paint_element_t));
+    _cairo_svg_paint_init_key (paint_entry);
+    status = _cairo_hash_table_insert (document->paints, &paint_entry->base);
+    if (unlikely (status)) {
+	return status;
+    }
+
     status = cairo_surface_status (paginated_surface);
     cairo_surface_destroy (paginated_surface);
 
@@ -1359,7 +1407,6 @@ _cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cair
 	    // (r, g, b, a) -> (1, 1, 1, a)
 	    _cairo_output_stream_printf (document->xml_node_filters,
 					 "<filter id=\"filter-remove-color\" "
-					 "filterUnits=\"userSpaceOnUse\" "
 					 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
 					 "<feColorMatrix values=\"0 0 0 0 1 "
 					 /*                   */ "0 0 0 0 1 "
@@ -1371,7 +1418,6 @@ _cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cair
 	    // (r, g, b, a) -> (1, 1, 1, 1 - a)
 	    _cairo_output_stream_printf (document->xml_node_filters,
 					 "<filter id=\"filter-remove-color-and-invert-alpha\" "
-					 "filterUnits=\"userSpaceOnUse\" "
 					 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
 					 "<feColorMatrix values=\"0 0 0 0 1 "
 					 /*                   */ "0 0 0 0 1 "
@@ -1383,7 +1429,6 @@ _cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cair
 	    // (r, g, b, a) -> (1, 1, 1, 0.2126 * r + 0.7152 * g + 0.0722 * b)
 	    _cairo_output_stream_printf (document->xml_node_filters,
 					 "<filter id=\"filter-color-to-alpha\" "
-					 "filterUnits=\"userSpaceOnUse\" "
 					 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
 					 "<feColorMatrix values=\"0 0 0 0 1 "
 					 /*                   */ "0 0 0 0 1 "
@@ -1410,7 +1455,7 @@ _cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cair
 
 #define _CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER(operation) \
     _cairo_output_stream_printf (document->xml_node_filters, \
-                                 "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" " \
+                                 "<filter id=\"filter-%d\" " \
                                  "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n" \
                                  "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"/>\n" \
                                  "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"/>\n" \
@@ -1424,7 +1469,7 @@ _cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cair
 
 #define _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER(mode) \
     _cairo_output_stream_printf (document->xml_node_filters, \
-                                 "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" " \
+                                 "<filter id=\"filter-%d\" " \
                                  "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n" \
                                  "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"/>\n" \
                                  "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"/>\n" \
@@ -1462,7 +1507,7 @@ _cairo_svg_surface_emit_parametric_filter (cairo_svg_document_t *document,
     case CAIRO_SVG_FILTER_ADD:
 	// This can also be done with <feComposite operator="lighter"/>, but it is not from SVG 1.1
 	_cairo_output_stream_printf (document->xml_node_filters,
-				     "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" "
+				     "<filter id=\"filter-%d\" "
 				     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
 				     "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"/>\n"
 				     "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"/>\n"
commit 1c1bceb581941b304a7ed8ff9fd3519884250633
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Tue Apr 13 02:58:43 2021 +0200

    Emit bitmap glyph data as images instead of as a bunch of squares, as this results in smaller file size and better quality, allowing the use of shades of gray

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 043943e91..e1ebbc08e 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -269,6 +269,13 @@ _cairo_svg_surface_create_for_stream_internal (cairo_output_stream_t	*stream,
 					       double			 height,
 					       cairo_svg_version_t	 version);
 
+static cairo_status_t
+_cairo_svg_surface_emit_composite_pattern (cairo_output_stream_t *output,
+					   cairo_svg_surface_t *surface,
+					   cairo_surface_pattern_t *pattern,
+					   unsigned int pattern_id,
+					   const cairo_matrix_t *parent_matrix);
+
 static const cairo_surface_backend_t cairo_svg_surface_backend;
 static const cairo_paginated_surface_backend_t cairo_svg_surface_paginated_backend;
 
@@ -1122,53 +1129,59 @@ _cairo_svg_document_emit_outline_glyph_data (cairo_svg_document_t *document,
 }
 
 static cairo_int_status_t
-_cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t	*document,
-					    cairo_scaled_font_t		*scaled_font,
-					    unsigned long		 glyph_index)
+_cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document,
+					    cairo_scaled_font_t *scaled_font,
+					    unsigned long glyph_index)
 {
-    cairo_scaled_glyph_t *scaled_glyph;
-    cairo_image_surface_t *image;
     cairo_status_t status;
-    uint8_t *row, *byte;
-    int rows, cols;
-    int x, y, bit;
 
+    cairo_scaled_glyph_t *scaled_glyph;
     status = _cairo_scaled_glyph_lookup (scaled_font,
 					 glyph_index,
-					 CAIRO_SCALED_GLYPH_INFO_METRICS |
-					 CAIRO_SCALED_GLYPH_INFO_SURFACE,
+					 CAIRO_SCALED_GLYPH_INFO_METRICS | CAIRO_SCALED_GLYPH_INFO_SURFACE,
 					 &scaled_glyph);
-    if (unlikely (status))
+    if (unlikely (status)) {
 	return status;
+    }
 
-    image = _cairo_image_surface_coerce_to_format (scaled_glyph->surface,
-					           CAIRO_FORMAT_A1);
-    status = image->base.status;
-    if (unlikely (status))
-	return status;
+    cairo_surface_t *paginated_surface = _cairo_svg_surface_create_for_document (document,
+										 CAIRO_CONTENT_COLOR_ALPHA,
+										 0,
+										 0,
+										 FALSE);
+    cairo_svg_surface_t *svg_surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (paginated_surface);
+    if (unlikely (paginated_surface->status)) {
+	return paginated_surface->status;
+    }
+
+    unsigned int mask_id = document->mask_id++;
+
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<mask id=\"mask-%d\">\n",
+				 mask_id);
+
+    cairo_pattern_t *pattern = cairo_pattern_create_for_surface (&scaled_glyph->surface->base);
+    _cairo_svg_surface_emit_composite_pattern (document->xml_node_glyphs,
+					       svg_surface,
+					       (cairo_surface_pattern_t *) pattern,
+					       invalid_pattern_id,
+					       NULL);
+    cairo_pattern_destroy (pattern);
+
+    _cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
 
-    _cairo_output_stream_printf (document->xml_node_glyphs, "<g");
+    _cairo_output_stream_printf (document->xml_node_glyphs,
+				 "<rect x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" mask=\"url(#mask-%d)\"",
+				 scaled_glyph->surface->width, scaled_glyph->surface->height,
+				 mask_id);
     _cairo_svg_surface_emit_transform (document->xml_node_glyphs, "transform",
-				       &image->base.device_transform_inverse, NULL);
-    _cairo_output_stream_printf (document->xml_node_glyphs, ">\n");
-
-    for (y = 0, row = image->data, rows = image->height; rows; row += image->stride, rows--, y++) {
-	for (x = 0, byte = row, cols = (image->width + 7) / 8; cols; byte++, cols--) {
-	    uint8_t output_byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte);
-	    for (bit = 7; bit >= 0 && x < image->width; bit--, x++) {
-		if (output_byte & (1 << bit)) {
-		    _cairo_output_stream_printf (document->xml_node_glyphs,
-						 "<rect x=\"%d\" y=\"%d\" width=\"1\" height=\"1\"/>\n",
-						 x, y);
-		}
-	    }
-	}
-    }
-    _cairo_output_stream_printf (document->xml_node_glyphs, "</g>\n");
+				       &scaled_glyph->surface->base.device_transform_inverse, NULL);
+    _cairo_output_stream_printf (document->xml_node_glyphs, "/>\n");
 
-    cairo_surface_destroy (&image->base);
+    status = cairo_surface_status (paginated_surface);
+    cairo_surface_destroy (paginated_surface);
 
-    return CAIRO_STATUS_SUCCESS;
+    return status;
 }
 
 static cairo_int_status_t
@@ -3639,7 +3652,7 @@ _cairo_svg_surface_show_glyphs_impl (cairo_output_stream_t *output,
 					   &path,
 					   CAIRO_FILL_RULE_WINDING,
 					   0.0,
-					   CAIRO_ANTIALIAS_SUBPIXEL);
+					   CAIRO_ANTIALIAS_DEFAULT);
 
     _cairo_path_fixed_fini (&path);
 
commit 1fe3c5571253a5b6c7808981babff09af8fbb3ed
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Mon Apr 12 18:49:03 2021 +0200

    Do not emit empty glyph paths

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 40ebdf6af..043943e91 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -1106,15 +1106,17 @@ _cairo_svg_document_emit_outline_glyph_data (cairo_svg_document_t *document,
 	return status;
     }
 
-    _cairo_output_stream_printf (document->xml_node_glyphs,
-				 "<path");
+    if (_cairo_path_fixed_size (scaled_glyph->path) != 0) {
+	_cairo_output_stream_printf (document->xml_node_glyphs,
+				     "<path");
 
-    _cairo_svg_surface_emit_path (document->xml_node_glyphs,
-				  scaled_glyph->path,
-				  NULL);
+	_cairo_svg_surface_emit_path (document->xml_node_glyphs,
+				      scaled_glyph->path,
+				      NULL);
 
-    _cairo_output_stream_printf (document->xml_node_glyphs,
-				 "/>\n");
+	_cairo_output_stream_printf (document->xml_node_glyphs,
+				     "/>\n");
+    }
 
     return status;
 }
commit 2a8672d06ef98b5375c6eee825791c2797bef078
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Mon Apr 12 11:55:56 2021 +0200

    Fix filter being used on the use element causing the content to be clipped

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index e1d61a015..40ebdf6af 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -1824,15 +1824,16 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output
 	_cairo_output_stream_printf (output, ">\n");
     }
 
-    _cairo_output_stream_printf (output,
-				 "<use xlink:href=\"#source-%d\"",
-				 source_id);
     if (pattern->surface->content == CAIRO_CONTENT_ALPHA) {
 	_cairo_output_stream_printf (output,
-				     " filter=\"url(#filter-%s)\"",
+				     "<g filter=\"url(#filter-%s)\">\n",
 				     _cairo_svg_surface_emit_static_filter (surface->document,
 									    CAIRO_SVG_FILTER_COLOR_TO_ALPHA));
     }
+
+    _cairo_output_stream_printf (output,
+				 "<use xlink:href=\"#source-%d\"",
+				 source_id);
     if (pattern_id == invalid_pattern_id) {
 	_cairo_svg_surface_emit_transform (output,
 					   "transform",
@@ -1841,6 +1842,10 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output
     }
     _cairo_output_stream_printf (output, "/>\n");
 
+    if (pattern->surface->content == CAIRO_CONTENT_ALPHA) {
+	_cairo_output_stream_printf (output, "</g>\n");
+    }
+
     if (pattern_id != invalid_pattern_id) {
 	_cairo_output_stream_printf (output, "</pattern>\n");
     }
commit 87d5c9e8d1cb46415f3e1e7b24fff87a6e083b9a
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Mon Apr 12 00:17:51 2021 +0200

    Add missing include

diff --git a/src/cairo-svg-surface-private.h b/src/cairo-svg-surface-private.h
index ad2e76e9d..a6e4ea943 100644
--- a/src/cairo-svg-surface-private.h
+++ b/src/cairo-svg-surface-private.h
@@ -41,6 +41,8 @@
 #ifndef CAIRO_SVG_SURFACE_PRIVATE_H
 #define CAIRO_SVG_SURFACE_PRIVATE_H
 
+#include <cairo.h>
+
 void
 _cairo_svg_surface_set_force_fallbacks (void *abstract_surface,
 					cairo_bool_t force_fallbacks);
commit 5932084df3b9edd4472682f728a57bdb0b511950
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Mon Apr 12 00:00:45 2021 +0200

    Remove _cairo_memory_stream_to_string

diff --git a/src/cairo-output-stream-private.h b/src/cairo-output-stream-private.h
index 91657c3c6..2542646b8 100644
--- a/src/cairo-output-stream-private.h
+++ b/src/cairo-output-stream-private.h
@@ -177,9 +177,6 @@ _cairo_memory_stream_copy (cairo_output_stream_t *base,
 cairo_private int
 _cairo_memory_stream_length (cairo_output_stream_t *stream);
 
-cairo_private char *
-_cairo_memory_stream_to_string (cairo_output_stream_t *stream);
-
 cairo_private cairo_status_t
 _cairo_memory_stream_destroy (cairo_output_stream_t *abstract_stream,
 			      unsigned char **data_out,
diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c
index f00419ecd..935fa44c3 100644
--- a/src/cairo-output-stream.c
+++ b/src/cairo-output-stream.c
@@ -787,16 +787,6 @@ _cairo_memory_stream_length (cairo_output_stream_t *base)
     return _cairo_array_num_elements (&stream->array);
 }
 
-char *
-_cairo_memory_stream_to_string (cairo_output_stream_t *base)
-{
-    memory_stream_t *stream = (memory_stream_t *) base;
-
-    char zero = 0;
-    _cairo_array_append(&stream->array, &zero);
-    return _cairo_array_index (&stream->array, 0);
-}
-
 static cairo_status_t
 null_write (cairo_output_stream_t *base,
 	    const unsigned char *data, unsigned int length)
commit 917f366ad1d6da84221bb9ee1c3a9892cca98304
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sun Apr 11 23:41:59 2021 +0200

    Add a test for #431

diff --git a/test/Makefile.sources b/test/Makefile.sources
index 466d27cb8..cdcf9e33e 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -26,6 +26,7 @@ test_sources = \
 	bilevel-image.c					\
 	bug-40410.c					\
 	bug-361.c					\
+	bug-431.c					\
 	bug-448.c					\
 	bug-51910.c					\
 	bug-75705.c					\
diff --git a/test/bug-431.c b/test/bug-431.c
new file mode 100644
index 000000000..663fe0c45
--- /dev/null
+++ b/test/bug-431.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright © 2021 Lome More
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "cairo-test.h"
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    cairo_matrix_t test_matrix;
+    test_matrix.xx = 614;
+    test_matrix.yx = 0;
+    test_matrix.xy = 0;
+    test_matrix.yy = -794;
+    test_matrix.x0 = -1.3831;
+    test_matrix.y0 = 793;
+    cairo_set_matrix(cr, &test_matrix);
+
+    const cairo_test_context_t *ctx = cairo_test_get_context (cr);
+    cairo_surface_t *png_surface = cairo_test_create_surface_from_png (ctx, "romedalen.png");
+    cairo_pattern_t *png_pattern = cairo_pattern_create_for_surface(png_surface);
+    cairo_matrix_t matrix;
+    matrix.xx = 1228;
+    matrix.yx = 0;
+    matrix.xy = 0;
+    matrix.yy = -1590;
+    matrix.x0 = 0;
+    matrix.y0 = 1590;
+    cairo_pattern_set_matrix (png_pattern, &matrix);
+    cairo_pattern_t *mask_pattern = cairo_pattern_create_rgba (1.0, 1.0, 1.0, 0.15);
+    cairo_save(cr);
+    cairo_set_source(cr, png_pattern);
+    cairo_mask(cr, mask_pattern);
+    cairo_restore(cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (bug_431,
+	    "Bug 431 (Different result on SVG surface)",
+	    "", /* keywords */
+	    NULL, /* requirements */
+	    128, 96,
+	    NULL, draw)
diff --git a/test/meson.build b/test/meson.build
index c5cca669e..5cd220ce8 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -26,6 +26,7 @@ test_sources = [
   'bilevel-image.c',
   'bug-40410.c',
   'bug-361.c',
+  'bug-431.c',
   'bug-448.c',
   'bug-51910.c',
   'bug-75705.c',
diff --git a/test/reference/bug-431.ref.png b/test/reference/bug-431.ref.png
new file mode 100644
index 000000000..5ebddbb6d
Binary files /dev/null and b/test/reference/bug-431.ref.png differ
diff --git a/test/reference/operator-www.svg11.rgb24.ref.png b/test/reference/operator-www.svg11.rgb24.ref.png
deleted file mode 100644
index 80261ceb3..000000000
Binary files a/test/reference/operator-www.svg11.rgb24.ref.png and /dev/null differ
commit 39dabd34fee8ac07538e6567a105e9773e6c7acd
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sun Apr 11 23:28:41 2021 +0200

    Mark CAIRO_PATTERN_TYPE_MESH as unsupported and impose a limit on recording surfaces depth

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index a54464738..e1d61a015 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -213,6 +213,7 @@ typedef struct _cairo_svg_surface {
     cairo_surface_t base;
 
     unsigned int source_id;
+    unsigned int depth;
 
     cairo_content_t content;
 
@@ -843,6 +844,7 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
 			 TRUE); /* is_vector */
 
     surface->source_id = surface->base.unique_id;
+    surface->depth = 0;
 
     surface->content = content;
 
@@ -1253,8 +1255,16 @@ _cairo_svg_surface_are_operation_and_pattern_supported (cairo_svg_surface_t *sur
         return FALSE;
     }
 
-    if (pattern->type == CAIRO_PATTERN_TYPE_MESH) {
-	return FALSE;
+    if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+        /* Do not cause stack overflow because of too deep or infinite recording surfaces. */
+	if (((cairo_surface_pattern_t *) pattern)->surface->type == CAIRO_SURFACE_TYPE_RECORDING &&
+	    surface->depth > 1000) {
+	    return FALSE;
+	}
+	/* SVG doesn't support extends reflect and pad for surface pattern. */
+        if (pattern->extend != CAIRO_EXTEND_NONE && pattern->extend != CAIRO_EXTEND_REPEAT) {
+	    return FALSE;
+	}
     }
 
     /* SVG 1.1 does not support the focal point (fx, fy) that is outside of the circle defined by (cx, cy) and r. */
@@ -1273,9 +1283,11 @@ _cairo_svg_surface_are_operation_and_pattern_supported (cairo_svg_surface_t *sur
 	}
     }
 
-    /* SVG doesn't support extends reflect and pad for surface pattern */
-    if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE && (pattern->extend != CAIRO_EXTEND_NONE &&
-							pattern->extend != CAIRO_EXTEND_REPEAT)) {
+    if (pattern->type == CAIRO_PATTERN_TYPE_MESH) {
+	return FALSE;
+    }
+
+    if (pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
 	return FALSE;
     }
 
@@ -1837,13 +1849,14 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output
 }
 
 static cairo_status_t
-_cairo_svg_surface_emit_recording_surface (cairo_svg_document_t *document,
+_cairo_svg_surface_emit_recording_surface (cairo_svg_surface_t *surface,
 					   cairo_recording_surface_t *source,
 					   unsigned int source_id,
 					   cairo_bool_t *paint_used,
 					   cairo_bool_t *transitive_paint_used)
 {
     cairo_status_t status;
+    cairo_svg_document_t *document = surface->document;
 
     cairo_surface_t *paginated_surface = _cairo_svg_surface_create_for_document (document,
 										 source->base.content,
@@ -1856,6 +1869,7 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t *document,
     }
 
     svg_surface->source_id = source_id;
+    svg_surface->depth = surface->depth + 1;
 
     cairo_rectangle_int_t extents;
     cairo_bool_t bounded = _cairo_surface_get_extents (&source->base, &extents);
@@ -1990,7 +2004,7 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t *outp
     if (is_new) {
         cairo_bool_t paint_used;
 
-	status = _cairo_svg_surface_emit_recording_surface (document,
+	status = _cairo_svg_surface_emit_recording_surface (surface,
 							    recording_surface,
 							    source_id,
 							    &paint_used,
commit c91afd777a8260931d2c19b9c19679cf3ae6bfe9
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sun Apr 11 22:42:23 2021 +0200

    Do not use parent_matrix in the mask operation

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 2e8f63fae..a54464738 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -2652,8 +2652,7 @@ _cairo_svg_surface_get_extents (void		        *abstract_surface,
 static cairo_status_t
 _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
 			       cairo_svg_surface_t *surface,
-			       const cairo_pattern_t *source,
-			       const cairo_pattern_t *mask_source)
+			       const cairo_pattern_t *source)
 {
     cairo_status_t status;
 
@@ -2662,7 +2661,7 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
 							  surface,
 							  (cairo_surface_pattern_t *) source,
 							  invalid_pattern_id,
-							  mask_source ? &mask_source->matrix : NULL);
+							  NULL);
     }
 
     surface->paint_used = TRUE;
@@ -2803,7 +2802,7 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 										CAIRO_SVG_FILTER_ADD,
 										lerped_source_compositing_group_id,
 										lerped_destination_compositing_group_id));
-	status = _cairo_svg_surface_emit_paint (surface->xml_node, surface, &_cairo_pattern_black.base, NULL);
+	status = _cairo_svg_surface_emit_paint (surface->xml_node, surface, &_cairo_pattern_black.base);
 	if (unlikely (status)) {
 	    return status;
 	}
@@ -2868,7 +2867,7 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 	(void) _cairo_output_stream_destroy (mask_stream);
 	return status;
     }
-    status = _cairo_svg_surface_emit_paint (document->xml_node_defs, surface, &_cairo_pattern_white.base, NULL);
+    status = _cairo_svg_surface_emit_paint (document->xml_node_defs, surface, &_cairo_pattern_white.base);
     if (unlikely (status)) {
 	(void) _cairo_output_stream_destroy (destination_stream);
 	(void) _cairo_output_stream_destroy (source_stream);
@@ -3100,7 +3099,7 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 				 "filter=\"url(#filter-%d)\" mask=\"url(#mask-%d)\">\n",
 				 filter_id,
 				 positive_lerp_mask_id);
-    status = _cairo_svg_surface_emit_paint (document->xml_node_defs, surface, &_cairo_pattern_black.base, NULL);
+    status = _cairo_svg_surface_emit_paint (document->xml_node_defs, surface, &_cairo_pattern_black.base);
     if (unlikely (status)) {
 	return status;
     }
@@ -3122,7 +3121,7 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 									    CAIRO_SVG_FILTER_ADD,
 									    lerped_operation_compositing_group_id,
 									    lerped_destination_compositing_group_id));
-    status = _cairo_svg_surface_emit_paint (surface->xml_node, surface, &_cairo_pattern_black.base, NULL);
+    status = _cairo_svg_surface_emit_paint (surface->xml_node, surface, &_cairo_pattern_black.base);
     if (unlikely (status)) {
 	return status;
     }
@@ -3149,8 +3148,7 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
         cairo_output_stream_t *source_stream = _cairo_memory_stream_create (); \
         status = _cairo_svg_surface_emit_paint (source_stream, \
                                                 surface, \
-                                                SOURCE, \
-                                                NULL); \
+                                                SOURCE); \
         if (unlikely (status)) { \
             (void) _cairo_output_stream_destroy (source_stream); \
             (void) _cairo_output_stream_destroy (mask_stream); \
@@ -3172,7 +3170,7 @@ _cairo_svg_surface_paint_impl (cairo_output_stream_t *output,
 			       cairo_svg_surface_t *surface,
 			       const cairo_pattern_t *source)
 {
-    return _cairo_svg_surface_emit_paint (output, surface, source, NULL);
+    return _cairo_svg_surface_emit_paint (output, surface, source);
 }
 
 static cairo_int_status_t
@@ -3239,7 +3237,7 @@ _cairo_svg_surface_mask_impl (cairo_output_stream_t *output,
     _cairo_output_stream_printf (temporary_stream,
 				 "<g filter=\"url(#filter-%s)\">\n",
 				 _cairo_svg_surface_emit_static_filter (document, CAIRO_SVG_FILTER_REMOVE_COLOR));
-    status = _cairo_svg_surface_emit_paint (temporary_stream, surface, mask, source);
+    status = _cairo_svg_surface_emit_paint (temporary_stream, surface, mask);
     if (unlikely (status)) {
 	(void) _cairo_output_stream_destroy (temporary_stream);
 	return status;
@@ -3258,7 +3256,7 @@ _cairo_svg_surface_mask_impl (cairo_output_stream_t *output,
 				 "<g mask=\"url(#mask-%d)\">\n",
 				 mask_id);
 
-    status = _cairo_svg_surface_emit_paint (output, surface, source, NULL);
+    status = _cairo_svg_surface_emit_paint (output, surface, source);
     if (unlikely (status)) {
 	return status;
     }
commit d44bb67c7ffd0d42a29ecb37de0de4b768131ab8
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sun Apr 11 22:16:27 2021 +0200

    Fix clip-rule being emitted on the wrong elements

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 76e63a01a..2e8f63fae 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -778,16 +778,17 @@ _cairo_svg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper
 				 "<clipPath id=\"clip-%d\">\n",
 				 document->clip_id);
 
-    _cairo_output_stream_printf (document->xml_node_defs, "<path");
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<path clip-rule=\"%s\"",
+				 fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero");
     _cairo_svg_surface_emit_path (document->xml_node_defs, path, NULL);
     _cairo_output_stream_printf (document->xml_node_defs, "/>\n");
 
     _cairo_output_stream_printf (document->xml_node_defs, "</clipPath>\n");
 
     _cairo_output_stream_printf (surface->current_clipper_output_stream,
-				 "<g clip-path=\"url(#clip-%d)\" clip-rule=\"%s\">\n",
-				 document->clip_id,
-				 fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero");
+				 "<g clip-path=\"url(#clip-%d)\">\n",
+				 document->clip_id);
 
     document->clip_id++;
     surface->clip_level++;
@@ -3401,17 +3402,17 @@ _cairo_svg_surface_fill_impl (cairo_output_stream_t *output,
 				     "<clipPath id=\"clip-%d\">\n",
 				     surface->document->clip_id);
 
-	_cairo_output_stream_printf (surface->document->xml_node_defs, "<path");
+	_cairo_output_stream_printf (surface->document->xml_node_defs,
+				     "<path clip-rule=\"%s\"",
+				     fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero");
 	_cairo_svg_surface_emit_path (surface->document->xml_node_defs, path, NULL);
 	_cairo_output_stream_printf (surface->document->xml_node_defs, "/>\n");
 
 	_cairo_output_stream_printf (surface->document->xml_node_defs, "</clipPath>\n");
 
 	_cairo_output_stream_printf (output,
-				     "<g clip-path=\"url(#clip-%d)\" "
-				     "clip-rule=\"%s\">\n",
-				     surface->document->clip_id++,
-				     fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero");
+				     "<g clip-path=\"url(#clip-%d)\">\n",
+				     surface->document->clip_id++);
 
 	status = _cairo_svg_surface_emit_composite_pattern (output,
 							    surface,
commit 580e9b9be6f53fb63082a6c2e97f74219a4c9e54
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sun Apr 11 21:50:45 2021 +0200

    Add my name to the header of cairo-svg-surface.c

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index e4ae77534..76e63a01a 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -4,6 +4,7 @@
  * Copyright © 2004 Red Hat, Inc
  * Copyright © 2005-2007 Emmanuel Pacaud <emmanuel.pacaud at free.fr>
  * Copyright © 2006 Red Hat, Inc
+ * Copyright © 2020-2021 Anton Danilkin <afdw at yandex.ru>
  *
  * This library is free software; you can redistribute it and/or
  * modify it either under the terms of the GNU Lesser General Public
@@ -37,6 +38,7 @@
  *	Kristian Høgsberg <krh at redhat.com>
  *	Emmanuel Pacaud <emmanuel.pacaud at free.fr>
  *	Carl Worth <cworth at cworth.org>
+ *	Anton Danilkin <afdw at yandex.ru>
  */
 
 #include "cairoint.h"
commit 500b39e98fa17aaf89a805aa4ce73c5f334f6bd9
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sun Apr 11 21:49:47 2021 +0200

    Move cairo_svg_surface_t to cairo-svg-surface.c

diff --git a/boilerplate/cairo-boilerplate-svg.c b/boilerplate/cairo-boilerplate-svg.c
index bf9921d5a..2787e8567 100644
--- a/boilerplate/cairo-boilerplate-svg.c
+++ b/boilerplate/cairo-boilerplate-svg.c
@@ -264,15 +264,11 @@ _cairo_boilerplate_svg_force_fallbacks (cairo_surface_t *abstract_surface,
     svg_target_closure_t *ptc = cairo_surface_get_user_data (abstract_surface,
 							     &svg_closure_key);
 
-    cairo_paginated_surface_t *paginated;
-    cairo_svg_surface_t *surface;
-
     if (ptc->target)
 	abstract_surface = ptc->target;
 
-    paginated = (cairo_paginated_surface_t*) abstract_surface;
-    surface = (cairo_svg_surface_t*) paginated->target;
-    surface->force_fallbacks = TRUE;
+    cairo_paginated_surface_t *paginated = (cairo_paginated_surface_t*) abstract_surface;
+    _cairo_svg_surface_set_force_fallbacks (paginated->target, TRUE);
     cairo_surface_set_fallback_resolution (&paginated->base,
 					   x_pixels_per_inch,
 					   y_pixels_per_inch);
diff --git a/src/cairo-svg-surface-private.h b/src/cairo-svg-surface-private.h
index 32f032729..ad2e76e9d 100644
--- a/src/cairo-svg-surface-private.h
+++ b/src/cairo-svg-surface-private.h
@@ -41,41 +41,8 @@
 #ifndef CAIRO_SVG_SURFACE_PRIVATE_H
 #define CAIRO_SVG_SURFACE_PRIVATE_H
 
-#include "cairo-svg.h"
-
-#include "cairo-surface-private.h"
-#include "cairo-surface-clipper-private.h"
-
-typedef struct cairo_svg_document cairo_svg_document_t;
-
-typedef struct cairo_svg_surface {
-    cairo_surface_t base;
-
-    unsigned int source_id;
-
-    cairo_content_t content;
-
-    double width;
-    double height;
-    cairo_bool_t surface_bounded;
-
-    cairo_svg_document_t *document;
-
-    cairo_output_stream_t *xml_node;
-    cairo_array_t page_set;
-
-    cairo_hash_table_t *source_surfaces;
-
-    cairo_surface_clipper_t clipper;
-    cairo_output_stream_t *current_clipper_output_stream;
-    unsigned int clip_level;
-
-    cairo_bool_t paint_used;
-    cairo_bool_t transitive_paint_used;
-
-    cairo_paginated_mode_t paginated_mode;
-
-    cairo_bool_t force_fallbacks;
-} cairo_svg_surface_t;
+void
+_cairo_svg_surface_set_force_fallbacks (void *abstract_surface,
+					cairo_bool_t force_fallbacks);
 
 #endif /* CAIRO_SVG_SURFACE_PRIVATE_H */
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index c6eeb88d5..e4ae77534 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -172,11 +172,11 @@ typedef struct _cairo_svg_paint {
     cairo_box_double_t box;
 } cairo_svg_paint_t;
 
-typedef struct cairo_svg_page {
+typedef struct _cairo_svg_page {
     cairo_output_stream_t *xml_node;
 } cairo_svg_page_t;
 
-struct cairo_svg_document {
+typedef struct _cairo_svg_document {
     cairo_output_stream_t *output_stream;
     unsigned long refcount;
     cairo_surface_t *owner;
@@ -205,7 +205,37 @@ struct cairo_svg_document {
     cairo_scaled_font_subsets_t *font_subsets;
 
     cairo_hash_table_t *paints;
-};
+} cairo_svg_document_t;
+
+typedef struct _cairo_svg_surface {
+    cairo_surface_t base;
+
+    unsigned int source_id;
+
+    cairo_content_t content;
+
+    double width;
+    double height;
+    cairo_bool_t surface_bounded;
+
+    cairo_svg_document_t *document;
+
+    cairo_output_stream_t *xml_node;
+    cairo_array_t page_set;
+
+    cairo_hash_table_t *source_surfaces;
+
+    cairo_surface_clipper_t clipper;
+    cairo_output_stream_t *current_clipper_output_stream;
+    unsigned int clip_level;
+
+    cairo_bool_t paint_used;
+    cairo_bool_t transitive_paint_used;
+
+    cairo_paginated_mode_t paginated_mode;
+
+    cairo_bool_t force_fallbacks;
+} cairo_svg_surface_t;
 
 static cairo_status_t
 _cairo_svg_document_create (cairo_output_stream_t	 *stream,
@@ -379,6 +409,15 @@ _extract_svg_surface (cairo_surface_t *surface,
     return TRUE;
 }
 
+void
+_cairo_svg_surface_set_force_fallbacks (void *abstract_surface,
+					cairo_bool_t force_fallbacks)
+{
+    cairo_svg_surface_t *surface = (cairo_svg_surface_t *) abstract_surface;
+
+    surface->force_fallbacks = force_fallbacks;
+}
+
 /**
  * cairo_svg_surface_restrict_to_version:
  * @surface: a SVG #cairo_surface_t
@@ -3923,5 +3962,4 @@ static const cairo_paginated_surface_backend_t cairo_svg_surface_paginated_backe
     NULL, /* _cairo_svg_surface_set_bounding_box */
     NULL, /* _cairo_svg_surface_set_fallback_images_required */
     _cairo_svg_surface_supports_fine_grained_fallbacks,
-
 };
commit ceae137ba6930c0415b64918e74750d1cfd162cb
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sun Apr 11 21:32:49 2021 +0200

    Finish implementing correct paints in transformed recording patterns

diff --git a/src/cairo-svg-surface-private.h b/src/cairo-svg-surface-private.h
index b30948f33..32f032729 100644
--- a/src/cairo-svg-surface-private.h
+++ b/src/cairo-svg-surface-private.h
@@ -71,6 +71,7 @@ typedef struct cairo_svg_surface {
     unsigned int clip_level;
 
     cairo_bool_t paint_used;
+    cairo_bool_t transitive_paint_used;
 
     cairo_paginated_mode_t paginated_mode;
 
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index bc0b06a9f..c6eeb88d5 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -152,13 +152,24 @@ typedef struct _cairo_svg_source_surface {
     unsigned int id;
     unsigned char *unique_id;
     unsigned long unique_id_length;
-    cairo_bool_t paint_used;
+    cairo_bool_t transitive_paint_used;
 } cairo_svg_source_surface_t;
 
+/*
+ * _cairo_svg_paint_element and _cairo_svg_paint are used to implement paints in transformed recording patterns.
+ */
+
+typedef struct _cairo_svg_paint_element {
+    unsigned int source_id;
+    cairo_matrix_t matrix;
+} cairo_svg_paint_element_t;
+
 typedef struct _cairo_svg_paint {
     cairo_hash_entry_t base;
     unsigned int source_id;
-    cairo_output_stream_t *xml_node;
+    cairo_bool_t paint_used;
+    cairo_array_t paint_elements;
+    cairo_box_double_t box;
 } cairo_svg_paint_t;
 
 typedef struct cairo_svg_page {
@@ -559,21 +570,65 @@ _cairo_svg_paint_pluck (void *entry, void *closure)
     cairo_hash_table_t *patterns = closure;
 
     _cairo_hash_table_remove (patterns, &paint->base);
-    (void) _cairo_output_stream_destroy (paint->xml_node);
+    _cairo_array_fini (&paint->paint_elements);
     free (paint);
 }
 
 static void
-_cairo_svg_paint_emit (void *entry, void *closure)
+_cairo_svg_paint_compute (cairo_svg_document_t *document, cairo_svg_paint_t *paint) {
+    for (unsigned int i = 0; i < paint->paint_elements.num_elements; i++) {
+	cairo_svg_paint_element_t *paint_element = _cairo_array_index (&paint->paint_elements, i);
+
+	cairo_svg_paint_t paint_key;
+	paint_key.source_id = paint_element->source_id;
+	_cairo_svg_paint_init_key (&paint_key);
+
+	cairo_svg_paint_t *found_paint_entry = _cairo_hash_table_lookup (document->paints,
+									 &paint_key.base);
+	assert (found_paint_entry);
+
+	_cairo_svg_paint_compute (document, found_paint_entry);
+
+	cairo_box_double_t box = found_paint_entry->box;
+	_cairo_matrix_transform_bounding_box (&paint_element->matrix,
+					      &box.p1.x, &box.p1.y,
+					      &box.p2.x, &box.p2.y,
+					      NULL);
+
+	if (i == 0) {
+	    paint->box = box;
+	} else {
+	    paint->box.p1.x = MIN (paint->box.p1.x, box.p1.x);
+	    paint->box.p1.y = MIN (paint->box.p1.y, box.p1.y);
+	    paint->box.p2.x = MAX (paint->box.p2.x, box.p2.x);
+	    paint->box.p2.y = MAX (paint->box.p2.y, box.p2.y);
+	}
+    }
+    _cairo_array_truncate (&paint->paint_elements, 0);
+}
+
+static void
+_cairo_svg_paint_compute_func (void *entry, void *closure)
+{
+    cairo_svg_paint_t *paint = entry;
+    cairo_svg_document_t *document = closure;
+
+    _cairo_svg_paint_compute (document, paint);
+}
+
+static void
+_cairo_svg_paint_emit_func (void *entry, void *closure)
 {
     cairo_svg_paint_t *paint = entry;
     cairo_output_stream_t *output = closure;
 
-    _cairo_output_stream_printf (output,
-				 "<g id=\"paint-%d\">\n",
-				 paint->source_id);
-    _cairo_memory_stream_copy (paint->xml_node, output);
-    _cairo_output_stream_printf (output, "</g>\n");
+    if (paint->paint_used) {
+	_cairo_output_stream_printf (output,
+				     "<rect id=\"paint-%d\" x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\"/>\n",
+				     paint->source_id,
+				     paint->box.p1.x, paint->box.p1.y,
+				     paint->box.p2.x - paint->box.p1.x, paint->box.p2.y - paint->box.p1.y);
+    }
 }
 
 static cairo_status_t
@@ -768,6 +823,7 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
     surface->current_clipper_output_stream = NULL;
     surface->clip_level = 0;
     surface->paint_used = FALSE;
+    surface->transitive_paint_used = FALSE;
 
     surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
 
@@ -1285,31 +1341,31 @@ _cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cair
 
 #define _CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER(operation) \
     _cairo_output_stream_printf (document->xml_node_filters, \
-				 "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" " \
-				 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n" \
-				 "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"/>\n" \
-				 "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"/>\n" \
-				 "<feComposite in=\"source\" in2=\"destination\" " \
-				 "operator=\"" operation "\" " \
-				 "color-interpolation-filters=\"sRGB\"/>\n" \
-				 "</filter>\n", \
-				 filter_id, \
-				 source_compositing_group_id, \
-				 destination_compositing_group_id)
+                                 "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" " \
+                                 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n" \
+                                 "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"/>\n" \
+                                 "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"/>\n" \
+                                 "<feComposite in=\"source\" in2=\"destination\" " \
+                                 "operator=\"" operation "\" " \
+                                 "color-interpolation-filters=\"sRGB\"/>\n" \
+                                 "</filter>\n", \
+                                 filter_id, \
+                                 source_compositing_group_id, \
+                                 destination_compositing_group_id)
 
 #define _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER(mode) \
     _cairo_output_stream_printf (document->xml_node_filters, \
-				 "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" " \
-				 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n" \
-				 "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"/>\n" \
-				 "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"/>\n" \
-				 "<feBlend in=\"source\" in2=\"destination\" " \
-				 "mode=\"" mode "\" " \
-				 "color-interpolation-filters=\"sRGB\"/>\n" \
-				 "</filter>\n", \
-				 filter_id, \
-				 source_compositing_group_id, \
-				 destination_compositing_group_id)
+                                 "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" " \
+                                 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n" \
+                                 "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"/>\n" \
+                                 "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"/>\n" \
+                                 "<feBlend in=\"source\" in2=\"destination\" " \
+                                 "mode=\"" mode "\" " \
+                                 "color-interpolation-filters=\"sRGB\"/>\n" \
+                                 "</filter>\n", \
+                                 filter_id, \
+                                 source_compositing_group_id, \
+                                 destination_compositing_group_id)
 
 static unsigned int
 _cairo_svg_surface_emit_parametric_filter (cairo_svg_document_t *document,
@@ -1335,7 +1391,7 @@ _cairo_svg_surface_emit_parametric_filter (cairo_svg_document_t *document,
 	_CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("xor");
 	break;
     case CAIRO_SVG_FILTER_ADD:
-        // This can also be done with <feComposite operator="lighter"/>, but it is not from SVG 1.1
+	// This can also be done with <feComposite operator="lighter"/>, but it is not from SVG 1.1
 	_cairo_output_stream_printf (document->xml_node_filters,
 				     "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" "
 				     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
@@ -1395,7 +1451,7 @@ _cairo_svg_surface_emit_parametric_filter (cairo_svg_document_t *document,
 	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("luminosity");
 	break;
     default:
-        printf("%d\n", filter);
+	printf ("%d\n", filter);
 	ASSERT_NOT_REACHED;
     }
     return filter_id;
@@ -1742,7 +1798,8 @@ static cairo_status_t
 _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t *document,
 					   cairo_recording_surface_t *source,
 					   unsigned int source_id,
-					   cairo_bool_t *paint_used)
+					   cairo_bool_t *paint_used,
+					   cairo_bool_t *transitive_paint_used)
 {
     cairo_status_t status;
 
@@ -1827,6 +1884,7 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t *document,
     _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
 
     *paint_used = svg_surface->paint_used;
+    *transitive_paint_used = svg_surface->transitive_paint_used;
 
     status = cairo_surface_status (paginated_surface);
     cairo_surface_destroy (paginated_surface);
@@ -1846,7 +1904,8 @@ _cairo_svg_surface_to_recording_surface (const cairo_surface_pattern_t *pattern)
 }
 
 static cairo_bool_t
-_cairo_svg_surface_svg_pattern_should_be_used (const cairo_pattern_t *pattern) {
+_cairo_svg_surface_svg_pattern_should_be_used (const cairo_pattern_t *pattern)
+{
     cairo_rectangle_int_t extents;
     return pattern->type == CAIRO_PATTERN_TYPE_SURFACE &&
 	   pattern->extend == CAIRO_EXTEND_REPEAT &&
@@ -1854,7 +1913,8 @@ _cairo_svg_surface_svg_pattern_should_be_used (const cairo_pattern_t *pattern) {
 }
 
 static cairo_bool_t
-_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (const cairo_pattern_t *pattern) {
+_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (const cairo_pattern_t *pattern)
+{
     return pattern->type == CAIRO_PATTERN_TYPE_SURFACE && !_cairo_svg_surface_svg_pattern_should_be_used (pattern);
 }
 
@@ -1886,30 +1946,34 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t *outp
 
     cairo_recording_surface_t *recording_surface = _cairo_svg_surface_to_recording_surface (pattern);
     if (is_new) {
+        cairo_bool_t paint_used;
+
 	status = _cairo_svg_surface_emit_recording_surface (document,
 							    recording_surface,
 							    source_id,
-							    &source_surface->paint_used);
+							    &paint_used,
+							    &source_surface->transitive_paint_used);
 	if (unlikely (status)) {
 	    return status;
 	}
-    }
 
-    if (is_new && source_surface->paint_used) {
-	cairo_svg_paint_t *paint_entry = malloc (sizeof (cairo_svg_paint_t));
-	if (paint_entry == NULL) {
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	}
-	paint_entry->source_id = source_id;
-	paint_entry->xml_node = _cairo_memory_stream_create();
-	_cairo_svg_paint_init_key (paint_entry);
-	status = _cairo_hash_table_insert (document->paints, &paint_entry->base);
-	if (unlikely (status)) {
-	    return status;
+	if (source_surface->transitive_paint_used) {
+	    cairo_svg_paint_t *paint_entry = malloc (sizeof (cairo_svg_paint_t));
+	    if (paint_entry == NULL) {
+		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    }
+	    paint_entry->source_id = source_id;
+	    paint_entry->paint_used = paint_used;
+	    _cairo_array_init (&paint_entry->paint_elements, sizeof (cairo_svg_paint_element_t));
+	    _cairo_svg_paint_init_key (paint_entry);
+	    status = _cairo_hash_table_insert (document->paints, &paint_entry->base);
+	    if (unlikely (status)) {
+		return status;
+	    }
 	}
     }
 
-    if (source_surface->paint_used) {
+    if (source_surface->transitive_paint_used) {
 	cairo_svg_paint_t paint_key;
 	paint_key.source_id = source_id;
 	_cairo_svg_paint_init_key (&paint_key);
@@ -1918,25 +1982,26 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t *outp
 									 &paint_key.base);
 	assert (found_paint_entry);
 
-	_cairo_output_stream_printf (found_paint_entry->xml_node,
-				     "<use xlink:href=\"#paint-%d\"",
-				     surface->source_id);
-	cairo_matrix_t matrix = pattern->base.matrix;
+	cairo_svg_paint_element_t paint_element;
+	paint_element.source_id = surface->source_id;
+	paint_element.matrix = pattern->base.matrix;
 	if (parent_matrix != NULL) {
 	    cairo_matrix_t parent_matrix_inverse = *parent_matrix;
 	    status = cairo_matrix_invert (&parent_matrix_inverse);
 	    /* cairo_pattern_set_matrix ensures the matrix is invertible */
 	    assert (status == CAIRO_STATUS_SUCCESS);
-	    cairo_matrix_multiply (&matrix, &parent_matrix_inverse, &matrix);
+	    cairo_matrix_multiply (&paint_element.matrix, &parent_matrix_inverse, &paint_element.matrix);
+	}
+	status = _cairo_array_append (&found_paint_entry->paint_elements, &paint_element);
+	if (unlikely (status)) {
+	    return status;
 	}
-	_cairo_svg_surface_emit_transform (found_paint_entry->xml_node, "transform", &matrix, NULL);
-	_cairo_output_stream_printf (found_paint_entry->xml_node, "/>\n");
 
-        surface->paint_used = TRUE;
+	surface->transitive_paint_used = TRUE;
     }
 
     if (pattern_id != invalid_pattern_id) {
-        assert (!recording_surface->unbounded);
+	assert (!recording_surface->unbounded);
 	_cairo_output_stream_printf (output,
 				     "<pattern id=\"pattern-%d\" "
 				     "patternUnits=\"userSpaceOnUse\" "
@@ -2559,6 +2624,8 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
     }
 
     surface->paint_used = TRUE;
+    surface->transitive_paint_used = TRUE;
+
     _cairo_output_stream_printf (output,
 				 "<use xlink:href=\"#paint-%d\"",
 				 surface->source_id);
@@ -2584,10 +2651,10 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
     cairo_svg_document_t *document = surface->document;
 
     if (op == CAIRO_OPERATOR_CLEAR) {
-        /*
-         * The result is the same as one of the SOURCE operation application with the same arguments,
-         * but with an empty source.
-         */
+	/*
+	 * The result is the same as one of the SOURCE operation application with the same arguments,
+	 * but with an empty source.
+	 */
 
 	status = _cairo_output_stream_destroy (source_stream);
 	if (unlikely (status)) {
@@ -2704,9 +2771,9 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
     }
 
     if (op == CAIRO_OPERATOR_DEST) {
-        /*
-         * The result is the destination.
-         */
+	/*
+	 * The result is the destination.
+	 */
 
 	_cairo_memory_stream_copy (destination_stream, surface->xml_node);
 	status = _cairo_output_stream_destroy (destination_stream);
@@ -3750,13 +3817,33 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
 		final_status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	    }
 	}
+
+	if (surface->transitive_paint_used) {
+	    cairo_svg_paint_t *paint_entry = malloc (sizeof (cairo_svg_paint_t));
+	    if (paint_entry == NULL) {
+		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    }
+	    paint_entry->source_id = surface->source_id;
+	    paint_entry->paint_used = surface->paint_used;
+	    paint_entry->box.p1.x = 0;
+	    paint_entry->box.p1.y = 0;
+	    paint_entry->box.p2.x = document->width;
+	    paint_entry->box.p2.y = document->height;
+	    _cairo_array_init (&paint_entry->paint_elements, sizeof (cairo_svg_paint_element_t));
+	    _cairo_svg_paint_init_key (paint_entry);
+	    status = _cairo_hash_table_insert (document->paints, &paint_entry->base);
+	    if (unlikely (status)) {
+		return status;
+	    }
+	}
     }
 
+    _cairo_hash_table_foreach (document->paints, _cairo_svg_paint_compute_func, document);
+
     if (_cairo_memory_stream_length (document->xml_node_filters) > 0 ||
 	_cairo_memory_stream_length (document->xml_node_glyphs) > 0 ||
 	_cairo_memory_stream_length (document->xml_node_defs) > 0 ||
-	_cairo_hash_table_size (document->paints) != 0 ||
-	(surface != NULL && surface->paint_used)) {
+	_cairo_hash_table_size (document->paints) != 0) {
 	_cairo_output_stream_printf (output, "<defs>\n");
 	_cairo_memory_stream_copy (document->xml_node_filters, output);
 	if (_cairo_memory_stream_length (document->xml_node_glyphs) > 0) {
@@ -3765,13 +3852,7 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
 	    _cairo_output_stream_printf (output, "</g>\n");
 	}
 	_cairo_memory_stream_copy (document->xml_node_defs, output);
-	_cairo_hash_table_foreach (document->paints, _cairo_svg_paint_emit, output);
-	if (surface != NULL && surface->paint_used) {
-	    _cairo_output_stream_printf (output,
-					 "<rect id=\"paint-%d\" x=\"0\" y=\"0\" width=\"%f\" height=\"%f\"/>\n",
-					 surface->source_id,
-					 document->width, document->height);
-	}
+	_cairo_hash_table_foreach (document->paints, _cairo_svg_paint_emit_func, output);
 	_cairo_output_stream_printf (output, "</defs>\n");
     }
 
diff --git a/test/Makefile.sources b/test/Makefile.sources
index bb999169b..466d27cb8 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -281,6 +281,7 @@ test_sources = \
 	record-neg-extents.c                            \
 	record-mesh.c					\
 	record-replay-extend.c                          \
+	record-transform-paint.c                          \
 	recording-ink-extents.c                         \
 	recording-surface-pattern.c			\
 	recording-surface-extend.c			\
diff --git a/test/meson.build b/test/meson.build
index cc5160876..c5cca669e 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -281,6 +281,7 @@ test_sources = [
   'record-neg-extents.c',
   'record-mesh.c',
   'record-replay-extend.c',
+  'record-transform-paint.c',
   'recording-ink-extents.c',
   'recording-surface-pattern.c',
   'recording-surface-extend.c',
diff --git a/test/record-transform-paint.c b/test/record-transform-paint.c
new file mode 100644
index 000000000..0ccc2277f
--- /dev/null
+++ b/test/record-transform-paint.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright © 2021 Anton Danilkin
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "cairo-test.h"
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    cairo_surface_t *surface2 = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL);
+    {
+	cairo_t *cr2 = cairo_create (surface2);
+	cairo_surface_t *surface3 = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL);
+	{
+	    cairo_t *cr3 = cairo_create (surface3);
+	    cairo_pattern_t *pattern4 = cairo_pattern_create_linear (0.0, 0.0, width, height);
+	    cairo_pattern_add_color_stop_rgb (pattern4, 0, 0, 1, 0);
+	    cairo_pattern_add_color_stop_rgb (pattern4, 1, 0, 0, 1);
+	    cairo_set_source (cr3, pattern4);
+	    cairo_paint (cr3);
+	}
+	cairo_pattern_t *pattern3 = cairo_pattern_create_for_surface (surface3);
+	cairo_matrix_t matrix3;
+	cairo_matrix_init_scale (&matrix3, 2, 2);
+	cairo_pattern_set_matrix (pattern3, &matrix3);
+	cairo_set_source (cr2, pattern3);
+	cairo_paint (cr2);
+    }
+    cairo_pattern_t *pattern2 = cairo_pattern_create_for_surface (surface2);
+    cairo_matrix_t matrix2;
+    cairo_matrix_init_scale (&matrix2, 5, 5);
+    cairo_pattern_set_matrix (pattern2, &matrix2);
+    cairo_set_source (cr, pattern2);
+    cairo_paint (cr);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (record_transform_paint,
+	    "Tests paint in nested transformed recording patterns",
+	    "record, paint", /* keywords */
+	    NULL, /* requirements */
+	    512, 512,
+	    NULL, draw)
diff --git a/test/reference/record-transform-paint.ref.png b/test/reference/record-transform-paint.ref.png
new file mode 100644
index 000000000..051db262e
Binary files /dev/null and b/test/reference/record-transform-paint.ref.png differ
commit c5b24a3e12815fce328997a9b5825d732329cc4b
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sun Apr 11 19:48:50 2021 +0200

    Start implementing correct paints in transformed recording patterns

diff --git a/src/cairo-hash-private.h b/src/cairo-hash-private.h
index 30e51ffe6..b30126b20 100644
--- a/src/cairo-hash-private.h
+++ b/src/cairo-hash-private.h
@@ -84,4 +84,7 @@ _cairo_hash_table_foreach (cairo_hash_table_t	      *hash_table,
 			   cairo_hash_callback_func_t  hash_callback,
 			   void			      *closure);
 
+cairo_private unsigned long
+_cairo_hash_table_size (cairo_hash_table_t *hash_table);
+
 #endif
diff --git a/src/cairo-hash.c b/src/cairo-hash.c
index 151842eb6..564ca0732 100644
--- a/src/cairo-hash.c
+++ b/src/cairo-hash.c
@@ -576,3 +576,24 @@ _cairo_hash_table_foreach (cairo_hash_table_t	      *hash_table,
 	_cairo_hash_table_manage (hash_table);
     }
 }
+
+/**
+ * _cairo_hash_table_size:
+ * @hash_table: a hash table
+ *
+ * Gets the size of the hash table.
+ *
+ * Return value: the size of the hash table.
+ **/
+unsigned long
+_cairo_hash_table_size (cairo_hash_table_t *hash_table)
+{
+    unsigned long size = 0;
+    for (unsigned long i = 0; i < *hash_table->table_size; i++) {
+	cairo_hash_entry_t *entry = hash_table->entries[i];
+	if (ENTRY_IS_LIVE(entry)) {
+	    size++;
+	}
+    }
+    return size;
+}
diff --git a/src/cairo-svg-surface-private.h b/src/cairo-svg-surface-private.h
index f64814fe2..b30948f33 100644
--- a/src/cairo-svg-surface-private.h
+++ b/src/cairo-svg-surface-private.h
@@ -48,16 +48,11 @@
 
 typedef struct cairo_svg_document cairo_svg_document_t;
 
-typedef struct _cairo_svg_source_surface {
-    cairo_hash_entry_t base;
-    unsigned int id;
-    unsigned char *unique_id;
-    unsigned long unique_id_length;
-} cairo_svg_source_surface_t;
-
 typedef struct cairo_svg_surface {
     cairo_surface_t base;
 
+    unsigned int source_id;
+
     cairo_content_t content;
 
     double width;
@@ -67,13 +62,16 @@ typedef struct cairo_svg_surface {
     cairo_svg_document_t *document;
 
     cairo_output_stream_t *xml_node;
-    cairo_array_t	   page_set;
-    cairo_hash_table_t    *source_surfaces;
+    cairo_array_t page_set;
+
+    cairo_hash_table_t *source_surfaces;
 
     cairo_surface_clipper_t clipper;
     cairo_output_stream_t *current_clipper_output_stream;
     unsigned int clip_level;
 
+    cairo_bool_t paint_used;
+
     cairo_paginated_mode_t paginated_mode;
 
     cairo_bool_t force_fallbacks;
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index a10c47792..bc0b06a9f 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -75,8 +75,6 @@
  * Since: 1.2
  **/
 
-typedef struct cairo_svg_page cairo_svg_page_t;
-
 static const int invalid_pattern_id = -1;
 
 static const cairo_svg_version_t _cairo_svg_versions[] =
@@ -149,9 +147,23 @@ enum cairo_svg_filter {
     CAIRO_SVG_FILTER_LUMINOSITY,
 };
 
-struct cairo_svg_page {
+typedef struct _cairo_svg_source_surface {
+    cairo_hash_entry_t base;
+    unsigned int id;
+    unsigned char *unique_id;
+    unsigned long unique_id_length;
+    cairo_bool_t paint_used;
+} cairo_svg_source_surface_t;
+
+typedef struct _cairo_svg_paint {
+    cairo_hash_entry_t base;
+    unsigned int source_id;
     cairo_output_stream_t *xml_node;
-};
+} cairo_svg_paint_t;
+
+typedef struct cairo_svg_page {
+    cairo_output_stream_t *xml_node;
+} cairo_svg_page_t;
 
 struct cairo_svg_document {
     cairo_output_stream_t *output_stream;
@@ -180,6 +192,8 @@ struct cairo_svg_document {
     cairo_svg_version_t svg_version;
 
     cairo_scaled_font_subsets_t *font_subsets;
+
+    cairo_hash_table_t *paints;
 };
 
 static cairo_status_t
@@ -488,13 +502,14 @@ cairo_svg_surface_get_document_unit (cairo_surface_t	*abstract_surface)
 }
 
 static void
-_cairo_svg_source_surface_init_key (cairo_svg_source_surface_t *key)
+_cairo_svg_source_surface_init_key (cairo_svg_source_surface_t *source_surface)
 {
-    if (key->unique_id && key->unique_id_length > 0) {
-	key->base.hash = _cairo_hash_bytes (_CAIRO_HASH_INIT_VALUE,
-					    key->unique_id, key->unique_id_length);
+    if (source_surface->unique_id && source_surface->unique_id_length > 0) {
+	source_surface->base.hash = _cairo_hash_bytes (_CAIRO_HASH_INIT_VALUE,
+						       source_surface->unique_id,
+						       source_surface->unique_id_length);
     } else {
-	key->base.hash = key->id;
+	source_surface->base.hash = source_surface->id;
     }
 }
 
@@ -504,82 +519,123 @@ _cairo_svg_source_surface_equal (const void *key_a, const void *key_b)
     const cairo_svg_source_surface_t *a = key_a;
     const cairo_svg_source_surface_t *b = key_b;
 
-    if (a->unique_id && b->unique_id && a->unique_id_length == b->unique_id_length)
-	return (memcmp (a->unique_id, b->unique_id, a->unique_id_length) == 0);
+    if (a->unique_id && b->unique_id && a->unique_id_length == b->unique_id_length) {
+	return memcmp (a->unique_id, b->unique_id, a->unique_id_length) == 0;
+    }
 
-    return (a->id == b->id);
+    return a->id == b->id;
 }
 
 static void
 _cairo_svg_source_surface_pluck (void *entry, void *closure)
 {
-    cairo_svg_source_surface_t *surface_entry = entry;
+    cairo_svg_source_surface_t *source_surface = entry;
     cairo_hash_table_t *patterns = closure;
 
-    _cairo_hash_table_remove (patterns, &surface_entry->base);
-    free (surface_entry->unique_id);
-    free (surface_entry);
+    _cairo_hash_table_remove (patterns, &source_surface->base);
+    free (source_surface->unique_id);
+    free (source_surface);
+}
+
+static void
+_cairo_svg_paint_init_key (cairo_svg_paint_t *paint)
+{
+    paint->base.hash = paint->source_id;
+}
+
+static cairo_bool_t
+_cairo_svg_paint_equal (const void *key_a, const void *key_b)
+{
+    const cairo_svg_paint_t *a = key_a;
+    const cairo_svg_paint_t *b = key_b;
+
+    return a->source_id == b->source_id;
+}
+
+static void
+_cairo_svg_paint_pluck (void *entry, void *closure)
+{
+    cairo_svg_paint_t *paint = entry;
+    cairo_hash_table_t *patterns = closure;
+
+    _cairo_hash_table_remove (patterns, &paint->base);
+    (void) _cairo_output_stream_destroy (paint->xml_node);
+    free (paint);
+}
+
+static void
+_cairo_svg_paint_emit (void *entry, void *closure)
+{
+    cairo_svg_paint_t *paint = entry;
+    cairo_output_stream_t *output = closure;
+
+    _cairo_output_stream_printf (output,
+				 "<g id=\"paint-%d\">\n",
+				 paint->source_id);
+    _cairo_memory_stream_copy (paint->xml_node, output);
+    _cairo_output_stream_printf (output, "</g>\n");
 }
 
 static cairo_status_t
-_cairo_svg_surface_add_source_surface (cairo_svg_surface_t  *surface,
-				       cairo_surface_t	    *source_surface,
-				       unsigned int         *source_id,
-				       cairo_bool_t         *is_new)
+_cairo_svg_surface_add_source_surface (cairo_svg_surface_t *surface,
+				       cairo_surface_t *source_surface,
+				       cairo_bool_t *is_new,
+				       cairo_svg_source_surface_t **result_source_surface)
 {
-    cairo_svg_source_surface_t source_key;
-    cairo_svg_source_surface_t *source_entry;
-    unsigned char *unique_id = NULL;
-    unsigned long unique_id_length = 0;
     cairo_status_t status;
 
-    source_key.id  = source_surface->unique_id;
-    cairo_surface_get_mime_data (source_surface, CAIRO_MIME_TYPE_UNIQUE_ID,
-				 (const unsigned char **) &source_key.unique_id,
-				 &source_key.unique_id_length);
-    _cairo_svg_source_surface_init_key (&source_key);
-    source_entry = _cairo_hash_table_lookup (surface->source_surfaces, &source_key.base);
-    if (source_entry) {
-	*source_id = source_entry->id;
+    cairo_svg_source_surface_t source_surface_key;
+    source_surface_key.id = source_surface->unique_id;
+    cairo_surface_get_mime_data (source_surface,
+				 CAIRO_MIME_TYPE_UNIQUE_ID,
+				 (const unsigned char **) &source_surface_key.unique_id,
+				 &source_surface_key.unique_id_length);
+    _cairo_svg_source_surface_init_key (&source_surface_key);
+
+    cairo_svg_source_surface_t *found_source_surface_entry = _cairo_hash_table_lookup (surface->source_surfaces,
+										       &source_surface_key.base);
+    if (found_source_surface_entry) {
 	*is_new = FALSE;
+	*result_source_surface = found_source_surface_entry;
 	return CAIRO_STATUS_SUCCESS;
     }
 
-    if (source_key.unique_id && source_key.unique_id_length > 0) {
-	unique_id = _cairo_malloc (source_key.unique_id_length);
+    unsigned char *unique_id = NULL;
+    unsigned long unique_id_length = 0;
+    if (source_surface_key.unique_id && source_surface_key.unique_id_length > 0) {
+	unique_id = _cairo_malloc (source_surface_key.unique_id_length);
 	if (unique_id == NULL) {
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	}
 
-	unique_id_length = source_key.unique_id_length;
-	memcpy (unique_id, source_key.unique_id, unique_id_length);
+	unique_id_length = source_surface_key.unique_id_length;
+	memcpy (unique_id, source_surface_key.unique_id, unique_id_length);
     } else {
 	unique_id = NULL;
 	unique_id_length = 0;
     }
 
-    source_entry = malloc (sizeof (cairo_svg_source_surface_t));
-    if (source_entry == NULL) {
+    cairo_svg_source_surface_t *source_surface_entry = malloc (sizeof (cairo_svg_source_surface_t));
+    if (source_surface_entry == NULL) {
 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	goto fail;
     }
-
-    source_entry->id = source_key.id;
-    source_entry->unique_id_length = unique_id_length;
-    source_entry->unique_id = unique_id;
-    _cairo_svg_source_surface_init_key (source_entry);
-    status = _cairo_hash_table_insert (surface->source_surfaces, &source_entry->base);
+    source_surface_entry->id = source_surface_key.id;
+    source_surface_entry->unique_id_length = unique_id_length;
+    source_surface_entry->unique_id = unique_id;
+    _cairo_svg_source_surface_init_key (source_surface_entry);
+    status = _cairo_hash_table_insert (surface->source_surfaces, &source_surface_entry->base);
     if (unlikely (status)) {
 	goto fail;
     }
 
     *is_new = TRUE;
-    *source_id = source_entry->id;
+    *result_source_surface = source_surface_entry;
     return CAIRO_STATUS_SUCCESS;
 
-  fail:
+    fail:
     free (unique_id);
-    free (source_entry);
+    free (source_surface_entry);
     return status;
 }
 
@@ -689,30 +745,35 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
 			 content,
 			 TRUE); /* is_vector */
 
+    surface->source_id = surface->base.unique_id;
+
+    surface->content = content;
+
     surface->width = width;
     surface->height = height;
     surface->surface_bounded = bounded;
 
     surface->document = _cairo_svg_document_reference (document);
 
-    _cairo_surface_clipper_init (&surface->clipper, _cairo_svg_surface_clipper_intersect_clip_path);
-    surface->current_clipper_output_stream = NULL;
-    surface->clip_level = 0;
-
     surface->xml_node = _cairo_memory_stream_create ();
-
     _cairo_array_init (&surface->page_set, sizeof (cairo_svg_page_t));
 
-    surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
-    surface->force_fallbacks = FALSE;
-    surface->content = content;
-
     surface->source_surfaces = _cairo_hash_table_create (_cairo_svg_source_surface_equal);
     if (unlikely (surface->source_surfaces == NULL)) {
 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	goto CLEANUP;
     }
 
+    _cairo_surface_clipper_init (&surface->clipper, _cairo_svg_surface_clipper_intersect_clip_path);
+    surface->current_clipper_output_stream = NULL;
+    surface->clip_level = 0;
+    surface->paint_used = FALSE;
+
+    surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
+
+    surface->force_fallbacks = FALSE;
+
+
     paginated = _cairo_paginated_surface_create (&surface->base,
 						 surface->content,
 						 &cairo_svg_surface_paginated_backend);
@@ -1153,9 +1214,7 @@ _cairo_svg_surface_finish (void *abstract_surface)
 
     _cairo_surface_clipper_reset (&surface->clipper);
 
-    _cairo_hash_table_foreach (surface->source_surfaces,
-			       _cairo_svg_source_surface_pluck,
-			       surface->source_surfaces);
+    _cairo_hash_table_foreach (surface->source_surfaces, _cairo_svg_source_surface_pluck, surface->source_surfaces);
     _cairo_hash_table_destroy (surface->source_surfaces);
 
     status2 = _cairo_svg_document_destroy (document);
@@ -1574,7 +1633,7 @@ _cairo_svg_surface_emit_surface (cairo_svg_document_t *document,
     assert (is_bounded);
 
     _cairo_output_stream_printf (document->xml_node_defs,
-				 "<image id=\"image-%d\" x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" xlink:href=\"",
+				 "<image id=\"source-%d\" x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" xlink:href=\"",
 				 source_id,
 				 extents.x, extents.y,
 				 extents.width, extents.height);
@@ -1610,15 +1669,16 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output
     /* cairo_pattern_set_matrix ensures the matrix is invertible */
     assert (status == CAIRO_STATUS_SUCCESS);
 
-    unsigned int source_id;
     cairo_bool_t is_new;
+    cairo_svg_source_surface_t *source_surface;
     status = _cairo_svg_surface_add_source_surface (surface,
 						    pattern->surface,
-						    &source_id,
-						    &is_new);
+						    &is_new,
+						    &source_surface);
     if (unlikely (status)) {
 	return status;
     }
+    unsigned int source_id = source_surface->id;
 
     if (is_new) {
 	status = _cairo_svg_surface_emit_surface (surface->document,
@@ -1655,7 +1715,7 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output
     }
 
     _cairo_output_stream_printf (output,
-				 "<use xlink:href=\"#image-%d\"",
+				 "<use xlink:href=\"#source-%d\"",
 				 source_id);
     if (pattern->surface->content == CAIRO_CONTENT_ALPHA) {
 	_cairo_output_stream_printf (output,
@@ -1679,29 +1739,28 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output
 }
 
 static cairo_status_t
-_cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
+_cairo_svg_surface_emit_recording_surface (cairo_svg_document_t *document,
 					   cairo_recording_surface_t *source,
-					   unsigned int               source_id)
+					   unsigned int source_id,
+					   cairo_bool_t *paint_used)
 {
     cairo_status_t status;
-    cairo_surface_t *paginated_surface;
-    cairo_svg_surface_t *svg_surface;
-    cairo_array_t *page_set;
-    cairo_rectangle_int_t extents;
-    cairo_bool_t bounded;
-    cairo_output_stream_t *contents;
-
-    bounded = _cairo_surface_get_extents (&source->base, &extents);
-    paginated_surface = _cairo_svg_surface_create_for_document (document,
-								source->base.content,
-								0,
-								0,
-								FALSE);
-    if (unlikely (paginated_surface->status))
+
+    cairo_surface_t *paginated_surface = _cairo_svg_surface_create_for_document (document,
+										 source->base.content,
+										 0,
+										 0,
+										 FALSE);
+    cairo_svg_surface_t *svg_surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (paginated_surface);
+    if (unlikely (paginated_surface->status)) {
 	return paginated_surface->status;
+    }
+
+    svg_surface->source_id = source_id;
+
+    cairo_rectangle_int_t extents;
+    cairo_bool_t bounded = _cairo_surface_get_extents (&source->base, &extents);
 
-    svg_surface = (cairo_svg_surface_t *)
-    _cairo_paginated_surface_get_target (paginated_surface);
     cairo_surface_set_fallback_resolution (paginated_surface,
 					   document->owner->x_fallback_resolution,
 					   document->owner->y_fallback_resolution);
@@ -1719,12 +1778,15 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
 	return status;
     }
 
+    unsigned int clip_id;
     if (bounded) {
+	clip_id = document->clip_id++;
+
 	_cairo_output_stream_printf (document->xml_node_defs,
 				     "<clipPath id=\"clip-%d\">\n"
 				     "<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"/>\n"
 				     "</clipPath>\n",
-				     svg_surface->document->clip_id,
+				     clip_id,
 				     extents.x,
 				     extents.y,
 				     extents.width,
@@ -1732,13 +1794,13 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
     }
 
     _cairo_output_stream_printf (document->xml_node_defs,
-				 "<g id=\"surface-%d\"",
+				 "<g id=\"source-%d\"",
 				 source_id);
 
     if (bounded) {
 	_cairo_output_stream_printf (document->xml_node_defs,
 				     " clip-path=\"url(#clip-%d)\"",
-				     svg_surface->document->clip_id);
+				     clip_id);
     }
 
     if (source->base.content == CAIRO_CONTENT_ALPHA) {
@@ -1749,14 +1811,7 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
 
     _cairo_output_stream_printf (document->xml_node_defs, ">\n");
 
-    if (bounded) {
-	svg_surface->document->clip_id++;
-    }
-
-    contents = svg_surface->xml_node;
-    page_set = &svg_surface->page_set;
-
-    if (_cairo_memory_stream_length (contents) > 0) {
+    if (_cairo_memory_stream_length (svg_surface->xml_node) > 0) {
 	cairo_svg_page_t *page = _cairo_svg_surface_store_page (svg_surface);
 	if (unlikely (page == NULL)) {
 	    cairo_surface_destroy (paginated_surface);
@@ -1764,15 +1819,15 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
 	}
     }
 
-    if (page_set->num_elements > 0) {
-	cairo_svg_page_t *page;
-
-	page = _cairo_array_index (page_set, page_set->num_elements - 1);
+    if (svg_surface->page_set.num_elements > 0) {
+	cairo_svg_page_t *page = _cairo_array_index (&svg_surface->page_set, svg_surface->page_set.num_elements - 1);
 	_cairo_memory_stream_copy (page->xml_node, document->xml_node_defs);
     }
 
     _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
 
+    *paint_used = svg_surface->paint_used;
+
     status = cairo_surface_status (paginated_surface);
     cairo_surface_destroy (paginated_surface);
 
@@ -1804,36 +1859,80 @@ _cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (const cairo_pattern_t *p
 }
 
 static cairo_status_t
-_cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t	*output,
-						     cairo_svg_surface_t	*surface,
-						     cairo_surface_pattern_t	*pattern,
-						     unsigned int		 pattern_id,
-						     const cairo_matrix_t	*parent_matrix)
+_cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t *output,
+						     cairo_svg_surface_t *surface,
+						     cairo_surface_pattern_t *pattern,
+						     unsigned int pattern_id,
+						     const cairo_matrix_t *parent_matrix)
 {
-    cairo_svg_document_t *document = surface->document;
-    cairo_recording_surface_t *recording_surface;
-    cairo_matrix_t p2u;
     cairo_status_t status;
-    unsigned int source_id;
-    cairo_bool_t is_new;
+    cairo_svg_document_t *document = surface->document;
 
-    p2u = pattern->base.matrix;
+    cairo_matrix_t p2u = pattern->base.matrix;
     status = cairo_matrix_invert (&p2u);
     /* cairo_pattern_set_matrix ensures the matrix is invertible */
     assert (status == CAIRO_STATUS_SUCCESS);
 
+    cairo_bool_t is_new;
+    cairo_svg_source_surface_t *source_surface;
     status = _cairo_svg_surface_add_source_surface (surface,
 						    pattern->surface,
-						    &source_id,
-						    &is_new);
-    if (unlikely (status))
+						    &is_new,
+						    &source_surface);
+    if (unlikely (status)) {
 	return status;
+    }
+    unsigned int source_id = source_surface->id;
 
-    recording_surface = _cairo_svg_surface_to_recording_surface (pattern);
+    cairo_recording_surface_t *recording_surface = _cairo_svg_surface_to_recording_surface (pattern);
     if (is_new) {
-	status = _cairo_svg_surface_emit_recording_surface (document, recording_surface, source_id);
-	if (unlikely (status))
+	status = _cairo_svg_surface_emit_recording_surface (document,
+							    recording_surface,
+							    source_id,
+							    &source_surface->paint_used);
+	if (unlikely (status)) {
+	    return status;
+	}
+    }
+
+    if (is_new && source_surface->paint_used) {
+	cairo_svg_paint_t *paint_entry = malloc (sizeof (cairo_svg_paint_t));
+	if (paint_entry == NULL) {
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	}
+	paint_entry->source_id = source_id;
+	paint_entry->xml_node = _cairo_memory_stream_create();
+	_cairo_svg_paint_init_key (paint_entry);
+	status = _cairo_hash_table_insert (document->paints, &paint_entry->base);
+	if (unlikely (status)) {
 	    return status;
+	}
+    }
+
+    if (source_surface->paint_used) {
+	cairo_svg_paint_t paint_key;
+	paint_key.source_id = source_id;
+	_cairo_svg_paint_init_key (&paint_key);
+
+	cairo_svg_paint_t *found_paint_entry = _cairo_hash_table_lookup (document->paints,
+									 &paint_key.base);
+	assert (found_paint_entry);
+
+	_cairo_output_stream_printf (found_paint_entry->xml_node,
+				     "<use xlink:href=\"#paint-%d\"",
+				     surface->source_id);
+	cairo_matrix_t matrix = pattern->base.matrix;
+	if (parent_matrix != NULL) {
+	    cairo_matrix_t parent_matrix_inverse = *parent_matrix;
+	    status = cairo_matrix_invert (&parent_matrix_inverse);
+	    /* cairo_pattern_set_matrix ensures the matrix is invertible */
+	    assert (status == CAIRO_STATUS_SUCCESS);
+	    cairo_matrix_multiply (&matrix, &parent_matrix_inverse, &matrix);
+	}
+	_cairo_svg_surface_emit_transform (found_paint_entry->xml_node, "transform", &matrix, NULL);
+	_cairo_output_stream_printf (found_paint_entry->xml_node, "/>\n");
+
+        surface->paint_used = TRUE;
     }
 
     if (pattern_id != invalid_pattern_id) {
@@ -1857,7 +1956,7 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t	*outp
     }
 
     _cairo_output_stream_printf (output,
-				 "<use xlink:href=\"#surface-%d\"",
+				 "<use xlink:href=\"#source-%d\"",
 				 source_id);
 
     if (pattern_id == invalid_pattern_id) {
@@ -1866,8 +1965,9 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t	*outp
 
     _cairo_output_stream_printf (output, "/>\n");
 
-    if (pattern_id != invalid_pattern_id)
+    if (pattern_id != invalid_pattern_id) {
 	_cairo_output_stream_printf (output, "</pattern>\n");
+    }
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -2458,9 +2558,10 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
 							  mask_source ? &mask_source->matrix : NULL);
     }
 
+    surface->paint_used = TRUE;
     _cairo_output_stream_printf (output,
-				 "<rect x=\"-50%%\" y=\"-50%%\" "
-				 "width=\"200%%\" height=\"200%%\"");
+				 "<use xlink:href=\"#paint-%d\"",
+				 surface->source_id);
     status = _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, NULL);
     if (unlikely (status)) {
 	return status;
@@ -3505,31 +3606,29 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream,
 			    cairo_svg_document_t **document_out)
 {
     cairo_svg_document_t *document;
-    cairo_status_t status;
 
     if (output_stream->status) {
 	return output_stream->status;
     }
 
     document = _cairo_malloc (sizeof (cairo_svg_document_t));
-    if (unlikely (document == NULL))
+    if (unlikely (document == NULL)) {
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    /* The use of defs for font glyphs imposes no per-subset limit. */
-    document->font_subsets = _cairo_scaled_font_subsets_create_scaled ();
-    if (unlikely (document->font_subsets == NULL)) {
-	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	goto cleanup_document;
     }
 
     document->output_stream = output_stream;
     document->refcount = 1;
     document->owner = NULL;
     document->finished = FALSE;
+
     document->width = width;
     document->height = height;
     document->unit = CAIRO_SVG_UNIT_USER;
 
+    document->xml_node_defs = _cairo_memory_stream_create ();
+    document->xml_node_glyphs = _cairo_memory_stream_create ();
+    document->xml_node_filters = _cairo_memory_stream_create ();
+
     document->linear_pattern_id = 0;
     document->radial_pattern_id = 0;
     document->pattern_id = 0;
@@ -3542,18 +3641,30 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream,
 	document->filters_emitted[filter] = FALSE;
     }
 
-    document->xml_node_defs = _cairo_memory_stream_create ();
-    document->xml_node_glyphs = _cairo_memory_stream_create ();
-    document->xml_node_filters = _cairo_memory_stream_create ();
-
     document->svg_version = version;
 
+    /* The use of defs for font glyphs imposes no per-subset limit. */
+    document->font_subsets = _cairo_scaled_font_subsets_create_scaled ();
+    if (unlikely (document->font_subsets == NULL)) {
+	(void) _cairo_output_stream_destroy(document->xml_node_defs);
+	(void) _cairo_output_stream_destroy(document->xml_node_glyphs);
+	(void) _cairo_output_stream_destroy(document->xml_node_filters);
+	free (document);
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    document->paints = _cairo_hash_table_create (_cairo_svg_paint_equal);
+    if (unlikely (document->paints == NULL)) {
+	(void) _cairo_output_stream_destroy(document->xml_node_defs);
+	(void) _cairo_output_stream_destroy(document->xml_node_glyphs);
+	(void) _cairo_output_stream_destroy(document->xml_node_filters);
+	_cairo_scaled_font_subsets_destroy (document->font_subsets);
+	free (document);
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
     *document_out = document;
     return CAIRO_STATUS_SUCCESS;
-
-    cleanup_document:
-    free (document);
-    return status;
 }
 
 static cairo_svg_document_t *
@@ -3588,7 +3699,7 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
     }
     document->finished = TRUE;
 
-    cairo_status_t status;
+    cairo_status_t status, final_status = CAIRO_STATUS_SUCCESS;
 
     cairo_output_stream_t *output = document->output_stream;
 
@@ -3625,13 +3736,27 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
 				 document->width, document->height);
 
     status = _cairo_svg_document_emit_font_subsets (document);
-    if (unlikely (status)) {
-	return status;
+    if (final_status == CAIRO_STATUS_SUCCESS) {
+	final_status = status;
+    }
+
+    cairo_svg_surface_t *surface = NULL;
+    if (document->owner != NULL) {
+	surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (document->owner);
+
+	if (surface->xml_node != NULL && _cairo_memory_stream_length (surface->xml_node) > 0) {
+	    cairo_svg_page_t *page = _cairo_svg_surface_store_page (surface);
+	    if (final_status == CAIRO_STATUS_SUCCESS && page == NULL) {
+		final_status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    }
+	}
     }
 
     if (_cairo_memory_stream_length (document->xml_node_filters) > 0 ||
 	_cairo_memory_stream_length (document->xml_node_glyphs) > 0 ||
-	_cairo_memory_stream_length (document->xml_node_defs) > 0) {
+	_cairo_memory_stream_length (document->xml_node_defs) > 0 ||
+	_cairo_hash_table_size (document->paints) != 0 ||
+	(surface != NULL && surface->paint_used)) {
 	_cairo_output_stream_printf (output, "<defs>\n");
 	_cairo_memory_stream_copy (document->xml_node_filters, output);
 	if (_cairo_memory_stream_length (document->xml_node_glyphs) > 0) {
@@ -3640,19 +3765,17 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
 	    _cairo_output_stream_printf (output, "</g>\n");
 	}
 	_cairo_memory_stream_copy (document->xml_node_defs, output);
+	_cairo_hash_table_foreach (document->paints, _cairo_svg_paint_emit, output);
+	if (surface != NULL && surface->paint_used) {
+	    _cairo_output_stream_printf (output,
+					 "<rect id=\"paint-%d\" x=\"0\" y=\"0\" width=\"%f\" height=\"%f\"/>\n",
+					 surface->source_id,
+					 document->width, document->height);
+	}
 	_cairo_output_stream_printf (output, "</defs>\n");
     }
 
     if (document->owner != NULL) {
-	cairo_svg_surface_t *surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (document->owner);
-
-	if (surface->xml_node != NULL && _cairo_memory_stream_length (surface->xml_node) > 0) {
-	    cairo_svg_page_t *page = _cairo_svg_surface_store_page (surface);
-	    if (unlikely (page == NULL)) {
-		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	    }
-	}
-
 	if (surface->page_set.num_elements == 1) {
 	    cairo_svg_page_t *page = _cairo_array_index (&surface->page_set, 0);
 	    _cairo_memory_stream_copy (page->xml_node, output);
@@ -3670,24 +3793,27 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
 
     _cairo_output_stream_printf (output, "</svg>\n");
 
-    status = _cairo_output_stream_destroy (document->xml_node_filters);
-    if (unlikely (status)) {
-	return status;
+    status = _cairo_output_stream_destroy (document->xml_node_defs);
+    if (final_status == CAIRO_STATUS_SUCCESS) {
+	final_status = status;
     }
 
     status = _cairo_output_stream_destroy (document->xml_node_glyphs);
-    if (unlikely (status)) {
-	return status;
+    if (final_status == CAIRO_STATUS_SUCCESS) {
+	final_status = status;
     }
 
-    status = _cairo_output_stream_destroy (document->xml_node_defs);
-    if (unlikely (status)) {
-	return status;
+    status = _cairo_output_stream_destroy (document->xml_node_filters);
+    if (final_status == CAIRO_STATUS_SUCCESS) {
+	final_status = status;
     }
 
+    _cairo_hash_table_foreach (document->paints, _cairo_svg_paint_pluck, document->paints);
+    _cairo_hash_table_destroy (document->paints);
+
     status = _cairo_output_stream_destroy (output);
-    if (unlikely (status)) {
-	return status;
+    if (final_status == CAIRO_STATUS_SUCCESS) {
+	final_status = status;
     }
 
     return CAIRO_STATUS_SUCCESS;
commit c2ea2848fd52c23023f31f35f1a16693f8b50313
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sun Apr 11 13:05:59 2021 +0200

    Simplify _cairo_svg_surface_emit_composite_surface_pattern

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index e43621db4..a10c47792 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -623,18 +623,17 @@ _cairo_svg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper
     }
 
     _cairo_output_stream_printf (document->xml_node_defs,
-				 "<clipPath id=\"clip-%d\">\n"
-				 "<path",
+				 "<clipPath id=\"clip-%d\">\n",
 				 document->clip_id);
+
+    _cairo_output_stream_printf (document->xml_node_defs, "<path");
     _cairo_svg_surface_emit_path (document->xml_node_defs, path, NULL);
+    _cairo_output_stream_printf (document->xml_node_defs, "/>\n");
 
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "/>\n"
-				 "</clipPath>\n");
+    _cairo_output_stream_printf (document->xml_node_defs, "</clipPath>\n");
 
     _cairo_output_stream_printf (surface->current_clipper_output_stream,
-				 "<g clip-path=\"url(#clip-%d)\" "
-				 "clip-rule=\"%s\">\n",
+				 "<g clip-path=\"url(#clip-%d)\" clip-rule=\"%s\">\n",
 				 document->clip_id,
 				 fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero");
 
@@ -1598,35 +1597,36 @@ _cairo_svg_surface_emit_surface (cairo_svg_document_t *document,
 }
 
 static cairo_status_t
-_cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t   *output,
-						   cairo_svg_surface_t	 *svg_surface,
+_cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t *output,
+						   cairo_svg_surface_t *surface,
 						   cairo_surface_pattern_t *pattern,
-						   unsigned int		  pattern_id,
-						   const cairo_matrix_t	 *parent_matrix)
+						   unsigned int pattern_id,
+						   const cairo_matrix_t *parent_matrix)
 {
     cairo_status_t status;
-    cairo_matrix_t p2u;
-    unsigned int source_id;
-    cairo_bool_t is_new;
 
-    p2u = pattern->base.matrix;
+    cairo_matrix_t p2u = pattern->base.matrix;
     status = cairo_matrix_invert (&p2u);
     /* cairo_pattern_set_matrix ensures the matrix is invertible */
     assert (status == CAIRO_STATUS_SUCCESS);
 
-    status = _cairo_svg_surface_add_source_surface (svg_surface,
+    unsigned int source_id;
+    cairo_bool_t is_new;
+    status = _cairo_svg_surface_add_source_surface (surface,
 						    pattern->surface,
 						    &source_id,
 						    &is_new);
-    if (unlikely (status))
+    if (unlikely (status)) {
 	return status;
+    }
 
     if (is_new) {
-	status = _cairo_svg_surface_emit_surface (svg_surface->document,
+	status = _cairo_svg_surface_emit_surface (surface->document,
 						  pattern->surface,
 						  source_id);
-	if (unlikely (status))
+	if (unlikely (status)) {
 	    return status;
+	}
     }
 
     if (pattern_id != invalid_pattern_id) {
@@ -1649,34 +1649,31 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t   *outp
 				     extents.width, extents.height);
 	_cairo_svg_surface_emit_transform (output,
 					   "patternTransform",
-					   &p2u, parent_matrix);
+					   &p2u,
+					   parent_matrix);
 	_cairo_output_stream_printf (output, ">\n");
     }
 
+    _cairo_output_stream_printf (output,
+				 "<use xlink:href=\"#image-%d\"",
+				 source_id);
     if (pattern->surface->content == CAIRO_CONTENT_ALPHA) {
 	_cairo_output_stream_printf (output,
-				     "<g filter=\"url(#filter-%s)\">\n",
-				     _cairo_svg_surface_emit_static_filter (svg_surface->document,
+				     " filter=\"url(#filter-%s)\"",
+				     _cairo_svg_surface_emit_static_filter (surface->document,
 									    CAIRO_SVG_FILTER_COLOR_TO_ALPHA));
     }
-
-    _cairo_output_stream_printf (output,
-				 "<use xlink:href=\"#image-%d\"",
-				 source_id);
-
     if (pattern_id == invalid_pattern_id) {
 	_cairo_svg_surface_emit_transform (output,
 					   "transform",
-					   &p2u, parent_matrix);
+					   &p2u,
+					   parent_matrix);
     }
     _cairo_output_stream_printf (output, "/>\n");
 
-    if (pattern->surface->content == CAIRO_CONTENT_ALPHA) {
-	_cairo_output_stream_printf (output, "</g>\n");
-    }
-
-    if (pattern_id != invalid_pattern_id)
+    if (pattern_id != invalid_pattern_id) {
 	_cairo_output_stream_printf (output, "</pattern>\n");
+    }
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1876,27 +1873,29 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t	*outp
 }
 
 static cairo_status_t
-_cairo_svg_surface_emit_composite_pattern (cairo_output_stream_t   *output,
-					   cairo_svg_surface_t	   *surface,
+_cairo_svg_surface_emit_composite_pattern (cairo_output_stream_t *output,
+					   cairo_svg_surface_t *surface,
 					   cairo_surface_pattern_t *pattern,
-					   unsigned int		    pattern_id,
-					   const cairo_matrix_t	   *parent_matrix)
+					   unsigned int pattern_id,
+					   const cairo_matrix_t *parent_matrix)
 {
     if (pattern_id != invalid_pattern_id) {
-        assert (_cairo_svg_surface_svg_pattern_should_be_used(&pattern->base));
+	assert (_cairo_svg_surface_svg_pattern_should_be_used (&pattern->base));
     }
 
     if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
-	return _cairo_svg_surface_emit_composite_recording_pattern (output, surface,
+	return _cairo_svg_surface_emit_composite_recording_pattern (output,
+								    surface,
 								    pattern,
 								    pattern_id,
 								    parent_matrix);
+    } else {
+	return _cairo_svg_surface_emit_composite_surface_pattern (output,
+								  surface,
+								  pattern,
+								  pattern_id,
+								  parent_matrix);
     }
-
-    return _cairo_svg_surface_emit_composite_surface_pattern (output, surface,
-							      pattern,
-							      pattern_id,
-							      parent_matrix);
 }
 
 static cairo_status_t
@@ -2445,18 +2444,19 @@ _cairo_svg_surface_get_extents (void		        *abstract_surface,
 
 static cairo_status_t
 _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
-			       cairo_svg_surface_t   *surface,
-			       const cairo_pattern_t	     *source,
-			       const cairo_pattern_t	     *mask_source)
+			       cairo_svg_surface_t *surface,
+			       const cairo_pattern_t *source,
+			       const cairo_pattern_t *mask_source)
 {
     cairo_status_t status;
 
-    if (_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used(source))
+    if (_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (source)) {
 	return _cairo_svg_surface_emit_composite_pattern (output,
 							  surface,
 							  (cairo_surface_pattern_t *) source,
 							  invalid_pattern_id,
 							  mask_source ? &mask_source->matrix : NULL);
+    }
 
     _cairo_output_stream_printf (output,
 				 "<rect x=\"-50%%\" y=\"-50%%\" "
@@ -2465,7 +2465,6 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
     if (unlikely (status)) {
 	return status;
     }
-
     _cairo_output_stream_printf (output, "/>\n");
 
     return CAIRO_STATUS_SUCCESS;
@@ -3049,10 +3048,7 @@ _cairo_svg_surface_mask_impl (cairo_output_stream_t *output,
 				 "<g mask=\"url(#mask-%d)\">\n",
 				 mask_id);
 
-    status = _cairo_svg_surface_emit_paint (output,
-					    surface,
-					    source,
-					    NULL);
+    status = _cairo_svg_surface_emit_paint (output, surface, source, NULL);
     if (unlikely (status)) {
 	return status;
     }
@@ -3355,9 +3351,11 @@ _cairo_svg_surface_show_glyphs_impl (cairo_output_stream_t *output,
     }
 
     _cairo_output_stream_printf (output, "<g");
+
     status = _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, NULL);
-    if (unlikely (status))
+    if (unlikely (status)) {
 	return status;
+    }
 
     _cairo_output_stream_printf (output, ">\n");
 
@@ -3401,7 +3399,6 @@ _cairo_svg_surface_show_glyphs_impl (cairo_output_stream_t *output,
     status = _cairo_scaled_font_glyph_path (scaled_font,
 					    (cairo_glyph_t *) glyphs,
 					    num_glyphs, &path);
-
     if (unlikely (status)) {
 	_cairo_path_fixed_fini (&path);
 	return status;
commit 89eda6f65035af676f8028a1ecfab6e376a757a0
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sat Apr 10 23:45:26 2021 +0200

    Simplify ignoring of statuses

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 399d1fdcb..e43621db4 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -318,41 +318,35 @@ _cairo_surface_is_svg (cairo_surface_t *surface)
  * target. Otherwise return FALSE.
  */
 static cairo_bool_t
-_extract_svg_surface (cairo_surface_t		 *surface,
-		      cairo_svg_surface_t	**svg_surface)
+_extract_svg_surface (cairo_surface_t *surface,
+		      cairo_svg_surface_t **svg_surface)
 {
     cairo_surface_t *target;
-    cairo_status_t status_ignored;
 
     if (surface->status)
 	return FALSE;
     if (surface->finished) {
-	status_ignored = _cairo_surface_set_error (surface,
-						   _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
-        return FALSE;
+	(void) _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
+	return FALSE;
     }
 
-    if (! _cairo_surface_is_paginated (surface)) {
-	status_ignored = _cairo_surface_set_error (surface,
-						   _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
+    if (!_cairo_surface_is_paginated (surface)) {
+	(void) _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
 	return FALSE;
     }
 
     target = _cairo_paginated_surface_get_target (surface);
     if (target->status) {
-	status_ignored = _cairo_surface_set_error (surface,
-						   target->status);
+	(void) _cairo_surface_set_error (surface, target->status);
 	return FALSE;
     }
     if (target->finished) {
-	status_ignored = _cairo_surface_set_error (surface,
-						   _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
-        return FALSE;
+	(void) _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
+	return FALSE;
     }
 
-    if (! _cairo_surface_is_svg (target)) {
-	status_ignored = _cairo_surface_set_error (surface,
-						   _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
+    if (!_cairo_surface_is_svg (target)) {
+	(void) _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
 	return FALSE;
     }
 
@@ -675,19 +669,20 @@ _cairo_svg_surface_set_clip (cairo_svg_surface_t *surface,
 }
 
 static cairo_surface_t *
-_cairo_svg_surface_create_for_document (cairo_svg_document_t	*document,
-					cairo_content_t		 content,
-					double			 width,
-					double			 height,
-					cairo_bool_t             bounded)
+_cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
+					cairo_content_t content,
+					double width,
+					double height,
+					cairo_bool_t bounded)
 {
     cairo_svg_surface_t *surface;
     cairo_surface_t *paginated;
-    cairo_status_t status, status_ignored;
+    cairo_status_t status;
 
     surface = _cairo_malloc (sizeof (cairo_svg_surface_t));
-    if (unlikely (surface == NULL))
+    if (unlikely (surface == NULL)) {
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+    }
 
     _cairo_surface_init (&surface->base,
 			 &cairo_svg_surface_backend,
@@ -720,7 +715,7 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t	*document,
     }
 
     paginated = _cairo_paginated_surface_create (&surface->base,
-					         surface->content,
+						 surface->content,
 						 &cairo_svg_surface_paginated_backend);
     status = paginated->status;
     if (status == CAIRO_STATUS_SUCCESS) {
@@ -730,9 +725,9 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t	*document,
     }
 
     /* ignore status as we are on the error path */
-CLEANUP:
-    status_ignored = _cairo_output_stream_destroy (surface->xml_node);
-    status_ignored = _cairo_svg_document_destroy (document);
+    CLEANUP:
+    (void) _cairo_output_stream_destroy (surface->xml_node);
+    (void) _cairo_svg_document_destroy (document);
 
     free (surface);
 
@@ -2496,11 +2491,9 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 
 	status = _cairo_output_stream_destroy (source_stream);
 	if (unlikely (status)) {
-	    cairo_status_t ignore1 = _cairo_output_stream_destroy (destination_stream);
-	    cairo_status_t ignore2 = _cairo_output_stream_destroy (mask_stream);
+	    (void) _cairo_output_stream_destroy (destination_stream);
+	    (void) _cairo_output_stream_destroy (mask_stream);
 	    return status;
-	    (void) ignore1;
-	    (void) ignore2;
 	}
 	return _cairo_svg_surface_do_operator (output,
 					       surface,
@@ -2535,22 +2528,17 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 				     lerp_compositing_group_id);
 	status = _cairo_svg_surface_set_clip (surface, document->xml_node_defs, clip);
 	if (unlikely (status)) {
-	    cairo_status_t ignore1 = _cairo_output_stream_destroy (destination_stream);
-	    cairo_status_t ignore2 = _cairo_output_stream_destroy (source_stream);
-	    cairo_status_t ignore3 = _cairo_output_stream_destroy (mask_stream);
+	    (void) _cairo_output_stream_destroy (destination_stream);
+	    (void) _cairo_output_stream_destroy (source_stream);
+	    (void) _cairo_output_stream_destroy (mask_stream);
 	    return status;
-	    (void) ignore1;
-	    (void) ignore2;
-	    (void) ignore3;
 	}
 	_cairo_memory_stream_copy (mask_stream, document->xml_node_defs);
 	status = _cairo_output_stream_destroy (mask_stream);
 	if (unlikely (status)) {
-	    cairo_status_t ignore1 = _cairo_output_stream_destroy (destination_stream);
-	    cairo_status_t ignore2 = _cairo_output_stream_destroy (source_stream);
+	    (void) _cairo_output_stream_destroy (destination_stream);
+	    (void) _cairo_output_stream_destroy (source_stream);
 	    return status;
-	    (void) ignore1;
-	    (void) ignore2;
 	}
 	_cairo_svg_surface_reset_clip (surface);
 	_cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
@@ -2583,9 +2571,8 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 	_cairo_memory_stream_copy (source_stream, document->xml_node_defs);
 	status = _cairo_output_stream_destroy (source_stream);
 	if (unlikely (status)) {
-	    cairo_status_t ignore = _cairo_output_stream_destroy (destination_stream);
+	    (void) _cairo_output_stream_destroy (destination_stream);
 	    return status;
-	    (void) ignore;
 	}
 	_cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
 
@@ -2624,17 +2611,14 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 	_cairo_memory_stream_copy (destination_stream, surface->xml_node);
 	status = _cairo_output_stream_destroy (destination_stream);
 	if (unlikely (status)) {
-	    cairo_status_t ignore1 = _cairo_output_stream_destroy (source_stream);
-	    cairo_status_t ignore2 = _cairo_output_stream_destroy (mask_stream);
+	    (void) _cairo_output_stream_destroy (source_stream);
+	    (void) _cairo_output_stream_destroy (mask_stream);
 	    return status;
-	    (void) ignore1;
-	    (void) ignore2;
 	}
 	status = _cairo_output_stream_destroy (source_stream);
 	if (unlikely (status)) {
-	    cairo_status_t ignore = _cairo_output_stream_destroy (source_stream);
+	    (void) _cairo_output_stream_destroy (source_stream);
 	    return status;
-	    (void) ignore;
 	}
 	status = _cairo_output_stream_destroy (source_stream);
 	if (unlikely (status)) {
@@ -2670,23 +2654,17 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 				 lerp_compositing_group_id);
     status = _cairo_svg_surface_set_clip (surface, document->xml_node_defs, clip);
     if (unlikely (status)) {
-	cairo_status_t ignore1 = _cairo_output_stream_destroy (destination_stream);
-	cairo_status_t ignore2 = _cairo_output_stream_destroy (source_stream);
-	cairo_status_t ignore3 = _cairo_output_stream_destroy (mask_stream);
+	(void) _cairo_output_stream_destroy (destination_stream);
+	(void) _cairo_output_stream_destroy (source_stream);
+	(void) _cairo_output_stream_destroy (mask_stream);
 	return status;
-	(void) ignore1;
-	(void) ignore2;
-	(void) ignore3;
     }
     status = _cairo_svg_surface_emit_paint (document->xml_node_defs, surface, &_cairo_pattern_white.base, NULL);
     if (unlikely (status)) {
-	cairo_status_t ignore1 = _cairo_output_stream_destroy (destination_stream);
-	cairo_status_t ignore2 = _cairo_output_stream_destroy (source_stream);
-	cairo_status_t ignore3 = _cairo_output_stream_destroy (mask_stream);
+	(void) _cairo_output_stream_destroy (destination_stream);
+	(void) _cairo_output_stream_destroy (source_stream);
+	(void) _cairo_output_stream_destroy (mask_stream);
 	return status;
-	(void) ignore1;
-	(void) ignore2;
-	(void) ignore3;
     }
     _cairo_svg_surface_reset_clip (surface);
     _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
@@ -2718,11 +2696,9 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
     _cairo_memory_stream_copy (mask_stream, document->xml_node_defs);
     status = _cairo_output_stream_destroy (mask_stream);
     if (unlikely (status)) {
-	cairo_status_t ignore1 = _cairo_output_stream_destroy (source_stream);
-	cairo_status_t ignore2 = _cairo_output_stream_destroy (destination_stream);
+	(void) _cairo_output_stream_destroy (source_stream);
+	(void) _cairo_output_stream_destroy (destination_stream);
 	return status;
-	(void) ignore1;
-	(void) ignore2;
     }
     _cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
 
@@ -2734,9 +2710,8 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
     _cairo_memory_stream_copy (source_stream, document->xml_node_defs);
     status = _cairo_output_stream_destroy (source_stream);
     if (unlikely (status)) {
-	cairo_status_t ignore = _cairo_output_stream_destroy (destination_stream);
+	(void) _cairo_output_stream_destroy (destination_stream);
 	return status;
-	(void) ignore;
     }
     _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
 
@@ -2959,9 +2934,8 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
         cairo_output_stream_t *mask_stream = _cairo_memory_stream_create (); \
         status = OPERATOR_IMPL (mask_stream, surface, &_cairo_pattern_white.base, ## __VA_ARGS__); \
         if (unlikely (status)) { \
-            cairo_status_t ignore = _cairo_output_stream_destroy (mask_stream); \
+            (void) _cairo_output_stream_destroy (mask_stream); \
             return status; \
-            (void) ignore; \
         } \
         cairo_output_stream_t *source_stream = _cairo_memory_stream_create (); \
         status = _cairo_svg_surface_emit_paint (source_stream, \
@@ -2969,11 +2943,9 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
                                                 SOURCE, \
                                                 NULL); \
         if (unlikely (status)) { \
-            cairo_status_t ignore1 = _cairo_output_stream_destroy (source_stream); \
-            cairo_status_t ignore2 = _cairo_output_stream_destroy (mask_stream); \
+            (void) _cairo_output_stream_destroy (source_stream); \
+            (void) _cairo_output_stream_destroy (mask_stream); \
             return status; \
-            (void) ignore1; \
-            (void) ignore2; \
         } \
         cairo_output_stream_t *destination_stream = surface->xml_node; \
         surface->xml_node = _cairo_memory_stream_create (); \
@@ -3060,9 +3032,8 @@ _cairo_svg_surface_mask_impl (cairo_output_stream_t *output,
 				 _cairo_svg_surface_emit_static_filter (document, CAIRO_SVG_FILTER_REMOVE_COLOR));
     status = _cairo_svg_surface_emit_paint (temporary_stream, surface, mask, source);
     if (unlikely (status)) {
-	cairo_status_t ignore = _cairo_output_stream_destroy (temporary_stream);
+	(void) _cairo_output_stream_destroy (temporary_stream);
 	return status;
-	(void) ignore;
     }
     _cairo_output_stream_printf (temporary_stream, "</g>\n");
     _cairo_output_stream_printf (temporary_stream, "</mask>\n");
commit cf0023d7cef4b0bb82020d496de40d36b8503973
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sat Apr 10 23:39:13 2021 +0200

    Simplify SVG document generation

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 48bc6468c..399d1fdcb 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -101,12 +101,6 @@ _cairo_svg_surface_emit_path (cairo_output_stream_t	*output,
 			      const cairo_path_fixed_t	*path,
 			      const cairo_matrix_t	*ctm_inverse);
 
-static cairo_bool_t
-_cairo_svg_version_has_page_set_support (cairo_svg_version_t version)
-{
-    return version > CAIRO_SVG_VERSION_1_1;
-}
-
 static const char * _cairo_svg_version_strings[CAIRO_SVG_VERSION_LAST] =
 {
     "SVG 1.1",
@@ -156,7 +150,6 @@ enum cairo_svg_filter {
 };
 
 struct cairo_svg_page {
-    unsigned int surface_id;
     cairo_output_stream_t *xml_node;
 };
 
@@ -784,24 +777,13 @@ _cairo_svg_surface_create_for_stream_internal (cairo_output_stream_t	*stream,
 static cairo_svg_page_t *
 _cairo_svg_surface_store_page (cairo_svg_surface_t *surface)
 {
-    cairo_svg_page_t page;
-    cairo_output_stream_t *stream;
-    cairo_int_status_t status;
-
     _cairo_svg_surface_reset_clip (surface);
-
-    stream = _cairo_memory_stream_create ();
-
-    page.surface_id = surface->base.unique_id;
+    cairo_svg_page_t page;
     page.xml_node = surface->xml_node;
-
     if (_cairo_array_append (&surface->page_set, &page)) {
-	status = _cairo_output_stream_destroy (stream);
 	return NULL;
     }
-
-    surface->xml_node = stream;
-
+    surface->xml_node = _cairo_memory_stream_create ();
     return _cairo_array_index (&surface->page_set,
 			       surface->page_set.num_elements - 1);
 }
@@ -810,11 +792,11 @@ static cairo_int_status_t
 _cairo_svg_surface_copy_page (void *abstract_surface)
 {
     cairo_svg_surface_t *surface = abstract_surface;
-    cairo_svg_page_t *page;
 
-    page = _cairo_svg_surface_store_page (surface);
-    if (unlikely (page == NULL))
+    cairo_svg_page_t *page = _cairo_svg_surface_store_page (surface);
+    if (unlikely (page == NULL)) {
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
 
     _cairo_memory_stream_copy (page->xml_node, surface->xml_node);
 
@@ -826,8 +808,10 @@ _cairo_svg_surface_show_page (void *abstract_surface)
 {
     cairo_svg_surface_t *surface = abstract_surface;
 
-    if (unlikely (_cairo_svg_surface_store_page (surface) == NULL))
+    cairo_svg_page_t *page = _cairo_svg_surface_store_page (surface);
+    if (unlikely (page == NULL)) {
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1781,7 +1765,8 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
     page_set = &svg_surface->page_set;
 
     if (_cairo_memory_stream_length (contents) > 0) {
-	if (unlikely (_cairo_svg_surface_store_page (svg_surface) == NULL)) {
+	cairo_svg_page_t *page = _cairo_svg_surface_store_page (svg_surface);
+	if (unlikely (page == NULL)) {
 	    cairo_surface_destroy (paginated_surface);
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	}
@@ -3630,13 +3615,14 @@ _cairo_svg_document_destroy (cairo_svg_document_t *document)
 static cairo_status_t
 _cairo_svg_document_finish (cairo_svg_document_t *document)
 {
-    cairo_status_t status, status2;
-    cairo_output_stream_t *output = document->output_stream;
-    cairo_svg_page_t *page;
-    unsigned int i;
-
-    if (document->finished)
+    if (document->finished) {
 	return CAIRO_STATUS_SUCCESS;
+    }
+    document->finished = TRUE;
+
+    cairo_status_t status;
+
+    cairo_output_stream_t *output = document->output_stream;
 
     /*
      * Should we add DOCTYPE?
@@ -3666,11 +3652,14 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
 				 "xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
 				 "width=\"%f%s\" height=\"%f%s\" "
 				 "viewBox=\"0 0 %f %f\">\n",
-				 document->width, _cairo_svg_unit_strings [document->unit],
-				 document->height, _cairo_svg_unit_strings [document->unit],
+				 document->width, _cairo_svg_unit_strings[document->unit],
+				 document->height, _cairo_svg_unit_strings[document->unit],
 				 document->width, document->height);
 
     status = _cairo_svg_document_emit_font_subsets (document);
+    if (unlikely (status)) {
+	return status;
+    }
 
     if (_cairo_memory_stream_length (document->xml_node_filters) > 0 ||
 	_cairo_memory_stream_length (document->xml_node_glyphs) > 0 ||
@@ -3687,61 +3676,53 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
     }
 
     if (document->owner != NULL) {
-	cairo_svg_surface_t *surface;
-
-	surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (document->owner);
-	if (surface->xml_node != NULL &&
-		_cairo_memory_stream_length (surface->xml_node) > 0) {
-	    if (unlikely (_cairo_svg_surface_store_page (surface) == NULL)) {
-		if (status == CAIRO_STATUS_SUCCESS)
-		    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	cairo_svg_surface_t *surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (document->owner);
+
+	if (surface->xml_node != NULL && _cairo_memory_stream_length (surface->xml_node) > 0) {
+	    cairo_svg_page_t *page = _cairo_svg_surface_store_page (surface);
+	    if (unlikely (page == NULL)) {
+		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	    }
 	}
 
-	if (surface->page_set.num_elements > 1 &&
-	    _cairo_svg_version_has_page_set_support (document->svg_version)) {
+	if (surface->page_set.num_elements == 1) {
+	    cairo_svg_page_t *page = _cairo_array_index (&surface->page_set, 0);
+	    _cairo_memory_stream_copy (page->xml_node, output);
+	} else if (surface->page_set.num_elements > 1) {
 	    _cairo_output_stream_printf (output, "<pageSet>\n");
-	    for (i = 0; i < surface->page_set.num_elements; i++) {
-		page = _cairo_array_index (&surface->page_set, i);
+	    for (unsigned int i = 0; i < surface->page_set.num_elements; i++) {
+		cairo_svg_page_t *page = _cairo_array_index (&surface->page_set, i);
 		_cairo_output_stream_printf (output, "<page>\n");
-		_cairo_output_stream_printf (output,
-					     "<g id=\"surface-%d\">\n",
-					     page->surface_id);
 		_cairo_memory_stream_copy (page->xml_node, output);
-		_cairo_output_stream_printf (output, "</g>\n</page>\n");
+		_cairo_output_stream_printf (output, "</page>\n");
 	    }
 	    _cairo_output_stream_printf (output, "</pageSet>\n");
-	} else if (surface->page_set.num_elements > 0) {
-	    page = _cairo_array_index (&surface->page_set, surface->page_set.num_elements - 1);
-	    _cairo_output_stream_printf (output,
-					 "<g id=\"surface-%d\">\n",
-					 page->surface_id);
-	    _cairo_memory_stream_copy (page->xml_node, output);
-	    _cairo_output_stream_printf (output, "</g>\n");
 	}
     }
 
     _cairo_output_stream_printf (output, "</svg>\n");
 
-    status2 = _cairo_output_stream_destroy (document->xml_node_filters);
-    if (status == CAIRO_STATUS_SUCCESS)
-	status = status2;
-
-    status2 = _cairo_output_stream_destroy (document->xml_node_glyphs);
-    if (status == CAIRO_STATUS_SUCCESS)
-	status = status2;
+    status = _cairo_output_stream_destroy (document->xml_node_filters);
+    if (unlikely (status)) {
+	return status;
+    }
 
-    status2 = _cairo_output_stream_destroy (document->xml_node_defs);
-    if (status == CAIRO_STATUS_SUCCESS)
-	status = status2;
+    status = _cairo_output_stream_destroy (document->xml_node_glyphs);
+    if (unlikely (status)) {
+	return status;
+    }
 
-    status2 = _cairo_output_stream_destroy (output);
-    if (status == CAIRO_STATUS_SUCCESS)
-	status = status2;
+    status = _cairo_output_stream_destroy (document->xml_node_defs);
+    if (unlikely (status)) {
+	return status;
+    }
 
-    document->finished = TRUE;
+    status = _cairo_output_stream_destroy (output);
+    if (unlikely (status)) {
+	return status;
+    }
 
-    return status;
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
commit 733c38b9f494fe64d1314e5d5cc5da4212a5bb9b
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sat Apr 10 23:08:06 2021 +0200

    Fix and clarify _cairo_svg_surface_do_operator

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 0cab2724a..48bc6468c 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -179,7 +179,7 @@ struct cairo_svg_document {
     unsigned int pattern_id;
     unsigned int clip_id;
     unsigned int mask_id;
-    unsigned int composing_group_id;
+    unsigned int compositing_group_id;
     unsigned int filter_id;
 
     cairo_bool_t filters_emitted[CAIRO_SVG_FILTER_LAST_STATIC_FILTER];
@@ -1250,35 +1250,35 @@ _cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cair
     _cairo_output_stream_printf (document->xml_node_filters, \
 				 "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" " \
 				 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n" \
-				 "<feImage xlink:href=\"#composing-group-%d\" result=\"source\"/>\n" \
-				 "<feImage xlink:href=\"#composing-group-%d\" result=\"destination\"/>\n" \
+				 "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"/>\n" \
+				 "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"/>\n" \
 				 "<feComposite in=\"source\" in2=\"destination\" " \
 				 "operator=\"" operation "\" " \
 				 "color-interpolation-filters=\"sRGB\"/>\n" \
 				 "</filter>\n", \
 				 filter_id, \
-				 source_composing_group_id, \
-				 destination_composing_group_id)
+				 source_compositing_group_id, \
+				 destination_compositing_group_id)
 
 #define _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER(mode) \
     _cairo_output_stream_printf (document->xml_node_filters, \
 				 "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" " \
 				 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n" \
-				 "<feImage xlink:href=\"#composing-group-%d\" result=\"source\"/>\n" \
-				 "<feImage xlink:href=\"#composing-group-%d\" result=\"destination\"/>\n" \
+				 "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"/>\n" \
+				 "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"/>\n" \
 				 "<feBlend in=\"source\" in2=\"destination\" " \
 				 "mode=\"" mode "\" " \
 				 "color-interpolation-filters=\"sRGB\"/>\n" \
 				 "</filter>\n", \
 				 filter_id, \
-				 source_composing_group_id, \
-				 destination_composing_group_id)
+				 source_compositing_group_id, \
+				 destination_compositing_group_id)
 
 static unsigned int
 _cairo_svg_surface_emit_parametric_filter (cairo_svg_document_t *document,
 					   enum cairo_svg_filter filter,
-					   unsigned int source_composing_group_id,
-					   unsigned int destination_composing_group_id)
+					   unsigned int source_compositing_group_id,
+					   unsigned int destination_compositing_group_id)
 {
     unsigned int filter_id = document->filter_id++;
     switch (filter) {
@@ -1302,15 +1302,15 @@ _cairo_svg_surface_emit_parametric_filter (cairo_svg_document_t *document,
 	_cairo_output_stream_printf (document->xml_node_filters,
 				     "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" "
 				     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
-				     "<feImage xlink:href=\"#composing-group-%d\" result=\"source\"/>\n"
-				     "<feImage xlink:href=\"#composing-group-%d\" result=\"destination\"/>\n"
+				     "<feImage xlink:href=\"#compositing-group-%d\" result=\"source\"/>\n"
+				     "<feImage xlink:href=\"#compositing-group-%d\" result=\"destination\"/>\n"
 				     "<feComposite in=\"source\" in2=\"destination\" "
 				     "operator=\"arithmetic\" k1=\"0\" k2=\"1\" k3=\"1\" k4=\"0\" "
 				     "color-interpolation-filters=\"sRGB\"/>\n"
 				     "</filter>\n",
 				     filter_id,
-				     source_composing_group_id,
-				     destination_composing_group_id);
+				     source_compositing_group_id,
+				     destination_compositing_group_id);
 	break;
     case CAIRO_SVG_FILTER_MULTIPLY:
 	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("multiply");
@@ -2504,9 +2504,18 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
     cairo_svg_document_t *document = surface->document;
 
     if (op == CAIRO_OPERATOR_CLEAR) {
+        /*
+         * The result is the same as one of the SOURCE operation application with the same arguments,
+         * but with an empty source.
+         */
+
 	status = _cairo_output_stream_destroy (source_stream);
 	if (unlikely (status)) {
+	    cairo_status_t ignore1 = _cairo_output_stream_destroy (destination_stream);
+	    cairo_status_t ignore2 = _cairo_output_stream_destroy (mask_stream);
 	    return status;
+	    (void) ignore1;
+	    (void) ignore2;
 	}
 	return _cairo_svg_surface_do_operator (output,
 					       surface,
@@ -2518,10 +2527,27 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
     }
 
     if (op == CAIRO_OPERATOR_SOURCE) {
-	unsigned int lerp_composing_group_id = document->composing_group_id++;
+	/*
+	 * Below we use the "Bounded" equation with SOURCE as the operation from the "Clipping and masking" section
+	 * of https://cairographics.org/operators/:
+	 * result = source LEPR_(clip IN mask) destination
+	 *
+	 * It is equivalent to:
+	 * result = (source IN (clip IN mask)) ADD (destination IN (NOT (clip IN mask)))
+	 *
+	 * 1. We put the clip masked with the mask into the SVG group `lerp_compositing_group`.
+	 * 2. `positive_lerp_mask` is an SVG mask with `lerp_compositing_group`.
+	 * 3. `negative_lerp_mask` is an SVG mask with inverted `lerp_compositing_group`.
+	 * 5. We put the source masked with `positive_lerp_mask` into the SVG group `lerped_source_compositing_group`.
+	 * 6. We put the destination masked with `negative_lerp_mask` into
+	 *    the SVG group `lerped_destination_compositing_group`.
+	 * 7. The result is addition of `lerped_source_compositing_group` and `lerped_destination_compositing_group`.
+	 */
+
+	unsigned int lerp_compositing_group_id = document->compositing_group_id++;
 	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<g id=\"composing-group-%d\">\n",
-				     lerp_composing_group_id);
+				     "<g id=\"compositing-group-%d\">\n",
+				     lerp_compositing_group_id);
 	status = _cairo_svg_surface_set_clip (surface, document->xml_node_defs, clip);
 	if (unlikely (status)) {
 	    cairo_status_t ignore1 = _cairo_output_stream_destroy (destination_stream);
@@ -2544,20 +2570,31 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 	_cairo_svg_surface_reset_clip (surface);
 	_cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
 
-	unsigned int source_mask_id = document->mask_id++;
+	unsigned int positive_lerp_mask_id = document->mask_id++;
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     "<mask id=\"mask-%d\">\n",
+				     positive_lerp_mask_id);
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     "<use xlink:href=\"#compositing-group-%d\"/>\n",
+				     lerp_compositing_group_id);
+	_cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
+
+	unsigned int negative_lerp_mask_id = document->mask_id++;
 	_cairo_output_stream_printf (document->xml_node_defs,
 				     "<mask id=\"mask-%d\">\n",
-				     source_mask_id);
+				     negative_lerp_mask_id);
 	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<use xlink:href=\"#composing-group-%d\"/>\n",
-				     lerp_composing_group_id);
+				     "<use xlink:href=\"#compositing-group-%d\" filter=\"url(#filter-%s)\"/>\n",
+				     lerp_compositing_group_id,
+				     _cairo_svg_surface_emit_static_filter (document,
+									    CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA));
 	_cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
 
-	unsigned int source_composing_group_id = document->composing_group_id++;
+	unsigned int lerped_source_compositing_group_id = document->compositing_group_id++;
 	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<g id=\"composing-group-%d\" mask=\"url(#mask-%d)\">\n",
-				     source_composing_group_id,
-				     source_mask_id);
+				     "<g id=\"compositing-group-%d\" mask=\"url(#mask-%d)\">\n",
+				     lerped_source_compositing_group_id,
+				     positive_lerp_mask_id);
 	_cairo_memory_stream_copy (source_stream, document->xml_node_defs);
 	status = _cairo_output_stream_destroy (source_stream);
 	if (unlikely (status)) {
@@ -2567,22 +2604,11 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 	}
 	_cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
 
-	unsigned int destination_mask_id = document->mask_id++;
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<mask id=\"mask-%d\">\n",
-				     destination_mask_id);
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<use xlink:href=\"#composing-group-%d\" filter=\"url(#filter-%s)\"/>\n",
-				     lerp_composing_group_id,
-				     _cairo_svg_surface_emit_static_filter (document,
-									    CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA));
-	_cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
-
-	unsigned int destination_composing_group_id = document->composing_group_id++;
+	unsigned int lerped_destination_compositing_group_id = document->compositing_group_id++;
 	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<g id=\"composing-group-%d\" mask=\"url(#mask-%d)\">\n",
-				     destination_composing_group_id,
-				     destination_mask_id);
+				     "<g id=\"compositing-group-%d\" mask=\"url(#mask-%d)\">\n",
+				     lerped_destination_compositing_group_id,
+				     negative_lerp_mask_id);
 	_cairo_memory_stream_copy (destination_stream, document->xml_node_defs);
 	status = _cairo_output_stream_destroy (destination_stream);
 	if (unlikely (status)) {
@@ -2594,8 +2620,8 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 				     "<g filter=\"url(#filter-%d)\">\n",
 				     _cairo_svg_surface_emit_parametric_filter (document,
 										CAIRO_SVG_FILTER_ADD,
-										source_composing_group_id,
-										destination_composing_group_id));
+										lerped_source_compositing_group_id,
+										lerped_destination_compositing_group_id));
 	status = _cairo_svg_surface_emit_paint (surface->xml_node, surface, &_cairo_pattern_black.base, NULL);
 	if (unlikely (status)) {
 	    return status;
@@ -2606,6 +2632,10 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
     }
 
     if (op == CAIRO_OPERATOR_DEST) {
+        /*
+         * The result is the destination.
+         */
+
 	_cairo_memory_stream_copy (destination_stream, surface->xml_node);
 	status = _cairo_output_stream_destroy (destination_stream);
 	if (unlikely (status)) {
@@ -2628,10 +2658,31 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 	return CAIRO_STATUS_SUCCESS;
     }
 
-    unsigned int lerp_composing_group_id = document->composing_group_id++;
+    /*
+     * Below we use the "XRender" equation from the "Clipping and masking" section
+     * of https://cairographics.org/operators/:
+     *
+     * It is equivalent to:
+     * result = (((source IN mask) OP destination) IN clip) ADD (destination IN (NOT clip))
+     *
+     * 1. We put the clip into the SVG group `lerp_compositing_group`.
+     * 2. `positive_lerp_mask` is an SVG mask with `lerp_compositing_group`.
+     * 3. `negative_lerp_mask` is an SVG mask with inverted `lerp_compositing_group`.
+     * 4. We put the mask into the SVG mask `mask_mask`.
+     * 5. We put the source masked with `mask_mask` into the SVG group `masked_source_compositing_group`.
+     * 6. We put the destination into the SVG group `destination_compositing_group`.
+     * 7. `lerped_operation_compositing_group` is an SVG group of operation applied to
+     *    (`masked_source_compositing_group`, `destination_compositing_group`)
+     *    masked with `positive_lerp_mask`.
+     * 8. `lerped_destination_compositing_group` is an SVG group of `destination_compositing_group`
+     *    masked with `negative_lerp_mask`.
+     * 9. The result is addition of `lerped_operation_compositing_group` and `lerped_destination_compositing_group`.
+     */
+
+    unsigned int lerp_compositing_group_id = document->compositing_group_id++;
     _cairo_output_stream_printf (document->xml_node_defs,
-				 "<g id=\"composing-group-%d\">\n",
-				 lerp_composing_group_id);
+				 "<g id=\"compositing-group-%d\">\n",
+				 lerp_compositing_group_id);
     status = _cairo_svg_surface_set_clip (surface, document->xml_node_defs, clip);
     if (unlikely (status)) {
 	cairo_status_t ignore1 = _cairo_output_stream_destroy (destination_stream);
@@ -2655,6 +2706,26 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
     _cairo_svg_surface_reset_clip (surface);
     _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
 
+    unsigned int positive_lerp_mask_id = document->mask_id++;
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<mask id=\"mask-%d\">\n",
+				 positive_lerp_mask_id);
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<use xlink:href=\"#compositing-group-%d\"/>\n",
+				 lerp_compositing_group_id);
+    _cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
+
+    unsigned int negative_lerp_mask_id = document->mask_id++;
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<mask id=\"mask-%d\">\n",
+				 negative_lerp_mask_id);
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<use xlink:href=\"#compositing-group-%d\" filter=\"url(#filter-%s)\"/>\n",
+				 lerp_compositing_group_id,
+				 _cairo_svg_surface_emit_static_filter (document,
+									CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA));
+    _cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
+
     unsigned int mask_mask_id = document->mask_id++;
     _cairo_output_stream_printf (document->xml_node_defs,
 				 "<mask id=\"mask-%d\">\n",
@@ -2670,22 +2741,10 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
     }
     _cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
 
-    unsigned int source_mask_id = document->mask_id++;
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<mask id=\"mask-%d\">\n",
-				 source_mask_id);
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<use xlink:href=\"#composing-group-%d\"/>\n",
-				 lerp_composing_group_id);
-    _cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
-
-    unsigned int source_composing_group_id = document->composing_group_id++;
+    unsigned int masked_source_compositing_group_id = document->compositing_group_id++;
     _cairo_output_stream_printf (document->xml_node_defs,
-				 "<g id=\"composing-group-%d\" mask=\"url(#mask-%d)\">\n",
-				 source_composing_group_id,
-				 source_mask_id);
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<g mask=\"url(#mask-%d)\">\n",
+				 "<g id=\"compositing-group-%d\" mask=\"url(#mask-%d)\">\n",
+				 masked_source_compositing_group_id,
 				 mask_mask_id);
     _cairo_memory_stream_copy (source_stream, document->xml_node_defs);
     status = _cairo_output_stream_destroy (source_stream);
@@ -2695,23 +2754,11 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 	(void) ignore;
     }
     _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
-    _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
-
-    unsigned int destination_mask_id = document->mask_id++;
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<mask id=\"mask-%d\">\n",
-				 destination_mask_id);
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<use xlink:href=\"#composing-group-%d\" filter=\"url(#filter-%s)\"/>\n",
-				 lerp_composing_group_id,
-				 _cairo_svg_surface_emit_static_filter (document,
-									CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA));
-    _cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
 
-    unsigned int raw_destination_composing_group_id = document->composing_group_id++;
+    unsigned int destination_compositing_group_id = document->compositing_group_id++;
     _cairo_output_stream_printf (document->xml_node_defs,
-				 "<g id=\"composing-group-%d\">\n",
-				 raw_destination_composing_group_id);
+				 "<g id=\"compositing-group-%d\">\n",
+				 destination_compositing_group_id);
     _cairo_memory_stream_copy (destination_stream, document->xml_node_defs);
     status = _cairo_output_stream_destroy (destination_stream);
     if (unlikely (status)) {
@@ -2719,192 +2766,193 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
     }
     _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
 
-    unsigned int destination_composing_group_id = document->composing_group_id++;
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<g id=\"composing-group-%d\" mask=\"url(#mask-%d)\">\n",
-				 destination_composing_group_id,
-				 destination_mask_id);
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<use xlink:href=\"#composing-group-%d\"/>\n",
-				 raw_destination_composing_group_id);
-    _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
-
-    unsigned int operation_composing_group_id = document->composing_group_id++;
+    unsigned int lerped_operation_compositing_group_id = document->compositing_group_id++;
     _cairo_output_stream_printf (document->xml_node_defs,
-				 "<g id=\"composing-group-%d\" ",
-				 operation_composing_group_id);
-    unsigned int filer_id;
+				 "<g id=\"compositing-group-%d\" ",
+				 lerped_operation_compositing_group_id);
+    unsigned int filter_id;
     switch (op) {
     case CAIRO_OPERATOR_CLEAR:
     case CAIRO_OPERATOR_SOURCE:
     case CAIRO_OPERATOR_OVER:
 	ASSERT_NOT_REACHED;
     case CAIRO_OPERATOR_IN:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_IN,
-							      source_composing_group_id,
-							      raw_destination_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_IN,
+							       masked_source_compositing_group_id,
+							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_OUT:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_OUT,
-							      source_composing_group_id,
-							      raw_destination_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_OUT,
+							       masked_source_compositing_group_id,
+							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_ATOP:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_ATOP,
-							      source_composing_group_id,
-							      raw_destination_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_ATOP,
+							       masked_source_compositing_group_id,
+							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_DEST:
 	ASSERT_NOT_REACHED;
     case CAIRO_OPERATOR_DEST_OVER:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_OVER,
-							      raw_destination_composing_group_id,
-							      source_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_OVER,
+							       destination_compositing_group_id,
+							       masked_source_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_DEST_IN:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_IN,
-							      raw_destination_composing_group_id,
-							      source_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_IN,
+							       destination_compositing_group_id,
+							       masked_source_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_DEST_OUT:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_OUT,
-							      raw_destination_composing_group_id,
-							      source_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_OUT,
+							       destination_compositing_group_id,
+							       masked_source_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_DEST_ATOP:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_ATOP,
-							      raw_destination_composing_group_id,
-							      source_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_ATOP,
+							       destination_compositing_group_id,
+							       masked_source_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_XOR:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_XOR,
-							      source_composing_group_id,
-							      raw_destination_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_XOR,
+							       masked_source_compositing_group_id,
+							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_ADD:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_ADD,
-							      source_composing_group_id,
-							      raw_destination_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_ADD,
+							       masked_source_compositing_group_id,
+							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_SATURATE:
 	ASSERT_NOT_REACHED;
     case CAIRO_OPERATOR_MULTIPLY:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_MULTIPLY,
-							      source_composing_group_id,
-							      raw_destination_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_MULTIPLY,
+							       masked_source_compositing_group_id,
+							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_SCREEN:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_SCREEN,
-							      source_composing_group_id,
-							      raw_destination_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_SCREEN,
+							       masked_source_compositing_group_id,
+							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_OVERLAY:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_OVERLAY,
-							      source_composing_group_id,
-							      raw_destination_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_OVERLAY,
+							       masked_source_compositing_group_id,
+							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_DARKEN:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_DARKEN,
-							      source_composing_group_id,
-							      raw_destination_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_DARKEN,
+							       masked_source_compositing_group_id,
+							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_LIGHTEN:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_LIGHTEN,
-							      source_composing_group_id,
-							      raw_destination_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_LIGHTEN,
+							       masked_source_compositing_group_id,
+							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_COLOR_DODGE:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_COLOR_DODGE,
-							      source_composing_group_id,
-							      raw_destination_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_COLOR_DODGE,
+							       masked_source_compositing_group_id,
+							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_COLOR_BURN:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_COLOR_BURN,
-							      source_composing_group_id,
-							      raw_destination_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_COLOR_BURN,
+							       masked_source_compositing_group_id,
+							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_HARD_LIGHT:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_HARD_LIGHT,
-							      source_composing_group_id,
-							      raw_destination_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_HARD_LIGHT,
+							       masked_source_compositing_group_id,
+							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_SOFT_LIGHT:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_SOFT_LIGHT,
-							      source_composing_group_id,
-							      raw_destination_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_SOFT_LIGHT,
+							       masked_source_compositing_group_id,
+							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_DIFFERENCE:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_DIFFERENCE,
-							      source_composing_group_id,
-							      raw_destination_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_DIFFERENCE,
+							       masked_source_compositing_group_id,
+							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_EXCLUSION:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_EXCLUSION,
-							      source_composing_group_id,
-							      raw_destination_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_EXCLUSION,
+							       masked_source_compositing_group_id,
+							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_HSL_HUE:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_HUE,
-							      source_composing_group_id,
-							      raw_destination_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_HUE,
+							       masked_source_compositing_group_id,
+							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_HSL_SATURATION:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_SATURATION,
-							      source_composing_group_id,
-							      raw_destination_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_SATURATION,
+							       masked_source_compositing_group_id,
+							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_HSL_COLOR:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_COLOR,
-							      source_composing_group_id,
-							      raw_destination_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_COLOR,
+							       masked_source_compositing_group_id,
+							       destination_compositing_group_id);
 	break;
     case CAIRO_OPERATOR_HSL_LUMINOSITY:
-	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
-							      CAIRO_SVG_FILTER_LUMINOSITY,
-							      source_composing_group_id,
-							      raw_destination_composing_group_id);
+	filter_id = _cairo_svg_surface_emit_parametric_filter (document,
+							       CAIRO_SVG_FILTER_LUMINOSITY,
+							       masked_source_compositing_group_id,
+							       destination_compositing_group_id);
 	break;
     default:
 	ASSERT_NOT_REACHED;
     }
     _cairo_output_stream_printf (document->xml_node_defs,
-				 "filter=\"url(#filter-%d)\">\n",
-				 filer_id);
+				 "filter=\"url(#filter-%d)\" mask=\"url(#mask-%d)\">\n",
+				 filter_id,
+				 positive_lerp_mask_id);
     status = _cairo_svg_surface_emit_paint (document->xml_node_defs, surface, &_cairo_pattern_black.base, NULL);
     if (unlikely (status)) {
 	return status;
     }
     _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
 
+    unsigned int lerped_destination_compositing_group_id = document->compositing_group_id++;
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<g id=\"compositing-group-%d\" mask=\"url(#mask-%d)\">\n",
+				 lerped_destination_compositing_group_id,
+				 negative_lerp_mask_id);
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<use xlink:href=\"#compositing-group-%d\"/>\n",
+				 destination_compositing_group_id);
+    _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
+
     _cairo_output_stream_printf (surface->xml_node,
 				 "<g filter=\"url(#filter-%d)\">\n",
 				 _cairo_svg_surface_emit_parametric_filter (document,
 									    CAIRO_SVG_FILTER_ADD,
-									    operation_composing_group_id,
-									    destination_composing_group_id));
+									    lerped_operation_compositing_group_id,
+									    lerped_destination_compositing_group_id));
     status = _cairo_svg_surface_emit_paint (surface->xml_node, surface, &_cairo_pattern_black.base, NULL);
     if (unlikely (status)) {
 	return status;
@@ -3534,7 +3582,7 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream,
     document->pattern_id = 0;
     document->clip_id = 0;
     document->mask_id = 0;
-    document->composing_group_id = 0;
+    document->compositing_group_id = 0;
     document->filter_id = 0;
 
     for (enum cairo_svg_filter filter = 0; filter < CAIRO_SVG_FILTER_LAST_STATIC_FILTER; filter++) {
@@ -3628,11 +3676,7 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
 	_cairo_memory_stream_length (document->xml_node_glyphs) > 0 ||
 	_cairo_memory_stream_length (document->xml_node_defs) > 0) {
 	_cairo_output_stream_printf (output, "<defs>\n");
-	if (_cairo_memory_stream_length (document->xml_node_filters) > 0) {
-	    _cairo_output_stream_printf (output, "<g>\n");
-	    _cairo_memory_stream_copy (document->xml_node_filters, output);
-	    _cairo_output_stream_printf (output, "</g>\n");
-	}
+	_cairo_memory_stream_copy (document->xml_node_filters, output);
 	if (_cairo_memory_stream_length (document->xml_node_glyphs) > 0) {
 	    _cairo_output_stream_printf (output, "<g>\n");
 	    _cairo_memory_stream_copy (document->xml_node_glyphs, output);
commit b5baac736f923bcabd59b5cb160eed7029feffef
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sat Apr 10 20:13:10 2021 +0200

    Do not create temporary single-color patterns. Also, do not try to support CAIRO_CONTENT_COLOR

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index e6103e05b..0cab2724a 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -218,9 +218,6 @@ _cairo_svg_surface_create_for_stream_internal (cairo_output_stream_t	*stream,
 					       double			 height,
 					       cairo_svg_version_t	 version);
 
-static cairo_status_t
-_cairo_svg_surface_emit_paint_black (cairo_svg_surface_t *surface);
-
 static const cairo_surface_backend_t cairo_svg_surface_backend;
 static const cairo_paginated_surface_backend_t cairo_svg_surface_paginated_backend;
 
@@ -719,12 +716,6 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t	*document,
 
     _cairo_array_init (&surface->page_set, sizeof (cairo_svg_page_t));
 
-    if (content == CAIRO_CONTENT_COLOR) {
-	status = _cairo_svg_surface_emit_paint_black (surface);
-	if (unlikely (status))
-	    goto CLEANUP;
-    }
-
     surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
     surface->force_fallbacks = FALSE;
     surface->content = content;
@@ -2517,16 +2508,13 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 	if (unlikely (status)) {
 	    return status;
 	}
-	cairo_pattern_t *transparent_pattern = cairo_pattern_create_rgba (0.0, 0.0, 0.0, 0.0);
-	status = _cairo_svg_surface_do_operator (output,
-						 surface,
-						 CAIRO_OPERATOR_SOURCE,
-						 clip,
-						 mask_stream,
-						 _cairo_memory_stream_create (),
-						 destination_stream);
-	cairo_pattern_destroy (transparent_pattern);
-	return status;
+	return _cairo_svg_surface_do_operator (output,
+					       surface,
+					       CAIRO_OPERATOR_SOURCE,
+					       clip,
+					       mask_stream,
+					       _cairo_memory_stream_create (),
+					       destination_stream);
     }
 
     if (op == CAIRO_OPERATOR_SOURCE) {
@@ -2608,7 +2596,7 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 										CAIRO_SVG_FILTER_ADD,
 										source_composing_group_id,
 										destination_composing_group_id));
-	status = _cairo_svg_surface_emit_paint_black (surface);
+	status = _cairo_svg_surface_emit_paint (surface->xml_node, surface, &_cairo_pattern_black.base, NULL);
 	if (unlikely (status)) {
 	    return status;
 	}
@@ -2654,9 +2642,7 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 	(void) ignore2;
 	(void) ignore3;
     }
-    cairo_pattern_t *white_pattern = cairo_pattern_create_rgb (1.0, 1.0, 1.0);
-    status = _cairo_svg_surface_emit_paint (document->xml_node_defs, surface, white_pattern, NULL);
-    cairo_pattern_destroy (white_pattern);
+    status = _cairo_svg_surface_emit_paint (document->xml_node_defs, surface, &_cairo_pattern_white.base, NULL);
     if (unlikely (status)) {
 	cairo_status_t ignore1 = _cairo_output_stream_destroy (destination_stream);
 	cairo_status_t ignore2 = _cairo_output_stream_destroy (source_stream);
@@ -2907,9 +2893,7 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
     _cairo_output_stream_printf (document->xml_node_defs,
 				 "filter=\"url(#filter-%d)\">\n",
 				 filer_id);
-    cairo_pattern_t *black_pattern = cairo_pattern_create_rgb (0.0, 0.0, 0.0);
-    status = _cairo_svg_surface_emit_paint (document->xml_node_defs, surface, black_pattern, NULL);
-    cairo_pattern_destroy (black_pattern);
+    status = _cairo_svg_surface_emit_paint (document->xml_node_defs, surface, &_cairo_pattern_black.base, NULL);
     if (unlikely (status)) {
 	return status;
     }
@@ -2921,7 +2905,7 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 									    CAIRO_SVG_FILTER_ADD,
 									    operation_composing_group_id,
 									    destination_composing_group_id));
-    status = _cairo_svg_surface_emit_paint_black (surface);
+    status = _cairo_svg_surface_emit_paint (surface->xml_node, surface, &_cairo_pattern_black.base, NULL);
     if (unlikely (status)) {
 	return status;
     }
@@ -2940,9 +2924,7 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
     } else { \
         _cairo_svg_surface_reset_clip (surface); \
         cairo_output_stream_t *mask_stream = _cairo_memory_stream_create (); \
-        cairo_pattern_t *white_pattern = cairo_pattern_create_rgb (1.0, 1.0, 1.0); \
-        status = OPERATOR_IMPL (mask_stream, surface, white_pattern, ## __VA_ARGS__); \
-        cairo_pattern_destroy (white_pattern); \
+        status = OPERATOR_IMPL (mask_stream, surface, &_cairo_pattern_white.base, ## __VA_ARGS__); \
         if (unlikely (status)) { \
             cairo_status_t ignore = _cairo_output_stream_destroy (mask_stream); \
             return status; \
@@ -3005,9 +2987,6 @@ _cairo_svg_surface_paint (void *abstract_surface,
 	    surface->xml_node = _cairo_memory_stream_create ();
 
 	    if (op == CAIRO_OPERATOR_CLEAR) {
-		if (surface->content == CAIRO_CONTENT_COLOR) {
-		    return _cairo_svg_surface_emit_paint_black (surface);
-		}
 		return CAIRO_STATUS_SUCCESS;
 	    }
 	    break;
@@ -3117,7 +3096,6 @@ _cairo_svg_surface_stroke_impl (cairo_output_stream_t *output,
     cairo_bool_t svg_clip_or_svg_mask_should_be_used = _cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (source);
     unsigned int mask_id;
     cairo_output_stream_t *output_stream = output;
-    cairo_pattern_t *white_pattern;
     if (svg_clip_or_svg_mask_should_be_used) {
 	mask_id = surface->document->mask_id++;
 
@@ -3126,14 +3104,13 @@ _cairo_svg_surface_stroke_impl (cairo_output_stream_t *output,
 	_cairo_output_stream_printf (output_stream,
 				     "<mask id=\"mask-%d\">\n",
 				     mask_id);
-
-	white_pattern = cairo_pattern_create_rgb (1.0, 1.0, 1.0);
     }
 
     _cairo_output_stream_printf (output_stream, "<path fill=\"none\"");
     status = _cairo_svg_surface_emit_stroke_style (output_stream,
 						   surface,
-						   svg_clip_or_svg_mask_should_be_used ? white_pattern : source,
+						   svg_clip_or_svg_mask_should_be_used ? &_cairo_pattern_white.base
+										       : source,
 						   stroke_style,
 						   ctm_inverse);
 
@@ -3147,8 +3124,6 @@ _cairo_svg_surface_stroke_impl (cairo_output_stream_t *output,
     _cairo_output_stream_printf (output_stream, "/>\n");
 
     if (svg_clip_or_svg_mask_should_be_used) {
-	cairo_pattern_destroy (white_pattern);
-
 	_cairo_output_stream_printf (output_stream, "</mask>\n");
 
 	_cairo_output_stream_printf (output,
@@ -3485,14 +3460,6 @@ _cairo_svg_surface_get_supported_mime_types (void	   *abstract_surface)
     return _cairo_svg_supported_mime_types;
 }
 
-static cairo_status_t
-_cairo_svg_surface_emit_paint_black (cairo_svg_surface_t *surface) {
-    cairo_pattern_t *black_pattern = cairo_pattern_create_rgb (0.0, 0.0, 0.0);
-    cairo_status_t status = _cairo_svg_surface_emit_paint (surface->xml_node, surface, black_pattern, NULL);
-    cairo_pattern_destroy(black_pattern);
-    return status;
-}
-
 static const cairo_surface_backend_t cairo_svg_surface_backend = {
 	CAIRO_SURFACE_TYPE_SVG,
 	_cairo_svg_surface_finish,
commit d88ac55b9ffb04cd5dd6ae76c3939f767ced9bbf
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sat Apr 10 19:49:50 2021 +0200

    Remove SVG 1.2 and CAIRO_CONTENT_COLOR SVG boilerplate targets

diff --git a/boilerplate/cairo-boilerplate-svg.c b/boilerplate/cairo-boilerplate-svg.c
index bbef30aed..bf9921d5a 100644
--- a/boilerplate/cairo-boilerplate-svg.c
+++ b/boilerplate/cairo-boilerplate-svg.c
@@ -127,24 +127,6 @@ _cairo_boilerplate_svg11_create_surface (const char		   *name,
 						  closure);
 }
 
-static cairo_surface_t *
-_cairo_boilerplate_svg12_create_surface (const char		   *name,
-					 cairo_content_t	    content,
-					 double 		    width,
-					 double 		    height,
-					 double 		    max_width,
-					 double 		    max_height,
-					 cairo_boilerplate_mode_t   mode,
-					 void			  **closure)
-{
-    return _cairo_boilerplate_svg_create_surface (name, content,
-						  CAIRO_SVG_VERSION_1_2,
-						  width, height,
-						  max_width, max_height,
-						  mode,
-						  closure);
-}
-
 static cairo_status_t
 _cairo_boilerplate_svg_finish_surface (cairo_surface_t *surface)
 {
@@ -315,45 +297,6 @@ static const cairo_boilerplate_target_t targets[] = {
 	_cairo_boilerplate_svg_cleanup,
 	NULL, NULL, FALSE, TRUE, TRUE
     },
-    {
-	"svg11", "svg", ".svg", NULL,
-	CAIRO_SURFACE_TYPE_RECORDING, CAIRO_CONTENT_COLOR, 1,
-	"cairo_svg_surface_create",
-	_cairo_boilerplate_svg11_create_surface,
-	cairo_surface_create_similar,
-	_cairo_boilerplate_svg_force_fallbacks,
-	_cairo_boilerplate_svg_finish_surface,
-	_cairo_boilerplate_svg_get_image_surface,
-	_cairo_boilerplate_svg_surface_write_to_png,
-	_cairo_boilerplate_svg_cleanup,
-	NULL, NULL, FALSE, TRUE, TRUE
-    },
-    {
-	"svg12", "svg", ".svg", NULL,
-	CAIRO_SURFACE_TYPE_SVG, CAIRO_CONTENT_COLOR_ALPHA, 1,
-	"cairo_svg_surface_create",
-	_cairo_boilerplate_svg12_create_surface,
-	cairo_surface_create_similar,
-	_cairo_boilerplate_svg_force_fallbacks,
-	_cairo_boilerplate_svg_finish_surface,
-	_cairo_boilerplate_svg_get_image_surface,
-	_cairo_boilerplate_svg_surface_write_to_png,
-	_cairo_boilerplate_svg_cleanup,
-	NULL, NULL, FALSE, TRUE, TRUE
-    },
-    {
-	"svg12", "svg", ".svg", NULL,
-	CAIRO_SURFACE_TYPE_RECORDING, CAIRO_CONTENT_COLOR, 1,
-	"cairo_svg_surface_create",
-	_cairo_boilerplate_svg12_create_surface,
-	cairo_surface_create_similar,
-	_cairo_boilerplate_svg_force_fallbacks,
-	_cairo_boilerplate_svg_finish_surface,
-	_cairo_boilerplate_svg_get_image_surface,
-	_cairo_boilerplate_svg_surface_write_to_png,
-	_cairo_boilerplate_svg_cleanup,
-	NULL, NULL, FALSE, TRUE, TRUE
-    },
 };
 CAIRO_BOILERPLATE (svg, targets)
 
commit 9ac707374fa3fc6029c4c33e2193fca0b50e4109
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sat Apr 10 18:39:18 2021 +0200

    Fix problems with radial gradients

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 71f8d1215..e6103e05b 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -1129,6 +1129,22 @@ _cairo_svg_surface_are_operation_and_pattern_supported (cairo_svg_surface_t *sur
 	return FALSE;
     }
 
+    /* SVG 1.1 does not support the focal point (fx, fy) that is outside of the circle defined by (cx, cy) and r. */
+    if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL) {
+	cairo_radial_pattern_t *radial_pattern = (cairo_radial_pattern_t *) pattern;
+	double max_radius;
+	if (radial_pattern->cd1.radius > radial_pattern->cd2.radius) {
+	    max_radius = radial_pattern->cd1.radius;
+	} else {
+	    max_radius = radial_pattern->cd2.radius;
+	}
+	cairo_point_double_t c1 = radial_pattern->cd1.center;
+	cairo_point_double_t c2 = radial_pattern->cd2.center;
+	if ((c1.x - c2.x) * (c1.x - c2.x) + (c1.y - c2.y) * (c1.y - c2.y) >= max_radius * max_radius) {
+	    return FALSE;
+	}
+    }
+
     /* SVG doesn't support extends reflect and pad for surface pattern */
     if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE && (pattern->extend != CAIRO_EXTEND_NONE &&
 							pattern->extend != CAIRO_EXTEND_REPEAT)) {
@@ -1959,7 +1975,7 @@ _cairo_svg_surface_emit_surface_pattern (cairo_svg_surface_t *surface,
 
 static cairo_status_t
 _cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t *output,
-				       cairo_gradient_pattern_t const *pattern,
+				       const cairo_gradient_pattern_t *pattern,
 				       double start_offset,
 				       cairo_bool_t reverse_stops,
 				       cairo_bool_t emulate_reflect)
@@ -1998,14 +2014,14 @@ _cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t *output,
 		stops[i] = pattern->stops[i];
 	    }
 	    if (emulate_reflect) {
-		stops[i].offset /= 2;
-		if (i > 0 && i < (pattern->n_stops - 1)) {
+		stops[i].offset *= 0.5;
+		if (i > 0 && i < pattern->n_stops - 1) {
 		    if (reverse_stops) {
 			stops[i + pattern->n_stops - 1] = pattern->stops[i];
 			stops[i + pattern->n_stops - 1].offset = 0.5 + 0.5 * stops[i + pattern->n_stops - 1].offset;
 		    } else {
 			stops[i + pattern->n_stops - 1] = pattern->stops[pattern->n_stops - i - 1];
-			stops[i + pattern->n_stops - 1].offset = 1 - 0.5 * stops[i + pattern->n_stops - 1].offset;
+			stops[i + pattern->n_stops - 1].offset = 1.0 - 0.5 * stops[i + pattern->n_stops - 1].offset;
 		    }
 		}
 	    }
@@ -2021,7 +2037,7 @@ _cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t *output,
 					 "<stop offset=\"%f\" "
 					 "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
 					 "stop-opacity=\"%f\"/>\n",
-					 start_offset + (1 - start_offset) * stops[i].offset,
+					 start_offset + (1.0 - start_offset) * stops[i].offset,
 					 stops[i].color.red * 100.0,
 					 stops[i].color.green * 100.0,
 					 stops[i].color.blue * 100.0,
@@ -2032,14 +2048,14 @@ _cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t *output,
 	unsigned int offset_index;
 	cairo_color_stop_t offset_color_start, offset_color_stop;
 
-	for (unsigned int i = 0; i < n_stops; i++) {
-	    if (stops[i].offset >= -start_offset) {
+	for (unsigned int i = 0; i <= n_stops; i++) {
+	    double x1 = i == n_stops ? stops[0].offset + 1 : stops[i].offset;
+	    cairo_color_stop_t *color1 = i == n_stops ? &stops[0].color : &stops[i].color;
+	    if (x1 >= -start_offset) {
 		if (i > 0) {
-		    if (stops[i].offset != stops[i - 1].offset) {
-			double x0 = stops[i - 1].offset;
-			double x1 = stops[i].offset;
-			cairo_color_stop_t *color0 = &stops[i - 1].color;
-			cairo_color_stop_t *color1 = &stops[i].color;
+		    double x0 = stops[i - 1].offset;
+		    cairo_color_stop_t *color0 = &stops[i - 1].color;
+		    if (x0 != x1) {
 			offset_color_start.red = color0->red + (color1->red - color0->red)
 							       * (-start_offset - x0) / (x1 - x0);
 			offset_color_start.green = color0->green + (color1->green - color0->green)
@@ -2219,136 +2235,93 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface,
 
     unsigned int radial_pattern_id = document->radial_pattern_id++;
 
-    if (r0 == r1) {
-	unsigned int n_stops = pattern->base.n_stops;
+    double start_offset;
+    cairo_bool_t emulate_reflect = FALSE;
+
+    double fx = (r1 * x0 - r0 * x1) / (r1 - r0);
+    double fy = (r1 * y0 - r0 * y1) / (r1 - r0);
+
+    /* SVG doesn't support the inner circle and use instead a gradient focal.
+     * That means we need to emulate the cairo behaviour by processing the
+     * cairo gradient stops.
+     * The CAIRO_EXTEND_NONE and CAIRO_EXTEND_PAD modes are quite easy to handle,
+     * it's just a matter of stop position translation and calculation of
+     * the corresponding SVG radial gradient focal.
+     * The CAIRO_EXTEND_REFLECT and CAIRO_EXTEND_REPEAT modes require to compute a new
+     * radial gradient, with an new outer circle, equal to r1 - r0 in the CAIRO_EXTEND_REPEAT
+     * case, and 2 * r1 - r0 in the CAIRO_EXTEND_REFLECT case, and a new gradient stop
+     * list that maps to the original cairo stop list.
+     */
+    if ((extend == CAIRO_EXTEND_REFLECT || extend == CAIRO_EXTEND_REPEAT) && r0 > 0.0) {
+	double r_org = r1;
 
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<radialGradient id=\"radial-pattern-%d\" "
-				     "gradientUnits=\"userSpaceOnUse\" "
-				     "cx=\"%f\" cy=\"%f\" "
-				     "fx=\"%f\" fy=\"%f\" r=\"%f\" ",
-				     radial_pattern_id,
-				     x1, y1,
-				     x1, y1, r1);
-	_cairo_svg_surface_emit_transform (document->xml_node_defs,
-					   "gradientTransform",
-					   &p2u,
-					   parent_matrix);
-	_cairo_output_stream_printf (document->xml_node_defs, ">\n");
-
-	if (extend == CAIRO_EXTEND_NONE || n_stops < 1) {
-	    _cairo_output_stream_printf (document->xml_node_defs,
-					 "<stop offset=\"0\" "
-					 "stop-color=\"rgb(0%%, 0%%, 0%%)\" "
-					 "stop-opacity=\"0\"/>\n");
-	} else {
-	    _cairo_output_stream_printf (document->xml_node_defs,
-					 "<stop offset=\"0\" "
-					 "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
-					 "stop-opacity=\"%f\"/>\n",
-					 pattern->base.stops[0].color.red * 100.0,
-					 pattern->base.stops[0].color.green * 100.0,
-					 pattern->base.stops[0].color.blue * 100.0,
-					 pattern->base.stops[0].color.alpha);
-	    if (n_stops > 1) {
-		_cairo_output_stream_printf (document->xml_node_defs,
-					     "<stop offset=\"0\" "
-					     "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
-					     "stop-opacity=\"%f\"/>\n",
-					     pattern->base.stops[n_stops - 1].color.red * 100.0,
-					     pattern->base.stops[n_stops - 1].color.green * 100.0,
-					     pattern->base.stops[n_stops - 1].color.blue * 100.0,
-					     pattern->base.stops[n_stops - 1].color.alpha);
-	    }
+	if (extend == CAIRO_EXTEND_REFLECT) {
+	    r1 = 2.0 * r1 - r0;
+	    emulate_reflect = TRUE;
 	}
-    } else {
-	double offset, r, x, y;
-	cairo_bool_t emulate_reflect = FALSE;
-
-	double fx = (r1 * x0 - r0 * x1) / (r1 - r0);
-	double fy = (r1 * y0 - r0 * y1) / (r1 - r0);
-
-	/* SVG doesn't support the inner circle and use instead a gradient focal.
-	 * That means we need to emulate the cairo behaviour by processing the
-	 * cairo gradient stops.
-	 * The CAIRO_EXTEND_NONE and CAIRO_EXTEND_PAD modes are quite easy to handle,
-	 * it's just a matter of stop position translation and calculation of
-	 * the corresponding SVG radial gradient focal.
-	 * The CAIRO_EXTEND_REFLECT and CAIRO_EXTEND_REPEAT modes require to compute a new
-	 * radial gradient, with an new outer circle, equal to r1 - r0 in the CAIRO_EXTEND_REPEAT
-	 * case, and 2 * (r1 - r0) in the CAIRO_EXTEND_REFLECT case, and a new gradient stop
-	 * list that maps to the original cairo stop list.
-	 */
-	if ((extend == CAIRO_EXTEND_REFLECT || extend == CAIRO_EXTEND_REPEAT) && r0 > 0.0) {
-	    double r_org = r1;
-
-	    if (extend == CAIRO_EXTEND_REFLECT) {
-		r1 = 2 * r1 - r0;
-		emulate_reflect = TRUE;
-	    }
 
-	    offset = fmod (r1, r1 - r0) / (r1 - r0) - 1.0;
-	    r = r1 - r0;
+	start_offset = fmod (r1, r1 - r0) / (r1 - r0) - 1.0;
+	double r = r1 - r0;
 
-	    /* New position of outer circle. */
-	    x = r * (x1 - fx) / r_org + fx;
-	    y = r * (y1 - fy) / r_org + fy;
+	/* New position of outer circle. */
+	double x = r * (x1 - fx) / r_org + fx;
+	double y = r * (y1 - fy) / r_org + fy;
 
-	    x1 = x;
-	    y1 = y;
-	    r1 = r;
-	    r0 = 0.0;
-	} else {
-	    offset = r0 / r1;
-	}
+	x1 = x;
+	y1 = y;
+	r1 = r;
+	r0 = 0.0;
+    } else {
+	start_offset = r0 / r1;
+    }
 
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<radialGradient id=\"radial-pattern-%d\" "
-				     "gradientUnits=\"userSpaceOnUse\" "
-				     "cx=\"%f\" cy=\"%f\" "
-				     "fx=\"%f\" fy=\"%f\" r=\"%f\" ",
-				     radial_pattern_id,
-				     x1, y1,
-				     fx, fy, r1);
-
-	if (emulate_reflect) {
-	    _cairo_output_stream_printf (document->xml_node_defs, "spreadMethod=\"repeat\" ");
-	} else {
-	    _cairo_svg_surface_emit_pattern_extend (document->xml_node_defs, &pattern->base.base);
-	}
-	_cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u, parent_matrix);
-	_cairo_output_stream_printf (document->xml_node_defs, ">\n");
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<radialGradient id=\"radial-pattern-%d\" "
+				 "gradientUnits=\"userSpaceOnUse\" "
+				 "cx=\"%f\" cy=\"%f\" "
+				 "fx=\"%f\" fy=\"%f\" r=\"%f\"",
+				 radial_pattern_id,
+				 x1, y1,
+				 fx, fy, r1);
+
+    if (emulate_reflect) {
+	_cairo_output_stream_printf (document->xml_node_defs, " spreadMethod=\"repeat\"");
+    } else {
+	_cairo_svg_surface_emit_pattern_extend (document->xml_node_defs, &pattern->base.base);
+    }
+    _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u, parent_matrix);
+    _cairo_output_stream_printf (document->xml_node_defs, ">\n");
 
-	/* To support cairo's EXTEND_NONE, (for which SVG has no similar
-	 * notion), we add transparent color stops on either end of the
-	 * user-provided stops. */
-	if (extend == CAIRO_EXTEND_NONE) {
+    /* To support cairo's EXTEND_NONE, (for which SVG has no similar
+     * notion), we add transparent color stops on either end of the
+     * user-provided stops. */
+    if (extend == CAIRO_EXTEND_NONE) {
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     "<stop offset=\"0\" "
+				     "stop-color=\"rgb(0%%, 0%%, 0%%)\" "
+				     "stop-opacity=\"0\"/>\n");
+	if (r0 != 0.0) {
 	    _cairo_output_stream_printf (document->xml_node_defs,
-					 "<stop offset=\"0\" "
+					 "<stop offset=\"%f\" "
 					 "stop-color=\"rgb(0%%, 0%%, 0%%)\" "
-					 "stop-opacity=\"0\"/>\n");
-	    if (r0 != 0.0) {
-		_cairo_output_stream_printf (document->xml_node_defs,
-					     "<stop offset=\"%f\" "
-					     "stop-color=\"rgb(0%%, 0%%, 0%%)\" "
-					     "stop-opacity=\"0\"/>\n",
-					     r0 / r1);
-	    }
-	}
-	status = _cairo_svg_surface_emit_pattern_stops (document->xml_node_defs,
-							&pattern->base, offset,
-							reverse_stops,
-							emulate_reflect);
-	if (unlikely (status)) {
-	    return status;
+					 "stop-opacity=\"0\"/>\n",
+					 r0 / r1);
 	}
+    }
+    status = _cairo_svg_surface_emit_pattern_stops (document->xml_node_defs,
+						    &pattern->base,
+						    start_offset,
+						    reverse_stops,
+						    emulate_reflect);
+    if (unlikely (status)) {
+	return status;
+    }
 
-	if (pattern->base.base.extend == CAIRO_EXTEND_NONE) {
-	    _cairo_output_stream_printf (document->xml_node_defs,
-					 "<stop offset=\"1\" "
-					 "stop-color=\"rgb(0%%, 0%%, 0%%)\" "
-					 "stop-opacity=\"0\"/>\n");
-	}
+    if (pattern->base.base.extend == CAIRO_EXTEND_NONE) {
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     "<stop offset=\"1\" "
+				     "stop-color=\"rgb(0%%, 0%%, 0%%)\" "
+				     "stop-opacity=\"0\"/>\n");
     }
 
     _cairo_output_stream_printf (document->xml_node_defs,
commit d397ab6d10123e6bbcf9ae446cc8ffd981f18222
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sat Apr 10 00:45:20 2021 +0200

    Change the default SVG unit to user unit

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 430b50407..71f8d1215 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -39,7 +39,6 @@
  *	Carl Worth <cworth at cworth.org>
  */
 
-#define _DEFAULT_SOURCE /* for snprintf() */
 #include "cairoint.h"
 
 #include "cairo-svg.h"
@@ -460,7 +459,7 @@ cairo_svg_version_to_string (cairo_svg_version_t version)
  * creating the SVG surface.
  *
  * Note if this function is never called, the default unit for SVG documents
- * generated by cairo will be "pt". This is for historical reasons.
+ * generated by cairo will be user unit.
  *
  * Since: 1.16
  **/
@@ -3588,7 +3587,7 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream,
     document->finished = FALSE;
     document->width = width;
     document->height = height;
-    document->unit = CAIRO_SVG_UNIT_PT;
+    document->unit = CAIRO_SVG_UNIT_USER;
 
     document->linear_pattern_id = 0;
     document->radial_pattern_id = 0;
commit f85834a1f5760a6bbec57fd8d24f35653fd6f2de
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Sat Apr 10 00:32:30 2021 +0200

    Do not use the style attribute

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 28f00be8e..430b50407 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -616,10 +616,10 @@ _cairo_svg_surface_cliprect_covers_surface (cairo_svg_surface_t *surface,
 
 static cairo_status_t
 _cairo_svg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper,
-						cairo_path_fixed_t	*path,
-						cairo_fill_rule_t	 fill_rule,
-						double			 tolerance,
-						cairo_antialias_t	 antialias)
+						cairo_path_fixed_t *path,
+						cairo_fill_rule_t fill_rule,
+						double tolerance,
+						cairo_antialias_t antialias)
 {
     cairo_svg_surface_t *surface = cairo_container_of (clipper,
 						       cairo_svg_surface_t,
@@ -641,7 +641,7 @@ _cairo_svg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper
 
     _cairo_output_stream_printf (document->xml_node_defs,
 				 "<clipPath id=\"clip-%d\">\n"
-				 "<path ",
+				 "<path",
 				 document->clip_id);
     _cairo_svg_surface_emit_path (document->xml_node_defs, path, NULL);
 
@@ -844,22 +844,24 @@ _cairo_svg_surface_show_page (void *abstract_surface)
 
 static void
 _cairo_svg_surface_emit_transform (cairo_output_stream_t *output,
-				   char const		 *attribute_str,
-				   const cairo_matrix_t	 *object_matrix,
-				   const cairo_matrix_t  *parent_matrix)
+				   char const *attribute_name,
+				   const cairo_matrix_t *object_matrix,
+				   const cairo_matrix_t *parent_matrix)
 {
     cairo_matrix_t matrix = *object_matrix;
 
-    if (parent_matrix != NULL)
+    if (parent_matrix != NULL) {
 	cairo_matrix_multiply (&matrix, &matrix, parent_matrix);
+    }
 
-    if (!_cairo_matrix_is_identity (&matrix))
+    if (!_cairo_matrix_is_identity (&matrix)) {
 	_cairo_output_stream_printf (output,
-				     "%s=\"matrix(%f,%f,%f,%f,%f,%f)\"",
-				     attribute_str,
+				     " %s=\"matrix(%f, %f, %f, %f, %f, %f)\"",
+				     attribute_name,
 				     matrix.xx, matrix.yx,
 				     matrix.xy, matrix.yy,
 				     matrix.x0, matrix.y0);
+    }
 }
 
 typedef struct {
@@ -937,14 +939,14 @@ _cairo_svg_path_close_path (void *closure)
 }
 
 static void
-_cairo_svg_surface_emit_path (cairo_output_stream_t	*output,
-			      const cairo_path_fixed_t	*path,
-			      const cairo_matrix_t	*ctm_inverse)
+_cairo_svg_surface_emit_path (cairo_output_stream_t *output,
+			      const cairo_path_fixed_t *path,
+			      const cairo_matrix_t *ctm_inverse)
 {
     cairo_status_t status;
     svg_path_info_t info;
 
-    _cairo_output_stream_printf (output, "d=\"");
+    _cairo_output_stream_printf (output, " d=\"");
 
     info.output = output;
     info.ctm_inverse = ctm_inverse;
@@ -960,26 +962,27 @@ _cairo_svg_surface_emit_path (cairo_output_stream_t	*output,
 }
 
 static cairo_int_status_t
-_cairo_svg_document_emit_outline_glyph_data (cairo_svg_document_t	*document,
-					     cairo_scaled_font_t	*scaled_font,
-					     unsigned long		 glyph_index)
+_cairo_svg_document_emit_outline_glyph_data (cairo_svg_document_t *document,
+					     cairo_scaled_font_t *scaled_font,
+					     unsigned long glyph_index)
 {
     cairo_scaled_glyph_t *scaled_glyph;
     cairo_int_status_t status;
 
     status = _cairo_scaled_glyph_lookup (scaled_font,
 					 glyph_index,
-					 CAIRO_SCALED_GLYPH_INFO_METRICS|
-					 CAIRO_SCALED_GLYPH_INFO_PATH,
+					 CAIRO_SCALED_GLYPH_INFO_METRICS | CAIRO_SCALED_GLYPH_INFO_PATH,
 					 &scaled_glyph);
-    if (unlikely (status))
+    if (unlikely (status)) {
 	return status;
+    }
 
     _cairo_output_stream_printf (document->xml_node_glyphs,
-				 "<path ");
+				 "<path");
 
     _cairo_svg_surface_emit_path (document->xml_node_glyphs,
-				  scaled_glyph->path, NULL);
+				  scaled_glyph->path,
+				  NULL);
 
     _cairo_output_stream_printf (document->xml_node_glyphs,
 				 "/>\n");
@@ -1014,7 +1017,7 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t	*document,
 	return status;
 
     _cairo_output_stream_printf (document->xml_node_glyphs, "<g");
-    _cairo_svg_surface_emit_transform (document->xml_node_glyphs, " transform",
+    _cairo_svg_surface_emit_transform (document->xml_node_glyphs, "transform",
 				       &image->base.device_transform_inverse, NULL);
     _cairo_output_stream_printf (document->xml_node_glyphs, ">\n");
 
@@ -1660,7 +1663,7 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t   *outp
 				     extents.x, extents.y,
 				     extents.width, extents.height);
 	_cairo_svg_surface_emit_transform (output,
-					   " patternTransform",
+					   "patternTransform",
 					   &p2u, parent_matrix);
 	_cairo_output_stream_printf (output, ">\n");
     }
@@ -1678,7 +1681,7 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t   *outp
 
     if (pattern_id == invalid_pattern_id) {
 	_cairo_svg_surface_emit_transform (output,
-					   " transform",
+					   "transform",
 					   &p2u, parent_matrix);
     }
     _cairo_output_stream_printf (output, "/>\n");
@@ -1866,7 +1869,7 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t	*outp
 				     recording_surface->extents_pixels.y,
 				     recording_surface->extents_pixels.width,
 				     recording_surface->extents_pixels.height);
-	_cairo_svg_surface_emit_transform (output, " patternTransform", &p2u, parent_matrix);
+	_cairo_svg_surface_emit_transform (output, "patternTransform", &p2u, parent_matrix);
 	_cairo_output_stream_printf (output, ">\n");
     }
 
@@ -1875,7 +1878,7 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t	*outp
 				 source_id);
 
     if (pattern_id == invalid_pattern_id) {
-	_cairo_svg_surface_emit_transform (output, " transform", &p2u, parent_matrix);
+	_cairo_svg_surface_emit_transform (output, "transform", &p2u, parent_matrix);
     }
 
     _cairo_output_stream_printf (output, "/>\n");
@@ -1911,14 +1914,14 @@ _cairo_svg_surface_emit_composite_pattern (cairo_output_stream_t   *output,
 }
 
 static cairo_status_t
-_cairo_svg_surface_emit_solid_pattern (cairo_svg_surface_t    *surface,
-				       cairo_solid_pattern_t  *pattern,
-				       cairo_output_stream_t  *style,
-				       cairo_bool_t	       is_stroke)
-{
-    _cairo_output_stream_printf (style, is_stroke ?
-				 "stroke:rgb(%f%%,%f%%,%f%%);stroke-opacity:%f;":
-				 "fill:rgb(%f%%,%f%%,%f%%);fill-opacity:%f;",
+_cairo_svg_surface_emit_solid_pattern (cairo_svg_surface_t *surface,
+				       cairo_solid_pattern_t *pattern,
+				       cairo_output_stream_t *output,
+				       cairo_bool_t is_stroke)
+{
+    _cairo_output_stream_printf (output,
+				 is_stroke ? " stroke=\"rgb(%f%%, %f%%, %f%%)\" stroke-opacity=\"%f\""
+					   : " fill=\"rgb(%f%%, %f%%, %f%%)\" fill-opacity=\"%f\"",
 				 pattern->color.red * 100.0,
 				 pattern->color.green * 100.0,
 				 pattern->color.blue * 100.0,
@@ -1928,11 +1931,11 @@ _cairo_svg_surface_emit_solid_pattern (cairo_svg_surface_t    *surface,
 }
 
 static cairo_status_t
-_cairo_svg_surface_emit_surface_pattern (cairo_svg_surface_t	 *surface,
+_cairo_svg_surface_emit_surface_pattern (cairo_svg_surface_t *surface,
 					 cairo_surface_pattern_t *pattern,
-					 cairo_output_stream_t   *style,
-					 cairo_bool_t		  is_stroke,
-					 const cairo_matrix_t	 *parent_matrix)
+					 cairo_output_stream_t *output,
+					 cairo_bool_t is_stroke,
+					 const cairo_matrix_t *parent_matrix)
 {
     cairo_svg_document_t *document = surface->document;
     cairo_status_t status;
@@ -1940,70 +1943,70 @@ _cairo_svg_surface_emit_surface_pattern (cairo_svg_surface_t	 *surface,
     unsigned int pattern_id = document->pattern_id++;
 
     status = _cairo_svg_surface_emit_composite_pattern (document->xml_node_defs,
-	                                                surface, pattern,
-							pattern_id, parent_matrix);
+							surface,
+							pattern,
+							pattern_id,
+							parent_matrix);
     if (unlikely (status))
 	return status;
 
-    _cairo_output_stream_printf (style,
-				 "%s:url(#pattern-%d);",
-				 is_stroke ? "stroke" : "fill",
+    _cairo_output_stream_printf (output,
+				 is_stroke ? " stroke=\"url(#pattern-%d)\""
+					   : " fill=\"url(#pattern-%d)\"",
 				 pattern_id);
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
-_cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t          *output,
+_cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t *output,
 				       cairo_gradient_pattern_t const *pattern,
-				       double			       start_offset,
-				       cairo_bool_t		       reverse_stops,
-				       cairo_bool_t		       emulate_reflect)
+				       double start_offset,
+				       cairo_bool_t reverse_stops,
+				       cairo_bool_t emulate_reflect)
 {
     cairo_gradient_stop_t *stops;
-    double offset;
     unsigned int n_stops;
-    unsigned int i;
 
-    if (pattern->n_stops < 1)
+    if (pattern->n_stops < 1) {
 	return CAIRO_STATUS_SUCCESS;
+    }
 
     if (pattern->n_stops == 1) {
-	    _cairo_output_stream_printf (output,
-					 "<stop offset=\"%f\" style=\""
-					 "stop-color:rgb(%f%%,%f%%,%f%%);"
-					 "stop-opacity:%f;\"/>\n",
-					 pattern->stops[0].offset,
-					 pattern->stops[0].color.red   * 100.0,
-					 pattern->stops[0].color.green * 100.0,
-					 pattern->stops[0].color.blue  * 100.0,
-					 pattern->stops[0].color.alpha);
-	    return CAIRO_STATUS_SUCCESS;
+	_cairo_output_stream_printf (output,
+				     "<stop offset=\"%f\" "
+				     "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
+				     "stop-opacity=\"%f\"/>\n",
+				     pattern->stops[0].offset,
+				     pattern->stops[0].color.red * 100.0,
+				     pattern->stops[0].color.green * 100.0,
+				     pattern->stops[0].color.blue * 100.0,
+				     pattern->stops[0].color.alpha);
+	return CAIRO_STATUS_SUCCESS;
     }
 
     if (emulate_reflect || reverse_stops) {
-	n_stops = emulate_reflect ? pattern->n_stops * 2 - 2: pattern->n_stops;
+	n_stops = emulate_reflect ? pattern->n_stops * 2 - 2 : pattern->n_stops;
 	stops = _cairo_malloc_ab (n_stops, sizeof (cairo_gradient_stop_t));
 	if (unlikely (stops == NULL))
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-	for (i = 0; i < pattern->n_stops; i++) {
+	for (unsigned int i = 0; i < pattern->n_stops; i++) {
 	    if (reverse_stops) {
 		stops[i] = pattern->stops[pattern->n_stops - i - 1];
 		stops[i].offset = 1.0 - stops[i].offset;
-	    } else
+	    } else {
 		stops[i] = pattern->stops[i];
+	    }
 	    if (emulate_reflect) {
 		stops[i].offset /= 2;
 		if (i > 0 && i < (pattern->n_stops - 1)) {
 		    if (reverse_stops) {
 			stops[i + pattern->n_stops - 1] = pattern->stops[i];
-			stops[i + pattern->n_stops - 1].offset =
-			    0.5 + 0.5 * stops[i + pattern->n_stops - 1].offset;
+			stops[i + pattern->n_stops - 1].offset = 0.5 + 0.5 * stops[i + pattern->n_stops - 1].offset;
 		    } else {
 			stops[i + pattern->n_stops - 1] = pattern->stops[pattern->n_stops - i - 1];
-			stops[i + pattern->n_stops - 1].offset =
-			    1 - 0.5 * stops[i + pattern->n_stops - 1].offset;
+			stops[i + pattern->n_stops - 1].offset = 1 - 0.5 * stops[i + pattern->n_stops - 1].offset;
 		    }
 		}
 	    }
@@ -2013,53 +2016,50 @@ _cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t          *output,
 	stops = pattern->stops;
     }
 
-    if (start_offset >= 0.0)
-	for (i = 0; i < n_stops; i++) {
-	    offset = start_offset + (1 - start_offset ) * stops[i].offset;
+    if (start_offset >= 0.0) {
+	for (unsigned int i = 0; i < n_stops; i++) {
 	    _cairo_output_stream_printf (output,
-					 "<stop offset=\"%f\" style=\""
-					 "stop-color:rgb(%f%%,%f%%,%f%%);"
-					 "stop-opacity:%f;\"/>\n",
-					 offset,
-					 stops[i].color.red   * 100.0,
+					 "<stop offset=\"%f\" "
+					 "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
+					 "stop-opacity=\"%f\"/>\n",
+					 start_offset + (1 - start_offset) * stops[i].offset,
+					 stops[i].color.red * 100.0,
 					 stops[i].color.green * 100.0,
-					 stops[i].color.blue  * 100.0,
+					 stops[i].color.blue * 100.0,
 					 stops[i].color.alpha);
 	}
-    else {
+    } else {
 	cairo_bool_t found = FALSE;
 	unsigned int offset_index;
 	cairo_color_stop_t offset_color_start, offset_color_stop;
 
-	for (i = 0; i < n_stops; i++) {
+	for (unsigned int i = 0; i < n_stops; i++) {
 	    if (stops[i].offset >= -start_offset) {
 		if (i > 0) {
-		    if (stops[i].offset != stops[i-1].offset) {
-			double x0, x1;
-			cairo_color_stop_t *color0, *color1;
-
-			x0 = stops[i-1].offset;
-			x1 = stops[i].offset;
-			color0 = &stops[i-1].color;
-			color1 = &stops[i].color;
+		    if (stops[i].offset != stops[i - 1].offset) {
+			double x0 = stops[i - 1].offset;
+			double x1 = stops[i].offset;
+			cairo_color_stop_t *color0 = &stops[i - 1].color;
+			cairo_color_stop_t *color1 = &stops[i].color;
 			offset_color_start.red = color0->red + (color1->red - color0->red)
-			    * (-start_offset - x0) / (x1 - x0);
+							       * (-start_offset - x0) / (x1 - x0);
 			offset_color_start.green = color0->green + (color1->green - color0->green)
-			    * (-start_offset - x0) / (x1 - x0);
+								   * (-start_offset - x0) / (x1 - x0);
 			offset_color_start.blue = color0->blue + (color1->blue - color0->blue)
-			    * (-start_offset - x0) / (x1 - x0);
+								 * (-start_offset - x0) / (x1 - x0);
 			offset_color_start.alpha = color0->alpha + (color1->alpha - color0->alpha)
-			    * (-start_offset - x0) / (x1 - x0);
+								   * (-start_offset - x0) / (x1 - x0);
 			offset_color_stop = offset_color_start;
 		    } else {
-			offset_color_stop = stops[i-1].color;
+			offset_color_stop = stops[i - 1].color;
 			offset_color_start = stops[i].color;
 		    }
-		} else
-			offset_color_stop = offset_color_start = stops[i].color;
-	    offset_index = i;
-	    found = TRUE;
-	    break;
+		} else {
+		    offset_color_stop = offset_color_start = stops[i].color;
+		}
+		offset_index = i;
+		found = TRUE;
+		break;
 	    }
 	}
 
@@ -2069,135 +2069,133 @@ _cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t          *output,
 	}
 
 	_cairo_output_stream_printf (output,
-				     "<stop offset=\"0\" style=\""
-				     "stop-color:rgb(%f%%,%f%%,%f%%);"
-				     "stop-opacity:%f;\"/>\n",
-				     offset_color_start.red   * 100.0,
+				     "<stop offset=\"0\" "
+				     "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
+				     "stop-opacity=\"%f\"/>\n",
+				     offset_color_start.red * 100.0,
 				     offset_color_start.green * 100.0,
-				     offset_color_start.blue  * 100.0,
+				     offset_color_start.blue * 100.0,
 				     offset_color_start.alpha);
-	for (i = offset_index; i < n_stops; i++) {
+	for (unsigned int i = offset_index; i < n_stops; i++) {
 	    _cairo_output_stream_printf (output,
-					 "<stop offset=\"%f\" style=\""
-					 "stop-color:rgb(%f%%,%f%%,%f%%);"
-					 "stop-opacity:%f;\"/>\n",
+					 "<stop offset=\"%f\" "
+					 "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
+					 "stop-opacity=\"%f\"/>\n",
 					 stops[i].offset + start_offset,
-					 stops[i].color.red   * 100.0,
+					 stops[i].color.red * 100.0,
 					 stops[i].color.green * 100.0,
-					 stops[i].color.blue  * 100.0,
+					 stops[i].color.blue * 100.0,
 					 stops[i].color.alpha);
 	}
-	for (i = 0; i < offset_index; i++) {
+	for (unsigned int i = 0; i < offset_index; i++) {
 	    _cairo_output_stream_printf (output,
-					 "<stop offset=\"%f\" style=\""
-					 "stop-color:rgb(%f%%,%f%%,%f%%);"
-					 "stop-opacity:%f;\"/>\n",
+					 "<stop offset=\"%f\" "
+					 "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
+					 "stop-opacity=\"%f\"/>\n",
 					 1.0 + stops[i].offset + start_offset,
-					 stops[i].color.red   * 100.0,
+					 stops[i].color.red * 100.0,
 					 stops[i].color.green * 100.0,
-					 stops[i].color.blue  * 100.0,
+					 stops[i].color.blue * 100.0,
 					 stops[i].color.alpha);
 	}
 
 	_cairo_output_stream_printf (output,
-				     "<stop offset=\"1\" style=\""
-				     "stop-color:rgb(%f%%,%f%%,%f%%);"
-				     "stop-opacity:%f;\"/>\n",
-				     offset_color_stop.red   * 100.0,
+				     "<stop offset=\"1\" "
+				     "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
+				     "stop-opacity=\"%f\"/>\n",
+				     offset_color_stop.red * 100.0,
 				     offset_color_stop.green * 100.0,
-				     offset_color_stop.blue  * 100.0,
+				     offset_color_stop.blue * 100.0,
 				     offset_color_stop.alpha);
 
     }
 
-    if (reverse_stops || emulate_reflect)
+    if (reverse_stops || emulate_reflect) {
 	free (stops);
+    }
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static void
 _cairo_svg_surface_emit_pattern_extend (cairo_output_stream_t *output,
-					cairo_pattern_t       *pattern)
+					cairo_pattern_t *pattern)
 {
     switch (pattern->extend) {
-	case CAIRO_EXTEND_REPEAT:
-	    _cairo_output_stream_printf (output, "spreadMethod=\"repeat\" ");
-	    break;
-	case CAIRO_EXTEND_REFLECT:
-	    _cairo_output_stream_printf (output, "spreadMethod=\"reflect\" ");
-	    break;
-	case CAIRO_EXTEND_NONE:
-	case CAIRO_EXTEND_PAD:
-	    break;
+    case CAIRO_EXTEND_REPEAT:
+	_cairo_output_stream_printf (output, " spreadMethod=\"repeat\"");
+	break;
+    case CAIRO_EXTEND_REFLECT:
+	_cairo_output_stream_printf (output, " spreadMethod=\"reflect\"");
+	break;
+    case CAIRO_EXTEND_NONE:
+    case CAIRO_EXTEND_PAD:
+	break;
     }
 }
 
 static cairo_status_t
-_cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t    *surface,
+_cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t *surface,
 					cairo_linear_pattern_t *pattern,
-					cairo_output_stream_t  *style,
-					cairo_bool_t	        is_stroke,
-					const cairo_matrix_t   *parent_matrix)
+					cairo_output_stream_t *output,
+					cairo_bool_t is_stroke,
+					const cairo_matrix_t *parent_matrix)
 {
-    cairo_svg_document_t *document = surface->document;
-    cairo_matrix_t p2u;
     cairo_status_t status;
+    cairo_svg_document_t *document = surface->document;
 
-    p2u = pattern->base.base.matrix;
+    cairo_matrix_t p2u = pattern->base.base.matrix;
     status = cairo_matrix_invert (&p2u);
     /* cairo_pattern_set_matrix ensures the matrix is invertible */
     assert (status == CAIRO_STATUS_SUCCESS);
 
+    unsigned int linear_pattern_id = document->linear_pattern_id++;
+
     _cairo_output_stream_printf (document->xml_node_defs,
-				 "<linearGradient id=\"linear-%d\" "
+				 "<linearGradient id=\"linear-pattern-%d\" "
 				 "gradientUnits=\"userSpaceOnUse\" "
-				 "x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" ",
-				 document->linear_pattern_id,
+				 "x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\"",
+				 linear_pattern_id,
 				 pattern->pd1.x, pattern->pd1.y,
 				 pattern->pd2.x, pattern->pd2.y);
 
-    _cairo_svg_surface_emit_pattern_extend (document->xml_node_defs, &pattern->base.base),
+    _cairo_svg_surface_emit_pattern_extend (document->xml_node_defs, &pattern->base.base);
     _cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u, parent_matrix);
     _cairo_output_stream_printf (document->xml_node_defs, ">\n");
 
     status = _cairo_svg_surface_emit_pattern_stops (document->xml_node_defs,
-	                                            &pattern->base, 0.0,
-						    FALSE, FALSE);
+						    &pattern->base,
+						    0.0,
+						    FALSE,
+						    FALSE);
     if (unlikely (status))
 	return status;
 
     _cairo_output_stream_printf (document->xml_node_defs,
 				 "</linearGradient>\n");
 
-    _cairo_output_stream_printf (style,
-				 "%s:url(#linear-%d);",
-				 is_stroke ? "stroke" : "fill",
-				 document->linear_pattern_id);
-
-    document->linear_pattern_id++;
+    _cairo_output_stream_printf (output,
+				 is_stroke ? " stroke=\"url(#linear-pattern-%d)\""
+					   : " fill=\"url(#linear-pattern-%d)\"",
+				 linear_pattern_id);
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
-_cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t    *surface,
+_cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface,
 					cairo_radial_pattern_t *pattern,
-					cairo_output_stream_t  *style,
-					cairo_bool_t            is_stroke,
-					const cairo_matrix_t   *parent_matrix)
+					cairo_output_stream_t *output,
+					cairo_bool_t is_stroke,
+					const cairo_matrix_t *parent_matrix)
 {
-    cairo_svg_document_t *document = surface->document;
-    cairo_matrix_t p2u;
-    cairo_extend_t extend;
-    double x0, y0, x1, y1, r0, r1;
-    double fx, fy;
-    cairo_bool_t reverse_stops;
     cairo_status_t status;
-    cairo_circle_double_t *c0, *c1;
+    cairo_svg_document_t *document = surface->document;
 
-    extend = pattern->base.base.extend;
+    cairo_extend_t extend = pattern->base.base.extend;
 
+    cairo_bool_t reverse_stops;
+    cairo_circle_double_t *c0, *c1;
     if (pattern->cd1.radius < pattern->cd2.radius) {
 	c0 = &pattern->cd1;
 	c1 = &pattern->cd2;
@@ -2208,65 +2206,68 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t    *surface,
 	reverse_stops = TRUE;
     }
 
-    x0 = c0->center.x;
-    y0 = c0->center.y;
-    r0 = c0->radius;
-    x1 = c1->center.x;
-    y1 = c1->center.y;
-    r1 = c1->radius;
+    double x0 = c0->center.x;
+    double y0 = c0->center.y;
+    double r0 = c0->radius;
+    double x1 = c1->center.x;
+    double y1 = c1->center.y;
+    double r1 = c1->radius;
 
-    p2u = pattern->base.base.matrix;
+    cairo_matrix_t p2u = pattern->base.base.matrix;
     status = cairo_matrix_invert (&p2u);
     /* cairo_pattern_set_matrix ensures the matrix is invertible */
     assert (status == CAIRO_STATUS_SUCCESS);
 
+    unsigned int radial_pattern_id = document->radial_pattern_id++;
+
     if (r0 == r1) {
 	unsigned int n_stops = pattern->base.n_stops;
 
 	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<radialGradient id=\"radial-%d\" "
+				     "<radialGradient id=\"radial-pattern-%d\" "
 				     "gradientUnits=\"userSpaceOnUse\" "
 				     "cx=\"%f\" cy=\"%f\" "
 				     "fx=\"%f\" fy=\"%f\" r=\"%f\" ",
-				     document->radial_pattern_id,
+				     radial_pattern_id,
 				     x1, y1,
 				     x1, y1, r1);
 	_cairo_svg_surface_emit_transform (document->xml_node_defs,
 					   "gradientTransform",
-					   &p2u, parent_matrix);
+					   &p2u,
+					   parent_matrix);
 	_cairo_output_stream_printf (document->xml_node_defs, ">\n");
 
-	if (extend == CAIRO_EXTEND_NONE || n_stops < 1)
+	if (extend == CAIRO_EXTEND_NONE || n_stops < 1) {
 	    _cairo_output_stream_printf (document->xml_node_defs,
-					 "<stop offset=\"0\" style=\""
-					 "stop-color:rgb(0%%,0%%,0%%);"
-					 "stop-opacity:0;\"/>\n");
-	else {
+					 "<stop offset=\"0\" "
+					 "stop-color=\"rgb(0%%, 0%%, 0%%)\" "
+					 "stop-opacity=\"0\"/>\n");
+	} else {
 	    _cairo_output_stream_printf (document->xml_node_defs,
-					 "<stop offset=\"0\" style=\""
-					 "stop-color:rgb(%f%%,%f%%,%f%%);"
-					 "stop-opacity %f;\"/>\n",
-					 pattern->base.stops[0].color.red   * 100.0,
+					 "<stop offset=\"0\" "
+					 "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
+					 "stop-opacity=\"%f\"/>\n",
+					 pattern->base.stops[0].color.red * 100.0,
 					 pattern->base.stops[0].color.green * 100.0,
-					 pattern->base.stops[0].color.blue  * 100.0,
+					 pattern->base.stops[0].color.blue * 100.0,
 					 pattern->base.stops[0].color.alpha);
-	    if (n_stops > 1)
+	    if (n_stops > 1) {
 		_cairo_output_stream_printf (document->xml_node_defs,
-					     "<stop offset=\"0\" style=\""
-					     "stop-color:rgb(%f%%,%f%%,%f%%);"
-					     "stop-opacity:%f;\"/>\n",
-					     pattern->base.stops[n_stops - 1].color.red   * 100.0,
+					     "<stop offset=\"0\" "
+					     "stop-color=\"rgb(%f%%, %f%%, %f%%)\" "
+					     "stop-opacity=\"%f\"/>\n",
+					     pattern->base.stops[n_stops - 1].color.red * 100.0,
 					     pattern->base.stops[n_stops - 1].color.green * 100.0,
-					     pattern->base.stops[n_stops - 1].color.blue  * 100.0,
+					     pattern->base.stops[n_stops - 1].color.blue * 100.0,
 					     pattern->base.stops[n_stops - 1].color.alpha);
+	    }
 	}
-
     } else {
 	double offset, r, x, y;
 	cairo_bool_t emulate_reflect = FALSE;
 
-	fx = (r1 * x0 - r0 * x1) / (r1 - r0);
-	fy = (r1 * y0 - r0 * y1) / (r1 - r0);
+	double fx = (r1 * x0 - r0 * x1) / (r1 - r0);
+	double fy = (r1 * y0 - r0 * y1) / (r1 - r0);
 
 	/* SVG doesn't support the inner circle and use instead a gradient focal.
 	 * That means we need to emulate the cairo behaviour by processing the
@@ -2279,9 +2280,7 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t    *surface,
 	 * case, and 2 * (r1 - r0) in the CAIRO_EXTEND_REFLECT case, and a new gradient stop
 	 * list that maps to the original cairo stop list.
 	 */
-	if ((extend == CAIRO_EXTEND_REFLECT
-	     || extend == CAIRO_EXTEND_REPEAT)
-	    && r0 > 0.0) {
+	if ((extend == CAIRO_EXTEND_REFLECT || extend == CAIRO_EXTEND_REPEAT) && r0 > 0.0) {
 	    double r_org = r1;
 
 	    if (extend == CAIRO_EXTEND_REFLECT) {
@@ -2305,18 +2304,19 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t    *surface,
 	}
 
 	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<radialGradient id=\"radial-%d\" "
+				     "<radialGradient id=\"radial-pattern-%d\" "
 				     "gradientUnits=\"userSpaceOnUse\" "
 				     "cx=\"%f\" cy=\"%f\" "
 				     "fx=\"%f\" fy=\"%f\" r=\"%f\" ",
-				     document->radial_pattern_id,
+				     radial_pattern_id,
 				     x1, y1,
 				     fx, fy, r1);
 
-	if (emulate_reflect)
+	if (emulate_reflect) {
 	    _cairo_output_stream_printf (document->xml_node_defs, "spreadMethod=\"repeat\" ");
-	else
+	} else {
 	    _cairo_svg_surface_emit_pattern_extend (document->xml_node_defs, &pattern->base.base);
+	}
 	_cairo_svg_surface_emit_transform (document->xml_node_defs, "gradientTransform", &p2u, parent_matrix);
 	_cairo_output_stream_printf (document->xml_node_defs, ">\n");
 
@@ -2325,49 +2325,50 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t    *surface,
 	 * user-provided stops. */
 	if (extend == CAIRO_EXTEND_NONE) {
 	    _cairo_output_stream_printf (document->xml_node_defs,
-					 "<stop offset=\"0\" style=\""
-					 "stop-color:rgb(0%%,0%%,0%%);"
-					 "stop-opacity:0;\"/>\n");
-	    if (r0 != 0.0)
+					 "<stop offset=\"0\" "
+					 "stop-color=\"rgb(0%%, 0%%, 0%%)\" "
+					 "stop-opacity=\"0\"/>\n");
+	    if (r0 != 0.0) {
 		_cairo_output_stream_printf (document->xml_node_defs,
-					     "<stop offset=\"%f\" style=\""
-					     "stop-color:rgb(0%%,0%%,0%%);"
-					     "stop-opacity:0;\"/>\n",
+					     "<stop offset=\"%f\" "
+					     "stop-color=\"rgb(0%%, 0%%, 0%%)\" "
+					     "stop-opacity=\"0\"/>\n",
 					     r0 / r1);
+	    }
 	}
 	status = _cairo_svg_surface_emit_pattern_stops (document->xml_node_defs,
-		                                        &pattern->base, offset,
+							&pattern->base, offset,
 							reverse_stops,
 							emulate_reflect);
-	if (unlikely (status))
+	if (unlikely (status)) {
 	    return status;
+	}
 
-	if (pattern->base.base.extend == CAIRO_EXTEND_NONE)
+	if (pattern->base.base.extend == CAIRO_EXTEND_NONE) {
 	    _cairo_output_stream_printf (document->xml_node_defs,
-					 "<stop offset=\"1.0\" style=\""
-					 "stop-color:rgb(0%%,0%%,0%%);"
-					 "stop-opacity:0;\"/>\n");
+					 "<stop offset=\"1\" "
+					 "stop-color=\"rgb(0%%, 0%%, 0%%)\" "
+					 "stop-opacity=\"0\"/>\n");
+	}
     }
 
     _cairo_output_stream_printf (document->xml_node_defs,
 				 "</radialGradient>\n");
 
-    _cairo_output_stream_printf (style,
-				 "%s:url(#radial-%d);",
-				 is_stroke ? "stroke" : "fill",
-				 document->radial_pattern_id);
-
-    document->radial_pattern_id++;
+    _cairo_output_stream_printf (output,
+				 is_stroke ? " stroke=\"url(#radial-pattern-%d)\""
+					   : " fill=\"url(#radial-pattern-%d)\"",
+				 radial_pattern_id);
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
-_cairo_svg_surface_emit_pattern (cairo_svg_surface_t   *surface,
-				 const cairo_pattern_t       *pattern,
+_cairo_svg_surface_emit_pattern (cairo_svg_surface_t *surface,
+				 const cairo_pattern_t *pattern,
 				 cairo_output_stream_t *output,
-				 cairo_bool_t		is_stroke,
-				 const cairo_matrix_t  *parent_matrix)
+				 cairo_bool_t is_stroke,
+				 const cairo_matrix_t *parent_matrix)
 {
     switch (pattern->type) {
     case CAIRO_PATTERN_TYPE_SOLID:
@@ -2394,89 +2395,87 @@ _cairo_svg_surface_emit_pattern (cairo_svg_surface_t   *surface,
 }
 
 static cairo_status_t
-_cairo_svg_surface_emit_fill_style (cairo_output_stream_t	*output,
-				    cairo_svg_surface_t		*surface,
-				    const cairo_pattern_t	*source,
-				    cairo_fill_rule_t		 fill_rule,
-				    const cairo_matrix_t	*parent_matrix)
+_cairo_svg_surface_emit_fill_style (cairo_output_stream_t *output,
+				    cairo_svg_surface_t *surface,
+				    const cairo_pattern_t *source,
+				    cairo_fill_rule_t fill_rule,
+				    const cairo_matrix_t *parent_matrix)
 {
     _cairo_output_stream_printf (output,
-				 "fill-rule:%s;",
-				 fill_rule == CAIRO_FILL_RULE_EVEN_ODD ?
-				 "evenodd" : "nonzero");
+				 " fill-rule=\"%s\" ",
+				 fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero");
     return _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, parent_matrix);
 }
 
 static cairo_status_t
-_cairo_svg_surface_emit_stroke_style (cairo_output_stream_t	   *output,
-				      cairo_svg_surface_t	   *surface,
-				      const cairo_pattern_t	   *source,
-				      const cairo_stroke_style_t   *stroke_style,
-				      const cairo_matrix_t	   *parent_matrix)
+_cairo_svg_surface_emit_stroke_style (cairo_output_stream_t *output,
+				      cairo_svg_surface_t *surface,
+				      const cairo_pattern_t *source,
+				      const cairo_stroke_style_t *stroke_style,
+				      const cairo_matrix_t *parent_matrix)
 {
     cairo_status_t status;
     const char *line_cap, *line_join;
     unsigned int i;
 
     switch (stroke_style->line_cap) {
-	case CAIRO_LINE_CAP_BUTT:
-	    line_cap = "butt";
-	    break;
-	case CAIRO_LINE_CAP_ROUND:
-	    line_cap = "round";
-	    break;
-	case CAIRO_LINE_CAP_SQUARE:
-	    line_cap = "square";
-	    break;
-	default:
-	    ASSERT_NOT_REACHED;
+    case CAIRO_LINE_CAP_BUTT:
+	line_cap = "butt";
+	break;
+    case CAIRO_LINE_CAP_ROUND:
+	line_cap = "round";
+	break;
+    case CAIRO_LINE_CAP_SQUARE:
+	line_cap = "square";
+	break;
+    default:
+	ASSERT_NOT_REACHED;
     }
 
     switch (stroke_style->line_join) {
-	case CAIRO_LINE_JOIN_MITER:
-	    line_join = "miter";
-	    break;
-	case CAIRO_LINE_JOIN_ROUND:
-	    line_join = "round";
-	    break;
-	case CAIRO_LINE_JOIN_BEVEL:
-	    line_join = "bevel";
-	    break;
-	default:
-	    ASSERT_NOT_REACHED;
+    case CAIRO_LINE_JOIN_MITER:
+	line_join = "miter";
+	break;
+    case CAIRO_LINE_JOIN_ROUND:
+	line_join = "round";
+	break;
+    case CAIRO_LINE_JOIN_BEVEL:
+	line_join = "bevel";
+	break;
+    default:
+	ASSERT_NOT_REACHED;
     }
 
     _cairo_output_stream_printf (output,
-				 "stroke-width:%f;"
-				 "stroke-linecap:%s;"
-				 "stroke-linejoin:%s;",
+				 " stroke-width=\"%f\""
+				 " stroke-linecap=\"%s\""
+				 " stroke-linejoin=\"%s\"",
 				 stroke_style->line_width,
 				 line_cap,
 				 line_join);
 
-     status = _cairo_svg_surface_emit_pattern (surface, source, output, TRUE, parent_matrix);
-     if (unlikely (status))
-	 return status;
+    status = _cairo_svg_surface_emit_pattern (surface, source, output, TRUE, parent_matrix);
+    if (unlikely (status)) {
+	return status;
+    }
 
     if (stroke_style->num_dashes > 0) {
-	_cairo_output_stream_printf (output, "stroke-dasharray:");
+	_cairo_output_stream_printf (output, " stroke-dasharray=\"");
 	for (i = 0; i < stroke_style->num_dashes; i++) {
-	    _cairo_output_stream_printf (output, "%f",
+	    _cairo_output_stream_printf (output,
+					 "%f",
 					 stroke_style->dash[i]);
-	    if (i + 1 < stroke_style->num_dashes)
-		_cairo_output_stream_printf (output, ",");
-	    else
-		_cairo_output_stream_printf (output, ";");
+	    _cairo_output_stream_printf (output, i + 1 < stroke_style->num_dashes ? " " : "\"");
 	}
 	if (stroke_style->dash_offset != 0.0) {
 	    _cairo_output_stream_printf (output,
-					 "stroke-dashoffset:%f;",
+					 " stroke-dashoffset=\"%f\"",
 					 stroke_style->dash_offset);
 	}
     }
 
     _cairo_output_stream_printf (output,
-				 "stroke-miterlimit:%f;",
+				 " stroke-miterlimit=\"%f\"",
 				 stroke_style->miter_limit);
 
     return CAIRO_STATUS_SUCCESS;
@@ -2518,13 +2517,11 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
 
     _cairo_output_stream_printf (output,
 				 "<rect x=\"-50%%\" y=\"-50%%\" "
-				 "width=\"200%%\" height=\"200%%\" "
-				 "style=\"");
+				 "width=\"200%%\" height=\"200%%\"");
     status = _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, NULL);
-    if (unlikely (status))
+    if (unlikely (status)) {
 	return status;
-
-    _cairo_output_stream_printf (output, "\"");
+    }
 
     _cairo_output_stream_printf (output, "/>\n");
 
@@ -3161,7 +3158,7 @@ _cairo_svg_surface_stroke_impl (cairo_output_stream_t *output,
 	white_pattern = cairo_pattern_create_rgb (1.0, 1.0, 1.0);
     }
 
-    _cairo_output_stream_printf (output_stream, "<path style=\"fill:none;");
+    _cairo_output_stream_printf (output_stream, "<path fill=\"none\"");
     status = _cairo_svg_surface_emit_stroke_style (output_stream,
 						   surface,
 						   svg_clip_or_svg_mask_should_be_used ? white_pattern : source,
@@ -3172,11 +3169,9 @@ _cairo_svg_surface_stroke_impl (cairo_output_stream_t *output,
 	return status;
     }
 
-    _cairo_output_stream_printf (output_stream, "\" ");
-
     _cairo_svg_surface_emit_path (output_stream, path, ctm_inverse);
 
-    _cairo_svg_surface_emit_transform (output_stream, " transform", ctm, NULL);
+    _cairo_svg_surface_emit_transform (output_stream, "transform", ctm, NULL);
     _cairo_output_stream_printf (output_stream, "/>\n");
 
     if (svg_clip_or_svg_mask_should_be_used) {
@@ -3250,7 +3245,7 @@ _cairo_svg_surface_fill_impl (cairo_output_stream_t *output,
 				     "<clipPath id=\"clip-%d\">\n",
 				     surface->document->clip_id);
 
-	_cairo_output_stream_printf (surface->document->xml_node_defs, "<path ");
+	_cairo_output_stream_printf (surface->document->xml_node_defs, "<path");
 	_cairo_svg_surface_emit_path (surface->document->xml_node_defs, path, NULL);
 	_cairo_output_stream_printf (surface->document->xml_node_defs, "/>\n");
 
@@ -3273,12 +3268,11 @@ _cairo_svg_surface_fill_impl (cairo_output_stream_t *output,
 
 	_cairo_output_stream_printf (output, "</g>");
     } else {
-	_cairo_output_stream_printf (output, "<path style=\"");
+	_cairo_output_stream_printf (output, "<path");
 	status = _cairo_svg_surface_emit_fill_style (output, surface, source, fill_rule, NULL);
 	if (unlikely (status)) {
 	    return status;
 	}
-	_cairo_output_stream_printf (output, "\" ");
 	_cairo_svg_surface_emit_path (output, path, NULL);
 	_cairo_output_stream_printf (output, "/>\n");
     }
@@ -3365,7 +3359,7 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface,
 	return status;
     }
 
-    _cairo_output_stream_printf (surface->xml_node, "<path style=\"");
+    _cairo_output_stream_printf (surface->xml_node, "<path");
     status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface,
 						 fill_source, fill_rule, stroke_ctm_inverse);
     if (unlikely (status)) {
@@ -3378,11 +3372,10 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface,
 	return status;
     }
 
-    _cairo_output_stream_printf (surface->xml_node, "\" ");
-
     _cairo_svg_surface_emit_path (surface->xml_node, path, stroke_ctm_inverse);
 
-    _cairo_svg_surface_emit_transform (surface->xml_node, " transform", stroke_ctm, NULL);
+    _cairo_svg_surface_emit_transform (surface->xml_node, "transform", stroke_ctm, NULL);
+
     _cairo_output_stream_printf (surface->xml_node, "/>\n");
 
     return CAIRO_STATUS_SUCCESS;
@@ -3410,12 +3403,12 @@ _cairo_svg_surface_show_glyphs_impl (cairo_output_stream_t *output,
 	goto fallback;
     }
 
-    _cairo_output_stream_printf (output, "<g style=\"");
+    _cairo_output_stream_printf (output, "<g");
     status = _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, NULL);
     if (unlikely (status))
 	return status;
 
-    _cairo_output_stream_printf (output, "\">\n");
+    _cairo_output_stream_printf (output, ">\n");
 
     for (int i = 0; i < num_glyphs; i++) {
 	cairo_scaled_font_subsets_glyph_t subset_glyph;
commit 71eef9c8bc21a5f9746dd7be411257fd3d9f20cc
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Fri Apr 9 21:19:47 2021 +0200

    Implement the rest of the operators

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 82a407d33..28f00be8e 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -139,6 +139,21 @@ enum cairo_svg_filter {
     CAIRO_SVG_FILTER_ATOP,
     CAIRO_SVG_FILTER_XOR,
     CAIRO_SVG_FILTER_ADD,
+    CAIRO_SVG_FILTER_MULTIPLY,
+    CAIRO_SVG_FILTER_SCREEN,
+    CAIRO_SVG_FILTER_OVERLAY,
+    CAIRO_SVG_FILTER_DARKEN,
+    CAIRO_SVG_FILTER_LIGHTEN,
+    CAIRO_SVG_FILTER_COLOR_DODGE,
+    CAIRO_SVG_FILTER_COLOR_BURN,
+    CAIRO_SVG_FILTER_HARD_LIGHT,
+    CAIRO_SVG_FILTER_SOFT_LIGHT,
+    CAIRO_SVG_FILTER_DIFFERENCE,
+    CAIRO_SVG_FILTER_EXCLUSION,
+    CAIRO_SVG_FILTER_HUE,
+    CAIRO_SVG_FILTER_SATURATION,
+    CAIRO_SVG_FILTER_COLOR,
+    CAIRO_SVG_FILTER_LUMINOSITY,
 };
 
 struct cairo_svg_page {
@@ -1096,13 +1111,18 @@ _cairo_svg_document_emit_font_subsets (cairo_svg_document_t *document)
 }
 
 static cairo_bool_t
-_cairo_svg_surface_is_pattern_supported (cairo_svg_surface_t *surface,
-					 const cairo_pattern_t *pattern)
+_cairo_svg_surface_are_operation_and_pattern_supported (cairo_svg_surface_t *surface,
+							cairo_operator_t op,
+							const cairo_pattern_t *pattern)
 {
     if (surface->force_fallbacks) {
 	return FALSE;
     }
 
+    if (op == CAIRO_OPERATOR_SATURATE) {
+        return FALSE;
+    }
+
     if (pattern->type == CAIRO_PATTERN_TYPE_MESH) {
 	return FALSE;
     }
@@ -1217,6 +1237,34 @@ _cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cair
     }
 }
 
+#define _CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER(operation) \
+    _cairo_output_stream_printf (document->xml_node_filters, \
+				 "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" " \
+				 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n" \
+				 "<feImage xlink:href=\"#composing-group-%d\" result=\"source\"/>\n" \
+				 "<feImage xlink:href=\"#composing-group-%d\" result=\"destination\"/>\n" \
+				 "<feComposite in=\"source\" in2=\"destination\" " \
+				 "operator=\"" operation "\" " \
+				 "color-interpolation-filters=\"sRGB\"/>\n" \
+				 "</filter>\n", \
+				 filter_id, \
+				 source_composing_group_id, \
+				 destination_composing_group_id)
+
+#define _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER(mode) \
+    _cairo_output_stream_printf (document->xml_node_filters, \
+				 "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" " \
+				 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n" \
+				 "<feImage xlink:href=\"#composing-group-%d\" result=\"source\"/>\n" \
+				 "<feImage xlink:href=\"#composing-group-%d\" result=\"destination\"/>\n" \
+				 "<feBlend in=\"source\" in2=\"destination\" " \
+				 "mode=\"" mode "\" " \
+				 "color-interpolation-filters=\"sRGB\"/>\n" \
+				 "</filter>\n", \
+				 filter_id, \
+				 source_composing_group_id, \
+				 destination_composing_group_id)
+
 static unsigned int
 _cairo_svg_surface_emit_parametric_filter (cairo_svg_document_t *document,
 					   enum cairo_svg_filter filter,
@@ -1226,74 +1274,19 @@ _cairo_svg_surface_emit_parametric_filter (cairo_svg_document_t *document,
     unsigned int filter_id = document->filter_id++;
     switch (filter) {
     case CAIRO_SVG_FILTER_OVER:
-	_cairo_output_stream_printf (document->xml_node_filters,
-				     "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" "
-				     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
-				     "<feImage xlink:href=\"#composing-group-%d\" result=\"source\"/>\n"
-				     "<feImage xlink:href=\"#composing-group-%d\" result=\"destination\"/>\n"
-				     "<feComposite in=\"source\" in2=\"destination\" "
-				     "operator=\"over\" "
-				     "color-interpolation-filters=\"sRGB\"/>\n"
-				     "</filter>\n",
-				     filter_id,
-				     source_composing_group_id,
-				     destination_composing_group_id);
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("over");
 	break;
     case CAIRO_SVG_FILTER_IN:
-	_cairo_output_stream_printf (document->xml_node_filters,
-				     "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" "
-				     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
-				     "<feImage xlink:href=\"#composing-group-%d\" result=\"source\"/>\n"
-				     "<feImage xlink:href=\"#composing-group-%d\" result=\"destination\"/>\n"
-				     "<feComposite in=\"source\" in2=\"destination\" "
-				     "operator=\"in\" "
-				     "color-interpolation-filters=\"sRGB\"/>\n"
-				     "</filter>\n",
-				     filter_id,
-				     source_composing_group_id,
-				     destination_composing_group_id);
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("in");
 	break;
     case CAIRO_SVG_FILTER_OUT:
-	_cairo_output_stream_printf (document->xml_node_filters,
-				     "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" "
-				     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
-				     "<feImage xlink:href=\"#composing-group-%d\" result=\"source\"/>\n"
-				     "<feImage xlink:href=\"#composing-group-%d\" result=\"destination\"/>\n"
-				     "<feComposite in=\"source\" in2=\"destination\" "
-				     "operator=\"out\" "
-				     "color-interpolation-filters=\"sRGB\"/>\n"
-				     "</filter>\n",
-				     filter_id,
-				     source_composing_group_id,
-				     destination_composing_group_id);
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("out");
 	break;
     case CAIRO_SVG_FILTER_ATOP:
-	_cairo_output_stream_printf (document->xml_node_filters,
-				     "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" "
-				     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
-				     "<feImage xlink:href=\"#composing-group-%d\" result=\"source\"/>\n"
-				     "<feImage xlink:href=\"#composing-group-%d\" result=\"destination\"/>\n"
-				     "<feComposite in=\"source\" in2=\"destination\" "
-				     "operator=\"atop\" "
-				     "color-interpolation-filters=\"sRGB\"/>\n"
-				     "</filter>\n",
-				     filter_id,
-				     source_composing_group_id,
-				     destination_composing_group_id);
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("atop");
 	break;
     case CAIRO_SVG_FILTER_XOR:
-	_cairo_output_stream_printf (document->xml_node_filters,
-				     "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" "
-				     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
-				     "<feImage xlink:href=\"#composing-group-%d\" result=\"source\"/>\n"
-				     "<feImage xlink:href=\"#composing-group-%d\" result=\"destination\"/>\n"
-				     "<feComposite in=\"source\" in2=\"destination\" "
-				     "operator=\"xor\" "
-				     "color-interpolation-filters=\"sRGB\"/>\n"
-				     "</filter>\n",
-				     filter_id,
-				     source_composing_group_id,
-				     destination_composing_group_id);
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("xor");
 	break;
     case CAIRO_SVG_FILTER_ADD:
         // This can also be done with <feComposite operator="lighter"/>, but it is not from SVG 1.1
@@ -1310,7 +1303,53 @@ _cairo_svg_surface_emit_parametric_filter (cairo_svg_document_t *document,
 				     source_composing_group_id,
 				     destination_composing_group_id);
 	break;
+    case CAIRO_SVG_FILTER_MULTIPLY:
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("multiply");
+	break;
+    case CAIRO_SVG_FILTER_SCREEN:
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("screen");
+	break;
+    case CAIRO_SVG_FILTER_OVERLAY:
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("overlay");
+	break;
+    case CAIRO_SVG_FILTER_DARKEN:
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("darken");
+	break;
+    case CAIRO_SVG_FILTER_LIGHTEN:
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("lighten");
+	break;
+    case CAIRO_SVG_FILTER_COLOR_DODGE:
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("color-dodge");
+	break;
+    case CAIRO_SVG_FILTER_COLOR_BURN:
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("color-burn");
+	break;
+    case CAIRO_SVG_FILTER_HARD_LIGHT:
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("hard-light");
+	break;
+    case CAIRO_SVG_FILTER_SOFT_LIGHT:
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("soft-light");
+	break;
+    case CAIRO_SVG_FILTER_DIFFERENCE:
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("difference");
+	break;
+    case CAIRO_SVG_FILTER_EXCLUSION:
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("exclusion");
+	break;
+    case CAIRO_SVG_FILTER_HUE:
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("hue");
+	break;
+    case CAIRO_SVG_FILTER_SATURATION:
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("saturation");
+	break;
+    case CAIRO_SVG_FILTER_COLOR:
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("color");
+	break;
+    case CAIRO_SVG_FILTER_LUMINOSITY:
+	_CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("luminosity");
+	break;
     default:
+        printf("%d\n", filter);
 	ASSERT_NOT_REACHED;
     }
     return filter_id;
@@ -2478,8 +2517,8 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
 							  mask_source ? &mask_source->matrix : NULL);
 
     _cairo_output_stream_printf (output,
-				 "<rect x=\"-1000%%\" y=\"-1000%%\" "
-				 "width=\"2000%%\" height=\"2000%%\" "
+				 "<rect x=\"-50%%\" y=\"-50%%\" "
+				 "width=\"200%%\" height=\"200%%\" "
 				 "style=\"");
     status = _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, NULL);
     if (unlikely (status))
@@ -2648,7 +2687,7 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
     }
     cairo_pattern_t *white_pattern = cairo_pattern_create_rgb (1.0, 1.0, 1.0);
     status = _cairo_svg_surface_emit_paint (document->xml_node_defs, surface, white_pattern, NULL);
-    cairo_pattern_destroy(white_pattern);
+    cairo_pattern_destroy (white_pattern);
     if (unlikely (status)) {
 	cairo_status_t ignore1 = _cairo_output_stream_destroy (destination_stream);
 	cairo_status_t ignore2 = _cairo_output_stream_destroy (source_stream);
@@ -2739,121 +2778,169 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
     _cairo_output_stream_printf (document->xml_node_defs,
 				 "<g id=\"composing-group-%d\" ",
 				 operation_composing_group_id);
+    unsigned int filer_id;
     switch (op) {
     case CAIRO_OPERATOR_CLEAR:
     case CAIRO_OPERATOR_SOURCE:
     case CAIRO_OPERATOR_OVER:
-        ASSERT_NOT_REACHED;
+	ASSERT_NOT_REACHED;
     case CAIRO_OPERATOR_IN:
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "filter=\"url(#filter-%d)\">\n",
-				     _cairo_svg_surface_emit_parametric_filter (document,
-										CAIRO_SVG_FILTER_IN,
-										source_composing_group_id,
-										raw_destination_composing_group_id));
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_IN,
+							      source_composing_group_id,
+							      raw_destination_composing_group_id);
 	break;
     case CAIRO_OPERATOR_OUT:
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "filter=\"url(#filter-%d)\">\n",
-				     _cairo_svg_surface_emit_parametric_filter (document,
-										CAIRO_SVG_FILTER_OUT,
-										source_composing_group_id,
-										raw_destination_composing_group_id));
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_OUT,
+							      source_composing_group_id,
+							      raw_destination_composing_group_id);
 	break;
     case CAIRO_OPERATOR_ATOP:
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "filter=\"url(#filter-%d)\">\n",
-				     _cairo_svg_surface_emit_parametric_filter (document,
-										CAIRO_SVG_FILTER_ATOP,
-										source_composing_group_id,
-										raw_destination_composing_group_id));
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_ATOP,
+							      source_composing_group_id,
+							      raw_destination_composing_group_id);
 	break;
     case CAIRO_OPERATOR_DEST:
 	ASSERT_NOT_REACHED;
     case CAIRO_OPERATOR_DEST_OVER:
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "filter=\"url(#filter-%d)\">\n",
-				     _cairo_svg_surface_emit_parametric_filter (document,
-										CAIRO_SVG_FILTER_OVER,
-										raw_destination_composing_group_id,
-										source_composing_group_id));
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_OVER,
+							      raw_destination_composing_group_id,
+							      source_composing_group_id);
 	break;
     case CAIRO_OPERATOR_DEST_IN:
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "filter=\"url(#filter-%d)\">\n",
-				     _cairo_svg_surface_emit_parametric_filter (document,
-										CAIRO_SVG_FILTER_IN,
-										raw_destination_composing_group_id,
-										source_composing_group_id));
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_IN,
+							      raw_destination_composing_group_id,
+							      source_composing_group_id);
 	break;
     case CAIRO_OPERATOR_DEST_OUT:
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "filter=\"url(#filter-%d)\">\n",
-				     _cairo_svg_surface_emit_parametric_filter (document,
-										CAIRO_SVG_FILTER_OUT,
-										raw_destination_composing_group_id,
-										source_composing_group_id));
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_OUT,
+							      raw_destination_composing_group_id,
+							      source_composing_group_id);
 	break;
     case CAIRO_OPERATOR_DEST_ATOP:
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "filter=\"url(#filter-%d)\">\n",
-				     _cairo_svg_surface_emit_parametric_filter (document,
-										CAIRO_SVG_FILTER_ATOP,
-										raw_destination_composing_group_id,
-										source_composing_group_id));
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_ATOP,
+							      raw_destination_composing_group_id,
+							      source_composing_group_id);
 	break;
     case CAIRO_OPERATOR_XOR:
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "filter=\"url(#filter-%d)\">\n",
-				     _cairo_svg_surface_emit_parametric_filter (document,
-										CAIRO_SVG_FILTER_XOR,
-										source_composing_group_id,
-										raw_destination_composing_group_id));
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_XOR,
+							      source_composing_group_id,
+							      raw_destination_composing_group_id);
 	break;
     case CAIRO_OPERATOR_ADD:
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "filter=\"url(#filter-%d)\">\n",
-				     _cairo_svg_surface_emit_parametric_filter (document,
-										CAIRO_SVG_FILTER_ADD,
-										source_composing_group_id,
-										raw_destination_composing_group_id));
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_ADD,
+							      source_composing_group_id,
+							      raw_destination_composing_group_id);
 	break;
     case CAIRO_OPERATOR_SATURATE:
-	break;
+	ASSERT_NOT_REACHED;
     case CAIRO_OPERATOR_MULTIPLY:
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_MULTIPLY,
+							      source_composing_group_id,
+							      raw_destination_composing_group_id);
 	break;
     case CAIRO_OPERATOR_SCREEN:
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_SCREEN,
+							      source_composing_group_id,
+							      raw_destination_composing_group_id);
 	break;
     case CAIRO_OPERATOR_OVERLAY:
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_OVERLAY,
+							      source_composing_group_id,
+							      raw_destination_composing_group_id);
 	break;
     case CAIRO_OPERATOR_DARKEN:
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_DARKEN,
+							      source_composing_group_id,
+							      raw_destination_composing_group_id);
 	break;
     case CAIRO_OPERATOR_LIGHTEN:
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_LIGHTEN,
+							      source_composing_group_id,
+							      raw_destination_composing_group_id);
 	break;
     case CAIRO_OPERATOR_COLOR_DODGE:
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_COLOR_DODGE,
+							      source_composing_group_id,
+							      raw_destination_composing_group_id);
 	break;
     case CAIRO_OPERATOR_COLOR_BURN:
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_COLOR_BURN,
+							      source_composing_group_id,
+							      raw_destination_composing_group_id);
 	break;
     case CAIRO_OPERATOR_HARD_LIGHT:
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_HARD_LIGHT,
+							      source_composing_group_id,
+							      raw_destination_composing_group_id);
 	break;
     case CAIRO_OPERATOR_SOFT_LIGHT:
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_SOFT_LIGHT,
+							      source_composing_group_id,
+							      raw_destination_composing_group_id);
 	break;
     case CAIRO_OPERATOR_DIFFERENCE:
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_DIFFERENCE,
+							      source_composing_group_id,
+							      raw_destination_composing_group_id);
 	break;
     case CAIRO_OPERATOR_EXCLUSION:
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_EXCLUSION,
+							      source_composing_group_id,
+							      raw_destination_composing_group_id);
 	break;
     case CAIRO_OPERATOR_HSL_HUE:
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_HUE,
+							      source_composing_group_id,
+							      raw_destination_composing_group_id);
 	break;
     case CAIRO_OPERATOR_HSL_SATURATION:
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_SATURATION,
+							      source_composing_group_id,
+							      raw_destination_composing_group_id);
 	break;
     case CAIRO_OPERATOR_HSL_COLOR:
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_COLOR,
+							      source_composing_group_id,
+							      raw_destination_composing_group_id);
 	break;
     case CAIRO_OPERATOR_HSL_LUMINOSITY:
+	filer_id = _cairo_svg_surface_emit_parametric_filter (document,
+							      CAIRO_SVG_FILTER_LUMINOSITY,
+							      source_composing_group_id,
+							      raw_destination_composing_group_id);
 	break;
+    default:
+	ASSERT_NOT_REACHED;
     }
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "filter=\"url(#filter-%d)\">\n",
+				 filer_id);
     cairo_pattern_t *black_pattern = cairo_pattern_create_rgb (0.0, 0.0, 0.0);
     status = _cairo_svg_surface_emit_paint (document->xml_node_defs, surface, black_pattern, NULL);
-    cairo_pattern_destroy(black_pattern);
+    cairo_pattern_destroy (black_pattern);
     if (unlikely (status)) {
 	return status;
     }
@@ -2874,13 +2961,13 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
     return CAIRO_STATUS_SUCCESS;
 }
 
-#define _CAIRO_SVG_SURFACE_CALL_OPERATOR_IMPL(OPERATOR_IMPL, source, ...) \
+#define _CAIRO_SVG_SURFACE_CALL_OPERATOR_IMPL(OPERATOR_IMPL, SOURCE, ...) \
     if (op == CAIRO_OPERATOR_OVER) { \
         status = _cairo_svg_surface_set_clip (surface, surface->xml_node, clip); \
         if (unlikely (status)) { \
             return status; \
         } \
-        return OPERATOR_IMPL (surface->xml_node, surface, source, ## __VA_ARGS__); \
+        return OPERATOR_IMPL (surface->xml_node, surface, SOURCE, ## __VA_ARGS__); \
     } else { \
         _cairo_svg_surface_reset_clip (surface); \
         cairo_output_stream_t *mask_stream = _cairo_memory_stream_create (); \
@@ -2895,7 +2982,7 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
         cairo_output_stream_t *source_stream = _cairo_memory_stream_create (); \
         status = _cairo_svg_surface_emit_paint (source_stream, \
                                                 surface, \
-                                                source, \
+                                                SOURCE, \
                                                 NULL); \
         if (unlikely (status)) { \
             cairo_status_t ignore1 = _cairo_output_stream_destroy (source_stream); \
@@ -2959,7 +3046,7 @@ _cairo_svg_surface_paint (void *abstract_surface,
 	    ASSERT_NOT_REACHED;
 	}
     } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
-	return _cairo_svg_surface_is_pattern_supported (surface, source)
+	return _cairo_svg_surface_are_operation_and_pattern_supported (surface, op, source)
 	       ? CAIRO_STATUS_SUCCESS
 	       : CAIRO_INT_STATUS_UNSUPPORTED;
     }
@@ -3034,8 +3121,8 @@ _cairo_svg_surface_mask (void *abstract_surface,
     cairo_svg_surface_t *surface = abstract_surface;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
-	return _cairo_svg_surface_is_pattern_supported (surface, source) &&
-	       _cairo_svg_surface_is_pattern_supported (surface, mask)
+	return _cairo_svg_surface_are_operation_and_pattern_supported (surface, op, source) &&
+	       _cairo_svg_surface_are_operation_and_pattern_supported (surface, op, mask)
 	       ? CAIRO_STATUS_SUCCESS
 	       : CAIRO_INT_STATUS_UNSUPPORTED;
     }
@@ -3132,7 +3219,7 @@ _cairo_svg_surface_stroke (void *abstract_dst,
     cairo_status_t status;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
-	return _cairo_svg_surface_is_pattern_supported (surface, source)
+	return _cairo_svg_surface_are_operation_and_pattern_supported (surface, op, source)
 	       ? CAIRO_STATUS_SUCCESS
 	       : CAIRO_INT_STATUS_UNSUPPORTED;
     }
@@ -3213,7 +3300,7 @@ _cairo_svg_surface_fill (void *abstract_surface,
     cairo_status_t status;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
-	return _cairo_svg_surface_is_pattern_supported (surface, source)
+	return _cairo_svg_surface_are_operation_and_pattern_supported (surface, op, source)
 	       ? CAIRO_STATUS_SUCCESS
 	       : CAIRO_INT_STATUS_UNSUPPORTED;
     }
@@ -3267,8 +3354,8 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface,
     }
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
-	return _cairo_svg_surface_is_pattern_supported (surface, fill_source)
-	       && _cairo_svg_surface_is_pattern_supported (surface, stroke_source)
+	return _cairo_svg_surface_are_operation_and_pattern_supported (surface, fill_op, fill_source)
+	       && _cairo_svg_surface_are_operation_and_pattern_supported (surface, stroke_op, stroke_source)
 	       ? CAIRO_STATUS_SUCCESS
 	       : CAIRO_INT_STATUS_UNSUPPORTED;
     }
@@ -3402,7 +3489,7 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
     cairo_int_status_t status;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
-	return _cairo_svg_surface_is_pattern_supported (surface, source)
+	return _cairo_svg_surface_are_operation_and_pattern_supported (surface, op, source)
 	       ? CAIRO_STATUS_SUCCESS
 	       : CAIRO_INT_STATUS_UNSUPPORTED;
     }
diff --git a/test/operator-www.c b/test/operator-www.c
index 36bed8db3..3e863040a 100644
--- a/test/operator-www.c
+++ b/test/operator-www.c
@@ -32,6 +32,7 @@ void
 example (cairo_t *cr, char *name)
 {
     cairo_save (cr);
+    cairo_push_group (cr);
 
     cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT);
     cairo_clip (cr);
@@ -106,6 +107,8 @@ example (cairo_t *cr, char *name)
     cairo_set_source_rgba (cr, 0, 0, 0.9, 0.4);
     cairo_fill (cr);
 
+    cairo_pop_group_to_source (cr);
+    cairo_paint (cr);
     cairo_restore (cr);
 
     cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans",
diff --git a/test/reference/operator-www.image.rgb24.ref.png b/test/reference/operator-www.image.rgb24.ref.png
new file mode 100644
index 000000000..80261ceb3
Binary files /dev/null and b/test/reference/operator-www.image.rgb24.ref.png differ
diff --git a/test/reference/operator-www.ref.png b/test/reference/operator-www.ref.png
new file mode 100644
index 000000000..22ae85d01
Binary files /dev/null and b/test/reference/operator-www.ref.png differ
diff --git a/test/reference/operator-www.svg11.rgb24.ref.png b/test/reference/operator-www.svg11.rgb24.ref.png
new file mode 100644
index 000000000..80261ceb3
Binary files /dev/null and b/test/reference/operator-www.svg11.rgb24.ref.png differ
commit 0df89ca8d8472dbb49e0613d6bcc7acbe9d00ad0
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Fri Apr 9 19:42:59 2021 +0200

    Implement most of the non-blending operators

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 47a1463ae..82a407d33 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -133,8 +133,12 @@ enum cairo_svg_filter {
     CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA,
     CAIRO_SVG_FILTER_COLOR_TO_ALPHA,
     CAIRO_SVG_FILTER_LAST_STATIC_FILTER,
-    CAIRO_SVG_FILTER_ADD,
+    CAIRO_SVG_FILTER_OVER,
     CAIRO_SVG_FILTER_IN,
+    CAIRO_SVG_FILTER_OUT,
+    CAIRO_SVG_FILTER_ATOP,
+    CAIRO_SVG_FILTER_XOR,
+    CAIRO_SVG_FILTER_ADD,
 };
 
 struct cairo_svg_page {
@@ -1221,14 +1225,14 @@ _cairo_svg_surface_emit_parametric_filter (cairo_svg_document_t *document,
 {
     unsigned int filter_id = document->filter_id++;
     switch (filter) {
-    case CAIRO_SVG_FILTER_ADD:
+    case CAIRO_SVG_FILTER_OVER:
 	_cairo_output_stream_printf (document->xml_node_filters,
 				     "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" "
 				     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
 				     "<feImage xlink:href=\"#composing-group-%d\" result=\"source\"/>\n"
 				     "<feImage xlink:href=\"#composing-group-%d\" result=\"destination\"/>\n"
 				     "<feComposite in=\"source\" in2=\"destination\" "
-				     "operator=\"arithmetic\" k1=\"0\" k2=\"1\" k3=\"1\" k4=\"0\" "
+				     "operator=\"over\" "
 				     "color-interpolation-filters=\"sRGB\"/>\n"
 				     "</filter>\n",
 				     filter_id,
@@ -1249,6 +1253,63 @@ _cairo_svg_surface_emit_parametric_filter (cairo_svg_document_t *document,
 				     source_composing_group_id,
 				     destination_composing_group_id);
 	break;
+    case CAIRO_SVG_FILTER_OUT:
+	_cairo_output_stream_printf (document->xml_node_filters,
+				     "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" "
+				     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
+				     "<feImage xlink:href=\"#composing-group-%d\" result=\"source\"/>\n"
+				     "<feImage xlink:href=\"#composing-group-%d\" result=\"destination\"/>\n"
+				     "<feComposite in=\"source\" in2=\"destination\" "
+				     "operator=\"out\" "
+				     "color-interpolation-filters=\"sRGB\"/>\n"
+				     "</filter>\n",
+				     filter_id,
+				     source_composing_group_id,
+				     destination_composing_group_id);
+	break;
+    case CAIRO_SVG_FILTER_ATOP:
+	_cairo_output_stream_printf (document->xml_node_filters,
+				     "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" "
+				     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
+				     "<feImage xlink:href=\"#composing-group-%d\" result=\"source\"/>\n"
+				     "<feImage xlink:href=\"#composing-group-%d\" result=\"destination\"/>\n"
+				     "<feComposite in=\"source\" in2=\"destination\" "
+				     "operator=\"atop\" "
+				     "color-interpolation-filters=\"sRGB\"/>\n"
+				     "</filter>\n",
+				     filter_id,
+				     source_composing_group_id,
+				     destination_composing_group_id);
+	break;
+    case CAIRO_SVG_FILTER_XOR:
+	_cairo_output_stream_printf (document->xml_node_filters,
+				     "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" "
+				     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
+				     "<feImage xlink:href=\"#composing-group-%d\" result=\"source\"/>\n"
+				     "<feImage xlink:href=\"#composing-group-%d\" result=\"destination\"/>\n"
+				     "<feComposite in=\"source\" in2=\"destination\" "
+				     "operator=\"xor\" "
+				     "color-interpolation-filters=\"sRGB\"/>\n"
+				     "</filter>\n",
+				     filter_id,
+				     source_composing_group_id,
+				     destination_composing_group_id);
+	break;
+    case CAIRO_SVG_FILTER_ADD:
+        // This can also be done with <feComposite operator="lighter"/>, but it is not from SVG 1.1
+	_cairo_output_stream_printf (document->xml_node_filters,
+				     "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" "
+				     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
+				     "<feImage xlink:href=\"#composing-group-%d\" result=\"source\"/>\n"
+				     "<feImage xlink:href=\"#composing-group-%d\" result=\"destination\"/>\n"
+				     "<feComposite in=\"source\" in2=\"destination\" "
+				     "operator=\"arithmetic\" k1=\"0\" k2=\"1\" k3=\"1\" k4=\"0\" "
+				     "color-interpolation-filters=\"sRGB\"/>\n"
+				     "</filter>\n",
+				     filter_id,
+				     source_composing_group_id,
+				     destination_composing_group_id);
+	break;
     default:
 	ASSERT_NOT_REACHED;
     }
@@ -2548,6 +2609,29 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 	return CAIRO_STATUS_SUCCESS;
     }
 
+    if (op == CAIRO_OPERATOR_DEST) {
+	_cairo_memory_stream_copy (destination_stream, surface->xml_node);
+	status = _cairo_output_stream_destroy (destination_stream);
+	if (unlikely (status)) {
+	    cairo_status_t ignore1 = _cairo_output_stream_destroy (source_stream);
+	    cairo_status_t ignore2 = _cairo_output_stream_destroy (mask_stream);
+	    return status;
+	    (void) ignore1;
+	    (void) ignore2;
+	}
+	status = _cairo_output_stream_destroy (source_stream);
+	if (unlikely (status)) {
+	    cairo_status_t ignore = _cairo_output_stream_destroy (source_stream);
+	    return status;
+	    (void) ignore;
+	}
+	status = _cairo_output_stream_destroy (source_stream);
+	if (unlikely (status)) {
+	    return status;
+	}
+	return CAIRO_STATUS_SUCCESS;
+    }
+
     unsigned int lerp_composing_group_id = document->composing_group_id++;
     _cairo_output_stream_printf (document->xml_node_defs,
 				 "<g id=\"composing-group-%d\">\n",
@@ -2653,12 +2737,120 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 
     unsigned int operation_composing_group_id = document->composing_group_id++;
     _cairo_output_stream_printf (document->xml_node_defs,
-				 "<g id=\"composing-group-%d\" filter=\"url(#filter-%d)\">\n",
-				 operation_composing_group_id,
-				 _cairo_svg_surface_emit_parametric_filter (document,
-									    CAIRO_SVG_FILTER_IN,
-									    source_composing_group_id,
-									    raw_destination_composing_group_id));
+				 "<g id=\"composing-group-%d\" ",
+				 operation_composing_group_id);
+    switch (op) {
+    case CAIRO_OPERATOR_CLEAR:
+    case CAIRO_OPERATOR_SOURCE:
+    case CAIRO_OPERATOR_OVER:
+        ASSERT_NOT_REACHED;
+    case CAIRO_OPERATOR_IN:
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     "filter=\"url(#filter-%d)\">\n",
+				     _cairo_svg_surface_emit_parametric_filter (document,
+										CAIRO_SVG_FILTER_IN,
+										source_composing_group_id,
+										raw_destination_composing_group_id));
+	break;
+    case CAIRO_OPERATOR_OUT:
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     "filter=\"url(#filter-%d)\">\n",
+				     _cairo_svg_surface_emit_parametric_filter (document,
+										CAIRO_SVG_FILTER_OUT,
+										source_composing_group_id,
+										raw_destination_composing_group_id));
+	break;
+    case CAIRO_OPERATOR_ATOP:
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     "filter=\"url(#filter-%d)\">\n",
+				     _cairo_svg_surface_emit_parametric_filter (document,
+										CAIRO_SVG_FILTER_ATOP,
+										source_composing_group_id,
+										raw_destination_composing_group_id));
+	break;
+    case CAIRO_OPERATOR_DEST:
+	ASSERT_NOT_REACHED;
+    case CAIRO_OPERATOR_DEST_OVER:
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     "filter=\"url(#filter-%d)\">\n",
+				     _cairo_svg_surface_emit_parametric_filter (document,
+										CAIRO_SVG_FILTER_OVER,
+										raw_destination_composing_group_id,
+										source_composing_group_id));
+	break;
+    case CAIRO_OPERATOR_DEST_IN:
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     "filter=\"url(#filter-%d)\">\n",
+				     _cairo_svg_surface_emit_parametric_filter (document,
+										CAIRO_SVG_FILTER_IN,
+										raw_destination_composing_group_id,
+										source_composing_group_id));
+	break;
+    case CAIRO_OPERATOR_DEST_OUT:
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     "filter=\"url(#filter-%d)\">\n",
+				     _cairo_svg_surface_emit_parametric_filter (document,
+										CAIRO_SVG_FILTER_OUT,
+										raw_destination_composing_group_id,
+										source_composing_group_id));
+	break;
+    case CAIRO_OPERATOR_DEST_ATOP:
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     "filter=\"url(#filter-%d)\">\n",
+				     _cairo_svg_surface_emit_parametric_filter (document,
+										CAIRO_SVG_FILTER_ATOP,
+										raw_destination_composing_group_id,
+										source_composing_group_id));
+	break;
+    case CAIRO_OPERATOR_XOR:
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     "filter=\"url(#filter-%d)\">\n",
+				     _cairo_svg_surface_emit_parametric_filter (document,
+										CAIRO_SVG_FILTER_XOR,
+										source_composing_group_id,
+										raw_destination_composing_group_id));
+	break;
+    case CAIRO_OPERATOR_ADD:
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     "filter=\"url(#filter-%d)\">\n",
+				     _cairo_svg_surface_emit_parametric_filter (document,
+										CAIRO_SVG_FILTER_ADD,
+										source_composing_group_id,
+										raw_destination_composing_group_id));
+	break;
+    case CAIRO_OPERATOR_SATURATE:
+	break;
+    case CAIRO_OPERATOR_MULTIPLY:
+	break;
+    case CAIRO_OPERATOR_SCREEN:
+	break;
+    case CAIRO_OPERATOR_OVERLAY:
+	break;
+    case CAIRO_OPERATOR_DARKEN:
+	break;
+    case CAIRO_OPERATOR_LIGHTEN:
+	break;
+    case CAIRO_OPERATOR_COLOR_DODGE:
+	break;
+    case CAIRO_OPERATOR_COLOR_BURN:
+	break;
+    case CAIRO_OPERATOR_HARD_LIGHT:
+	break;
+    case CAIRO_OPERATOR_SOFT_LIGHT:
+	break;
+    case CAIRO_OPERATOR_DIFFERENCE:
+	break;
+    case CAIRO_OPERATOR_EXCLUSION:
+	break;
+    case CAIRO_OPERATOR_HSL_HUE:
+	break;
+    case CAIRO_OPERATOR_HSL_SATURATION:
+	break;
+    case CAIRO_OPERATOR_HSL_COLOR:
+	break;
+    case CAIRO_OPERATOR_HSL_LUMINOSITY:
+	break;
+    }
     cairo_pattern_t *black_pattern = cairo_pattern_create_rgb (0.0, 0.0, 0.0);
     status = _cairo_svg_surface_emit_paint (document->xml_node_defs, surface, black_pattern, NULL);
     cairo_pattern_destroy(black_pattern);
@@ -2804,10 +2996,9 @@ _cairo_svg_surface_mask_impl (cairo_output_stream_t *output,
 	return status;
 	(void) ignore;
     }
+    _cairo_output_stream_printf (temporary_stream, "</g>\n");
+    _cairo_output_stream_printf (temporary_stream, "</mask>\n");
 
-    _cairo_output_stream_printf (temporary_stream,
-				 "</g>\n"
-				 "</mask>\n");
     _cairo_memory_stream_copy (temporary_stream, document->xml_node_defs);
 
     status = _cairo_output_stream_destroy (temporary_stream);
@@ -2898,15 +3089,13 @@ _cairo_svg_surface_stroke_impl (cairo_output_stream_t *output,
 
     _cairo_svg_surface_emit_path (output_stream, path, ctm_inverse);
 
-    _cairo_svg_surface_emit_transform (output_stream,
-				       " transform", ctm, NULL);
+    _cairo_svg_surface_emit_transform (output_stream, " transform", ctm, NULL);
     _cairo_output_stream_printf (output_stream, "/>\n");
 
     if (svg_clip_or_svg_mask_should_be_used) {
 	cairo_pattern_destroy (white_pattern);
 
-	_cairo_output_stream_printf (output_stream,
-				     "</mask>\n");
+	_cairo_output_stream_printf (output_stream, "</mask>\n");
 
 	_cairo_output_stream_printf (output,
 				     "<g mask=\"url(#mask-%d)\">\n",
@@ -2971,27 +3160,21 @@ _cairo_svg_surface_fill_impl (cairo_output_stream_t *output,
 
     if (_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (source)) {
 	_cairo_output_stream_printf (surface->document->xml_node_defs,
-				     "<clipPath id=\"clip-%d\">\n"
-				     "<path ",
+				     "<clipPath id=\"clip-%d\">\n",
 				     surface->document->clip_id);
 
+	_cairo_output_stream_printf (surface->document->xml_node_defs, "<path ");
 	_cairo_svg_surface_emit_path (surface->document->xml_node_defs, path, NULL);
+	_cairo_output_stream_printf (surface->document->xml_node_defs, "/>\n");
 
-	_cairo_output_stream_printf (surface->document->xml_node_defs,
-				     "/>\n"
-				     "</clipPath>\n");
+	_cairo_output_stream_printf (surface->document->xml_node_defs, "</clipPath>\n");
 
 	_cairo_output_stream_printf (output,
 				     "<g clip-path=\"url(#clip-%d)\" "
-				     "clip-rule=\"%s\" "
-				     "style=\"",
-				     surface->document->clip_id,
+				     "clip-rule=\"%s\">\n",
+				     surface->document->clip_id++,
 				     fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero");
 
-	surface->document->clip_id++;
-
-	_cairo_output_stream_printf (output, "\">\n");
-
 	status = _cairo_svg_surface_emit_composite_pattern (output,
 							    surface,
 							    (cairo_surface_pattern_t *) source,
@@ -3008,11 +3191,8 @@ _cairo_svg_surface_fill_impl (cairo_output_stream_t *output,
 	if (unlikely (status)) {
 	    return status;
 	}
-
 	_cairo_output_stream_printf (output, "\" ");
-
 	_cairo_svg_surface_emit_path (output, path, NULL);
-
 	_cairo_output_stream_printf (output, "/>\n");
     }
 
commit e728eb43de3476234382cd770157927658daddb6
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Fri Apr 9 15:34:45 2021 +0200

    Implement the in operator

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 9cf1f5b7f..47a1463ae 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -134,6 +134,7 @@ enum cairo_svg_filter {
     CAIRO_SVG_FILTER_COLOR_TO_ALPHA,
     CAIRO_SVG_FILTER_LAST_STATIC_FILTER,
     CAIRO_SVG_FILTER_ADD,
+    CAIRO_SVG_FILTER_IN,
 };
 
 struct cairo_svg_page {
@@ -1234,6 +1235,20 @@ _cairo_svg_surface_emit_parametric_filter (cairo_svg_document_t *document,
 				     source_composing_group_id,
 				     destination_composing_group_id);
 	break;
+    case CAIRO_SVG_FILTER_IN:
+	_cairo_output_stream_printf (document->xml_node_filters,
+				     "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" "
+				     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
+				     "<feImage xlink:href=\"#composing-group-%d\" result=\"source\"/>\n"
+				     "<feImage xlink:href=\"#composing-group-%d\" result=\"destination\"/>\n"
+				     "<feComposite in=\"source\" in2=\"destination\" "
+				     "operator=\"in\" "
+				     "color-interpolation-filters=\"sRGB\"/>\n"
+				     "</filter>\n",
+				     filter_id,
+				     source_composing_group_id,
+				     destination_composing_group_id);
+	break;
     default:
 	ASSERT_NOT_REACHED;
     }
@@ -2402,8 +2417,8 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
 							  mask_source ? &mask_source->matrix : NULL);
 
     _cairo_output_stream_printf (output,
-				 "<rect x=\"-1000000%%\" y=\"-1000000%%\" "
-				 "width=\"2000000%%\" height=\"2000000%%\" "
+				 "<rect x=\"-1000%%\" y=\"-1000%%\" "
+				 "width=\"2000%%\" height=\"2000%%\" "
 				 "style=\"");
     status = _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, NULL);
     if (unlikely (status))
@@ -2446,10 +2461,10 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
     }
 
     if (op == CAIRO_OPERATOR_SOURCE) {
-	unsigned int composing_group_id = document->composing_group_id++;
+	unsigned int lerp_composing_group_id = document->composing_group_id++;
 	_cairo_output_stream_printf (document->xml_node_defs,
 				     "<g id=\"composing-group-%d\">\n",
-				     composing_group_id);
+				     lerp_composing_group_id);
 	status = _cairo_svg_surface_set_clip (surface, document->xml_node_defs, clip);
 	if (unlikely (status)) {
 	    cairo_status_t ignore1 = _cairo_output_stream_destroy (destination_stream);
@@ -2478,7 +2493,7 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 				     source_mask_id);
 	_cairo_output_stream_printf (document->xml_node_defs,
 				     "<use xlink:href=\"#composing-group-%d\"/>\n",
-				     composing_group_id);
+				     lerp_composing_group_id);
 	_cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
 
 	unsigned int source_composing_group_id = document->composing_group_id++;
@@ -2501,7 +2516,7 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 				     destination_mask_id);
 	_cairo_output_stream_printf (document->xml_node_defs,
 				     "<use xlink:href=\"#composing-group-%d\" filter=\"url(#filter-%s)\"/>\n",
-				     composing_group_id,
+				     lerp_composing_group_id,
 				     _cairo_svg_surface_emit_static_filter (document,
 									    CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA));
 	_cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
@@ -2529,7 +2544,140 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 	    return status;
 	}
 	_cairo_output_stream_printf (surface->xml_node, "</g>\n");
+
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    unsigned int lerp_composing_group_id = document->composing_group_id++;
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<g id=\"composing-group-%d\">\n",
+				 lerp_composing_group_id);
+    status = _cairo_svg_surface_set_clip (surface, document->xml_node_defs, clip);
+    if (unlikely (status)) {
+	cairo_status_t ignore1 = _cairo_output_stream_destroy (destination_stream);
+	cairo_status_t ignore2 = _cairo_output_stream_destroy (source_stream);
+	cairo_status_t ignore3 = _cairo_output_stream_destroy (mask_stream);
+	return status;
+	(void) ignore1;
+	(void) ignore2;
+	(void) ignore3;
+    }
+    cairo_pattern_t *white_pattern = cairo_pattern_create_rgb (1.0, 1.0, 1.0);
+    status = _cairo_svg_surface_emit_paint (document->xml_node_defs, surface, white_pattern, NULL);
+    cairo_pattern_destroy(white_pattern);
+    if (unlikely (status)) {
+	cairo_status_t ignore1 = _cairo_output_stream_destroy (destination_stream);
+	cairo_status_t ignore2 = _cairo_output_stream_destroy (source_stream);
+	cairo_status_t ignore3 = _cairo_output_stream_destroy (mask_stream);
+	return status;
+	(void) ignore1;
+	(void) ignore2;
+	(void) ignore3;
+    }
+    _cairo_svg_surface_reset_clip (surface);
+    _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
+
+    unsigned int mask_mask_id = document->mask_id++;
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<mask id=\"mask-%d\">\n",
+				 mask_mask_id);
+    _cairo_memory_stream_copy (mask_stream, document->xml_node_defs);
+    status = _cairo_output_stream_destroy (mask_stream);
+    if (unlikely (status)) {
+	cairo_status_t ignore1 = _cairo_output_stream_destroy (source_stream);
+	cairo_status_t ignore2 = _cairo_output_stream_destroy (destination_stream);
+	return status;
+	(void) ignore1;
+	(void) ignore2;
+    }
+    _cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
+
+    unsigned int source_mask_id = document->mask_id++;
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<mask id=\"mask-%d\">\n",
+				 source_mask_id);
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<use xlink:href=\"#composing-group-%d\"/>\n",
+				 lerp_composing_group_id);
+    _cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
+
+    unsigned int source_composing_group_id = document->composing_group_id++;
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<g id=\"composing-group-%d\" mask=\"url(#mask-%d)\">\n",
+				 source_composing_group_id,
+				 source_mask_id);
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<g mask=\"url(#mask-%d)\">\n",
+				 mask_mask_id);
+    _cairo_memory_stream_copy (source_stream, document->xml_node_defs);
+    status = _cairo_output_stream_destroy (source_stream);
+    if (unlikely (status)) {
+	cairo_status_t ignore = _cairo_output_stream_destroy (destination_stream);
+	return status;
+	(void) ignore;
+    }
+    _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
+    _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
+
+    unsigned int destination_mask_id = document->mask_id++;
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<mask id=\"mask-%d\">\n",
+				 destination_mask_id);
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<use xlink:href=\"#composing-group-%d\" filter=\"url(#filter-%s)\"/>\n",
+				 lerp_composing_group_id,
+				 _cairo_svg_surface_emit_static_filter (document,
+									CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA));
+    _cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
+
+    unsigned int raw_destination_composing_group_id = document->composing_group_id++;
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<g id=\"composing-group-%d\">\n",
+				 raw_destination_composing_group_id);
+    _cairo_memory_stream_copy (destination_stream, document->xml_node_defs);
+    status = _cairo_output_stream_destroy (destination_stream);
+    if (unlikely (status)) {
+	return status;
+    }
+    _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
+
+    unsigned int destination_composing_group_id = document->composing_group_id++;
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<g id=\"composing-group-%d\" mask=\"url(#mask-%d)\">\n",
+				 destination_composing_group_id,
+				 destination_mask_id);
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<use xlink:href=\"#composing-group-%d\"/>\n",
+				 raw_destination_composing_group_id);
+    _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
+
+    unsigned int operation_composing_group_id = document->composing_group_id++;
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<g id=\"composing-group-%d\" filter=\"url(#filter-%d)\">\n",
+				 operation_composing_group_id,
+				 _cairo_svg_surface_emit_parametric_filter (document,
+									    CAIRO_SVG_FILTER_IN,
+									    source_composing_group_id,
+									    raw_destination_composing_group_id));
+    cairo_pattern_t *black_pattern = cairo_pattern_create_rgb (0.0, 0.0, 0.0);
+    status = _cairo_svg_surface_emit_paint (document->xml_node_defs, surface, black_pattern, NULL);
+    cairo_pattern_destroy(black_pattern);
+    if (unlikely (status)) {
+	return status;
+    }
+    _cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
+
+    _cairo_output_stream_printf (surface->xml_node,
+				 "<g filter=\"url(#filter-%d)\">\n",
+				 _cairo_svg_surface_emit_parametric_filter (document,
+									    CAIRO_SVG_FILTER_ADD,
+									    operation_composing_group_id,
+									    destination_composing_group_id));
+    status = _cairo_svg_surface_emit_paint_black (surface);
+    if (unlikely (status)) {
+	return status;
     }
+    _cairo_output_stream_printf (surface->xml_node, "</g>\n");
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -3011,7 +3159,7 @@ _cairo_svg_surface_show_glyphs_impl (cairo_output_stream_t *output,
 						       NULL,
 						       0,
 						       &subset_glyph);
-	if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+	if ((cairo_int_status_t) status == CAIRO_INT_STATUS_UNSUPPORTED) {
 	    _cairo_output_stream_printf (output, "</g>\n");
 
 	    glyphs += i;
commit 961db5b846a551a040895ca521732b396f747765
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Fri Apr 9 10:43:52 2021 +0200

    Implement operators for the rest of operations

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 4188dbe25..9cf1f5b7f 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -1163,6 +1163,7 @@ _cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cair
 	    // (r, g, b, a) -> (1, 1, 1, a)
 	    _cairo_output_stream_printf (document->xml_node_filters,
 					 "<filter id=\"filter-remove-color\" "
+					 "filterUnits=\"userSpaceOnUse\" "
 					 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
 					 "<feColorMatrix values=\"0 0 0 0 1 "
 					 /*                   */ "0 0 0 0 1 "
@@ -1174,6 +1175,7 @@ _cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cair
 	    // (r, g, b, a) -> (1, 1, 1, 1 - a)
 	    _cairo_output_stream_printf (document->xml_node_filters,
 					 "<filter id=\"filter-remove-color-and-invert-alpha\" "
+					 "filterUnits=\"userSpaceOnUse\" "
 					 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
 					 "<feColorMatrix values=\"0 0 0 0 1 "
 					 /*                   */ "0 0 0 0 1 "
@@ -1185,6 +1187,7 @@ _cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cair
 	    // (r, g, b, a) -> (1, 1, 1, 0.2126 * r + 0.7152 * g + 0.0722 * b)
 	    _cairo_output_stream_printf (document->xml_node_filters,
 					 "<filter id=\"filter-color-to-alpha\" "
+					 "filterUnits=\"userSpaceOnUse\" "
 					 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
 					 "<feColorMatrix values=\"0 0 0 0 1 "
 					 /*                   */ "0 0 0 0 1 "
@@ -2419,20 +2422,24 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 				cairo_operator_t op,
 				const cairo_clip_t *clip,
 				cairo_output_stream_t *mask_stream,
-				const cairo_pattern_t *source,
+				cairo_output_stream_t *source_stream,
 				cairo_output_stream_t *destination_stream)
 {
     cairo_status_t status;
     cairo_svg_document_t *document = surface->document;
 
     if (op == CAIRO_OPERATOR_CLEAR) {
+	status = _cairo_output_stream_destroy (source_stream);
+	if (unlikely (status)) {
+	    return status;
+	}
 	cairo_pattern_t *transparent_pattern = cairo_pattern_create_rgba (0.0, 0.0, 0.0, 0.0);
 	status = _cairo_svg_surface_do_operator (output,
 						 surface,
 						 CAIRO_OPERATOR_SOURCE,
 						 clip,
 						 mask_stream,
-						 transparent_pattern,
+						 _cairo_memory_stream_create (),
 						 destination_stream);
 	cairo_pattern_destroy (transparent_pattern);
 	return status;
@@ -2445,16 +2452,22 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 				     composing_group_id);
 	status = _cairo_svg_surface_set_clip (surface, document->xml_node_defs, clip);
 	if (unlikely (status)) {
-	    cairo_status_t ignore1 = _cairo_output_stream_destroy (mask_stream);
-	    cairo_status_t ignore2 = _cairo_output_stream_destroy (destination_stream);
+	    cairo_status_t ignore1 = _cairo_output_stream_destroy (destination_stream);
+	    cairo_status_t ignore2 = _cairo_output_stream_destroy (source_stream);
+	    cairo_status_t ignore3 = _cairo_output_stream_destroy (mask_stream);
 	    return status;
 	    (void) ignore1;
 	    (void) ignore2;
+	    (void) ignore3;
 	}
 	_cairo_memory_stream_copy (mask_stream, document->xml_node_defs);
 	status = _cairo_output_stream_destroy (mask_stream);
 	if (unlikely (status)) {
+	    cairo_status_t ignore1 = _cairo_output_stream_destroy (destination_stream);
+	    cairo_status_t ignore2 = _cairo_output_stream_destroy (source_stream);
 	    return status;
+	    (void) ignore1;
+	    (void) ignore2;
 	}
 	_cairo_svg_surface_reset_clip (surface);
 	_cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
@@ -2473,10 +2486,8 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 				     "<g id=\"composing-group-%d\" mask=\"url(#mask-%d)\">\n",
 				     source_composing_group_id,
 				     source_mask_id);
-	status = _cairo_svg_surface_emit_paint (document->xml_node_defs,
-						surface,
-						source,
-						NULL);
+	_cairo_memory_stream_copy (source_stream, document->xml_node_defs);
+	status = _cairo_output_stream_destroy (source_stream);
 	if (unlikely (status)) {
 	    cairo_status_t ignore = _cairo_output_stream_destroy (destination_stream);
 	    return status;
@@ -2513,12 +2524,10 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 										CAIRO_SVG_FILTER_ADD,
 										source_composing_group_id,
 										destination_composing_group_id));
-	_cairo_output_stream_printf (surface->xml_node,
-				     "<use xlink:href=\"#composing-group-%d\"/>\n",
-				     source_composing_group_id);
-	_cairo_output_stream_printf (surface->xml_node,
-				     "<use xlink:href=\"#composing-group-%d\"/>\n",
-				     destination_composing_group_id);
+	status = _cairo_svg_surface_emit_paint_black (surface);
+	if (unlikely (status)) {
+	    return status;
+	}
 	_cairo_output_stream_printf (surface->xml_node, "</g>\n");
     }
 
@@ -2543,6 +2552,18 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
             return status; \
             (void) ignore; \
         } \
+        cairo_output_stream_t *source_stream = _cairo_memory_stream_create (); \
+        status = _cairo_svg_surface_emit_paint (source_stream, \
+                                                surface, \
+                                                source, \
+                                                NULL); \
+        if (unlikely (status)) { \
+            cairo_status_t ignore1 = _cairo_output_stream_destroy (source_stream); \
+            cairo_status_t ignore2 = _cairo_output_stream_destroy (mask_stream); \
+            return status; \
+            (void) ignore1; \
+            (void) ignore2; \
+        } \
         cairo_output_stream_t *destination_stream = surface->xml_node; \
         surface->xml_node = _cairo_memory_stream_create (); \
         return _cairo_svg_surface_do_operator (surface->xml_node, \
@@ -2550,7 +2571,7 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
                                                op, \
                                                clip, \
                                                mask_stream, \
-                                               source, \
+                                               source_stream, \
                                                destination_stream); \
     }
 
@@ -2619,29 +2640,29 @@ _cairo_svg_surface_mask_impl (cairo_output_stream_t *output,
     /* _cairo_svg_surface_emit_paint() will output a pattern definition to
      * document->xml_node_defs so we need to write the mask element to
      * a temporary stream and then copy that to xml_node_defs. */
-    cairo_output_stream_t *temporary_mask_stream = _cairo_memory_stream_create ();
+    cairo_output_stream_t *temporary_stream = _cairo_memory_stream_create ();
 
     unsigned int mask_id = document->mask_id++;
 
-    _cairo_output_stream_printf (temporary_mask_stream,
+    _cairo_output_stream_printf (temporary_stream,
 				 "<mask id=\"mask-%d\">\n",
 				 mask_id);
-    _cairo_output_stream_printf (temporary_mask_stream,
+    _cairo_output_stream_printf (temporary_stream,
 				 "<g filter=\"url(#filter-%s)\">\n",
 				 _cairo_svg_surface_emit_static_filter (document, CAIRO_SVG_FILTER_REMOVE_COLOR));
-    status = _cairo_svg_surface_emit_paint (temporary_mask_stream, surface, mask, source);
+    status = _cairo_svg_surface_emit_paint (temporary_stream, surface, mask, source);
     if (unlikely (status)) {
-	cairo_status_t ignore = _cairo_output_stream_destroy (temporary_mask_stream);
+	cairo_status_t ignore = _cairo_output_stream_destroy (temporary_stream);
 	return status;
 	(void) ignore;
     }
 
-    _cairo_output_stream_printf (temporary_mask_stream,
+    _cairo_output_stream_printf (temporary_stream,
 				 "</g>\n"
 				 "</mask>\n");
-    _cairo_memory_stream_copy (temporary_mask_stream, document->xml_node_defs);
+    _cairo_memory_stream_copy (temporary_stream, document->xml_node_defs);
 
-    status = _cairo_output_stream_destroy (temporary_mask_stream);
+    status = _cairo_output_stream_destroy (temporary_stream);
     if (unlikely (status)) {
 	return status;
     }
@@ -2686,34 +2707,21 @@ _cairo_svg_surface_mask (void *abstract_surface,
 }
 
 static cairo_int_status_t
-_cairo_svg_surface_stroke (void			*abstract_dst,
-			   cairo_operator_t      op,
-			   const cairo_pattern_t *source,
-			   const cairo_path_fixed_t*path,
-			   const cairo_stroke_style_t *stroke_style,
-			   const cairo_matrix_t	*ctm,
-			   const cairo_matrix_t	*ctm_inverse,
-			   double		 tolerance,
-			   cairo_antialias_t	 antialias,
-			   const cairo_clip_t	*clip)
+_cairo_svg_surface_stroke_impl (cairo_output_stream_t *output,
+				cairo_svg_surface_t *surface,
+				const cairo_pattern_t *source,
+				const cairo_path_fixed_t *path,
+				const cairo_stroke_style_t *stroke_style,
+				const cairo_matrix_t *ctm,
+				const cairo_matrix_t *ctm_inverse,
+				double tolerance,
+				cairo_antialias_t antialias)
 {
-    cairo_svg_surface_t *surface = abstract_dst;
     cairo_status_t status;
 
-    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
-	return _cairo_svg_surface_is_pattern_supported (surface, source)
-	       ? CAIRO_STATUS_SUCCESS
-	       : CAIRO_INT_STATUS_UNSUPPORTED;
-    }
-
-    status = _cairo_svg_surface_set_clip (surface, surface->xml_node, clip);
-    if (unlikely (status)) {
-	return status;
-    }
-
     cairo_bool_t svg_clip_or_svg_mask_should_be_used = _cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (source);
     unsigned int mask_id;
-    cairo_output_stream_t *output_stream = surface->xml_node;
+    cairo_output_stream_t *output_stream = output;
     cairo_pattern_t *white_pattern;
     if (svg_clip_or_svg_mask_should_be_used) {
 	mask_id = surface->document->mask_id++;
@@ -2724,7 +2732,7 @@ _cairo_svg_surface_stroke (void			*abstract_dst,
 				     "<mask id=\"mask-%d\">\n",
 				     mask_id);
 
-	white_pattern = cairo_pattern_create_rgb(1.0, 1.0, 1.0);
+	white_pattern = cairo_pattern_create_rgb (1.0, 1.0, 1.0);
     }
 
     _cairo_output_stream_printf (output_stream, "<path style=\"fill:none;");
@@ -2747,16 +2755,16 @@ _cairo_svg_surface_stroke (void			*abstract_dst,
     _cairo_output_stream_printf (output_stream, "/>\n");
 
     if (svg_clip_or_svg_mask_should_be_used) {
-        cairo_pattern_destroy(white_pattern);
+	cairo_pattern_destroy (white_pattern);
 
 	_cairo_output_stream_printf (output_stream,
 				     "</mask>\n");
 
-	_cairo_output_stream_printf (surface->xml_node,
+	_cairo_output_stream_printf (output,
 				     "<g mask=\"url(#mask-%d)\">\n",
 				     mask_id);
 
-	status = _cairo_svg_surface_emit_composite_pattern (surface->xml_node,
+	status = _cairo_svg_surface_emit_composite_pattern (output,
 							    surface,
 							    (cairo_surface_pattern_t *) source,
 							    invalid_pattern_id,
@@ -2765,23 +2773,25 @@ _cairo_svg_surface_stroke (void			*abstract_dst,
 	    return status;
 	}
 
-	_cairo_output_stream_printf (surface->xml_node, "</g>\n");
+	_cairo_output_stream_printf (output, "</g>\n");
     }
 
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_int_status_t
-_cairo_svg_surface_fill (void *abstract_surface,
-			 cairo_operator_t op,
-			 const cairo_pattern_t *source,
-			 const cairo_path_fixed_t *path,
-			 cairo_fill_rule_t fill_rule,
-			 double tolerance,
-			 cairo_antialias_t antialias,
-			 const cairo_clip_t *clip)
+_cairo_svg_surface_stroke (void *abstract_dst,
+			   cairo_operator_t op,
+			   const cairo_pattern_t *source,
+			   const cairo_path_fixed_t *path,
+			   const cairo_stroke_style_t *stroke_style,
+			   const cairo_matrix_t *ctm,
+			   const cairo_matrix_t *ctm_inverse,
+			   double tolerance,
+			   cairo_antialias_t antialias,
+			   const cairo_clip_t *clip)
 {
-    cairo_svg_surface_t *surface = abstract_surface;
+    cairo_svg_surface_t *surface = abstract_dst;
     cairo_status_t status;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
@@ -2790,10 +2800,26 @@ _cairo_svg_surface_fill (void *abstract_surface,
 	       : CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    status = _cairo_svg_surface_set_clip (surface, surface->xml_node, clip);
-    if (unlikely (status)) {
-	return status;
-    }
+    _CAIRO_SVG_SURFACE_CALL_OPERATOR_IMPL (_cairo_svg_surface_stroke_impl,
+					   source,
+					   path,
+					   stroke_style,
+					   ctm,
+					   ctm_inverse,
+					   tolerance,
+					   antialias)
+}
+
+static cairo_int_status_t
+_cairo_svg_surface_fill_impl (cairo_output_stream_t *output,
+			      cairo_svg_surface_t *surface,
+			      const cairo_pattern_t *source,
+			      const cairo_path_fixed_t *path,
+			      cairo_fill_rule_t fill_rule,
+			      double tolerance,
+			      cairo_antialias_t antialias)
+{
+    cairo_status_t status;
 
     if (_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (source)) {
 	_cairo_output_stream_printf (surface->document->xml_node_defs,
@@ -2807,7 +2833,7 @@ _cairo_svg_surface_fill (void *abstract_surface,
 				     "/>\n"
 				     "</clipPath>\n");
 
-	_cairo_output_stream_printf (surface->xml_node,
+	_cairo_output_stream_printf (output,
 				     "<g clip-path=\"url(#clip-%d)\" "
 				     "clip-rule=\"%s\" "
 				     "style=\"",
@@ -2816,9 +2842,9 @@ _cairo_svg_surface_fill (void *abstract_surface,
 
 	surface->document->clip_id++;
 
-	_cairo_output_stream_printf (surface->xml_node, "\">\n");
+	_cairo_output_stream_printf (output, "\">\n");
 
-	status = _cairo_svg_surface_emit_composite_pattern (surface->xml_node,
+	status = _cairo_svg_surface_emit_composite_pattern (output,
 							    surface,
 							    (cairo_surface_pattern_t *) source,
 							    invalid_pattern_id,
@@ -2827,24 +2853,51 @@ _cairo_svg_surface_fill (void *abstract_surface,
 	    return status;
 	}
 
-	_cairo_output_stream_printf (surface->xml_node, "</g>");
+	_cairo_output_stream_printf (output, "</g>");
     } else {
-	_cairo_output_stream_printf (surface->xml_node, "<path style=\"");
-	status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, source, fill_rule, NULL);
+	_cairo_output_stream_printf (output, "<path style=\"");
+	status = _cairo_svg_surface_emit_fill_style (output, surface, source, fill_rule, NULL);
 	if (unlikely (status)) {
 	    return status;
 	}
 
-	_cairo_output_stream_printf (surface->xml_node, "\" ");
+	_cairo_output_stream_printf (output, "\" ");
 
-	_cairo_svg_surface_emit_path (surface->xml_node, path, NULL);
+	_cairo_svg_surface_emit_path (output, path, NULL);
 
-	_cairo_output_stream_printf (surface->xml_node, "/>\n");
+	_cairo_output_stream_printf (output, "/>\n");
     }
 
     return CAIRO_STATUS_SUCCESS;
 }
 
+static cairo_int_status_t
+_cairo_svg_surface_fill (void *abstract_surface,
+			 cairo_operator_t op,
+			 const cairo_pattern_t *source,
+			 const cairo_path_fixed_t *path,
+			 cairo_fill_rule_t fill_rule,
+			 double tolerance,
+			 cairo_antialias_t antialias,
+			 const cairo_clip_t *clip)
+{
+    cairo_svg_surface_t *surface = abstract_surface;
+    cairo_status_t status;
+
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+	return _cairo_svg_surface_is_pattern_supported (surface, source)
+	       ? CAIRO_STATUS_SUCCESS
+	       : CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    _CAIRO_SVG_SURFACE_CALL_OPERATOR_IMPL (_cairo_svg_surface_fill_impl,
+					   source,
+					   path,
+					   fill_rule,
+					   tolerance,
+					   antialias)
+}
+
 static cairo_int_status_t
 _cairo_svg_surface_fill_stroke (void *abstract_surface,
 				cairo_operator_t fill_op,
@@ -2866,7 +2919,9 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface,
     cairo_status_t status;
 
     if (_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (fill_source) ||
-	_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (stroke_source)) {
+	_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (stroke_source) ||
+	fill_op != CAIRO_OPERATOR_OVER ||
+	stroke_op != CAIRO_OPERATOR_OVER) {
 	status = _cairo_svg_surface_fill (abstract_surface, fill_op, fill_source, path,
 					  fill_rule, fill_tolerance, fill_antialias,
 					  clip);
@@ -2919,78 +2974,69 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface,
 }
 
 static cairo_int_status_t
-_cairo_svg_surface_show_glyphs (void			*abstract_surface,
-				cairo_operator_t	 op,
-				const cairo_pattern_t	*pattern,
-				cairo_glyph_t		*glyphs,
-				int			 num_glyphs,
-				cairo_scaled_font_t	*scaled_font,
-				const cairo_clip_t	*clip)
+_cairo_svg_surface_show_glyphs_impl (cairo_output_stream_t *output,
+				     cairo_svg_surface_t *surface,
+				     const cairo_pattern_t *source,
+				     cairo_glyph_t *glyphs,
+				     int num_glyphs,
+				     cairo_scaled_font_t *scaled_font)
 {
-    cairo_svg_surface_t *surface = abstract_surface;
+    cairo_status_t status;
     cairo_svg_document_t *document = surface->document;
-    cairo_path_fixed_t path;
-    cairo_int_status_t status;
-    cairo_scaled_font_subsets_glyph_t subset_glyph;
-    int i;
 
-    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
-	return _cairo_svg_surface_is_pattern_supported (surface, pattern)
-	       ? CAIRO_STATUS_SUCCESS
-	       : CAIRO_INT_STATUS_UNSUPPORTED;
-    }
-
-    if (num_glyphs <= 0)
+    if (num_glyphs <= 0) {
 	return CAIRO_STATUS_SUCCESS;
-
-    status = _cairo_svg_surface_set_clip (surface, surface->xml_node, clip);
-    if (unlikely (status)) {
-	return status;
     }
 
-    /* FIXME it's probably possible to apply a pattern of a gradient to
+    /* FIXME it's probably possible to apply a source of a gradient to
      * a group of symbols, but I don't know how yet. Gradients or patterns
      * are translated by x and y properties of use element. */
-    if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
-	goto FALLBACK;
+    if (source->type != CAIRO_PATTERN_TYPE_SOLID) {
+	goto fallback;
+    }
 
-    _cairo_output_stream_printf (surface->xml_node, "<g style=\"");
-    status = _cairo_svg_surface_emit_pattern (surface, pattern,
-	                                      surface->xml_node, FALSE, NULL);
+    _cairo_output_stream_printf (output, "<g style=\"");
+    status = _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, NULL);
     if (unlikely (status))
 	return status;
 
-    _cairo_output_stream_printf (surface->xml_node, "\">\n");
+    _cairo_output_stream_printf (output, "\">\n");
+
+    for (int i = 0; i < num_glyphs; i++) {
+	cairo_scaled_font_subsets_glyph_t subset_glyph;
 
-    for (i = 0; i < num_glyphs; i++) {
 	status = _cairo_scaled_font_subsets_map_glyph (document->font_subsets,
-						       scaled_font, glyphs[i].index,
-						       NULL, 0,
-                                                       &subset_glyph);
+						       scaled_font,
+						       glyphs[i].index,
+						       NULL,
+						       0,
+						       &subset_glyph);
 	if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
-	    _cairo_output_stream_printf (surface->xml_node, "</g>\n");
+	    _cairo_output_stream_printf (output, "</g>\n");
 
 	    glyphs += i;
 	    num_glyphs -= i;
-	    goto FALLBACK;
+	    goto fallback;
 	}
 
-	if (unlikely (status))
+	if (unlikely (status)) {
 	    return status;
+	}
 
-	_cairo_output_stream_printf (surface->xml_node,
-				     "<use xlink:href=\"#glyph-%d-%d\" "
-				     "x=\"%f\" y=\"%f\"/>\n",
+	_cairo_output_stream_printf (output,
+				     "<use xlink:href=\"#glyph-%d-%d\" x=\"%f\" y=\"%f\"/>\n",
 				     subset_glyph.font_id,
-                                     subset_glyph.subset_glyph_index,
+				     subset_glyph.subset_glyph_index,
 				     glyphs[i].x, glyphs[i].y);
     }
 
-    _cairo_output_stream_printf (surface->xml_node, "</g>\n");
+    _cairo_output_stream_printf (output, "</g>\n");
 
     return CAIRO_STATUS_SUCCESS;
 
-FALLBACK:
+    fallback:;
+    cairo_path_fixed_t path;
+
     _cairo_path_fixed_init (&path);
 
     status = _cairo_scaled_font_glyph_path (scaled_font,
@@ -3002,16 +3048,44 @@ FALLBACK:
 	return status;
     }
 
-    status = _cairo_svg_surface_fill (abstract_surface, op, pattern,
-				      &path, CAIRO_FILL_RULE_WINDING,
-				      0.0, CAIRO_ANTIALIAS_SUBPIXEL,
-				      clip);
+    status = _cairo_svg_surface_fill_impl (output,
+					   surface,
+					   source,
+					   &path,
+					   CAIRO_FILL_RULE_WINDING,
+					   0.0,
+					   CAIRO_ANTIALIAS_SUBPIXEL);
 
     _cairo_path_fixed_fini (&path);
 
     return status;
 }
 
+static cairo_int_status_t
+_cairo_svg_surface_show_glyphs (void *abstract_surface,
+				cairo_operator_t op,
+				const cairo_pattern_t *source,
+				cairo_glyph_t *glyphs,
+				int num_glyphs,
+				cairo_scaled_font_t *scaled_font,
+				const cairo_clip_t *clip)
+{
+    cairo_svg_surface_t *surface = abstract_surface;
+    cairo_int_status_t status;
+
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+	return _cairo_svg_surface_is_pattern_supported (surface, source)
+	       ? CAIRO_STATUS_SUCCESS
+	       : CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    _CAIRO_SVG_SURFACE_CALL_OPERATOR_IMPL (_cairo_svg_surface_show_glyphs_impl,
+					   source,
+					   glyphs,
+					   num_glyphs,
+					   scaled_font)
+}
+
 static void
 _cairo_svg_surface_get_font_options (void                  *abstract_surface,
 				     cairo_font_options_t  *options)
@@ -3076,17 +3150,18 @@ static const cairo_surface_backend_t cairo_svg_surface_backend = {
 };
 
 static cairo_status_t
-_cairo_svg_document_create (cairo_output_stream_t	 *output_stream,
-			    double			  width,
-			    double			  height,
-			    cairo_svg_version_t		  version,
-			    cairo_svg_document_t	**document_out)
+_cairo_svg_document_create (cairo_output_stream_t *output_stream,
+			    double width,
+			    double height,
+			    cairo_svg_version_t version,
+			    cairo_svg_document_t **document_out)
 {
     cairo_svg_document_t *document;
     cairo_status_t status;
 
-    if (output_stream->status)
+    if (output_stream->status) {
 	return output_stream->status;
+    }
 
     document = _cairo_malloc (sizeof (cairo_svg_document_t));
     if (unlikely (document == NULL))
@@ -3096,7 +3171,7 @@ _cairo_svg_document_create (cairo_output_stream_t	 *output_stream,
     document->font_subsets = _cairo_scaled_font_subsets_create_scaled ();
     if (unlikely (document->font_subsets == NULL)) {
 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	goto CLEANUP_DOCUMENT;
+	goto cleanup_document;
     }
 
     document->output_stream = output_stream;
@@ -3128,7 +3203,7 @@ _cairo_svg_document_create (cairo_output_stream_t	 *output_stream,
     *document_out = document;
     return CAIRO_STATUS_SUCCESS;
 
-  CLEANUP_DOCUMENT:
+    cleanup_document:
     free (document);
     return status;
 }
commit 1a03d883ab1c965efcbd4782c7783e4629ecf779
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Fri Apr 9 09:33:50 2021 +0200

    Implement operators for the mask operation

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index ef2429293..4188dbe25 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -130,9 +130,10 @@ static const char * _cairo_svg_unit_strings[] =
 
 enum cairo_svg_filter {
     CAIRO_SVG_FILTER_REMOVE_COLOR,
+    CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA,
     CAIRO_SVG_FILTER_COLOR_TO_ALPHA,
-    CAIRO_SVG_FILTER_ALL_INVERT,
-    CAIRO_SVG_FILTER_LAST_FILTER,
+    CAIRO_SVG_FILTER_LAST_STATIC_FILTER,
+    CAIRO_SVG_FILTER_ADD,
 };
 
 struct cairo_svg_page {
@@ -160,8 +161,9 @@ struct cairo_svg_document {
     unsigned int clip_id;
     unsigned int mask_id;
     unsigned int composing_group_id;
+    unsigned int filter_id;
 
-    cairo_bool_t filters_emitted[CAIRO_SVG_FILTER_LAST_FILTER];
+    cairo_bool_t filters_emitted[CAIRO_SVG_FILTER_LAST_STATIC_FILTER];
 
     cairo_svg_version_t svg_version;
 
@@ -1151,63 +1153,90 @@ _cairo_svg_surface_finish (void *abstract_surface)
     return status;
 }
 
-
 static char *
-_cairo_svg_surface_emit_filter (cairo_svg_document_t *document, enum cairo_svg_filter filter)
+_cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cairo_svg_filter filter)
 {
     if (!document->filters_emitted[filter]) {
 	document->filters_emitted[filter] = TRUE;
 	switch (filter) {
-	    case CAIRO_SVG_FILTER_REMOVE_COLOR:
-	        // (r, g, b, a) -> (1, 1, 1, a)
-		_cairo_output_stream_printf (document->xml_node_filters,
-					     "<filter id=\"filter-remove-color\" "
-					     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
-					     "<feColorMatrix values=\"0 0 0 0 1 "
-					     /*                   */ "0 0 0 0 1 "
-					     /*                   */ "0 0 0 0 1 "
-					     /*                   */ "0 0 0 1 0\"/>\n"
-					     "</filter>\n");
-		break;
-	    case CAIRO_SVG_FILTER_COLOR_TO_ALPHA:
-	        // (r, g, b, a) -> (1, 1, 1, 0.2126 * r + 0.7152 * g + 0.0722 * b)
-		_cairo_output_stream_printf (document->xml_node_filters,
-					     "<filter id=\"filter-color-to-alpha\" "
-					     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
-					     "<feColorMatrix values=\"0 0 0 0 1 "
-					     /*                   */ "0 0 0 0 1 "
-					     /*                   */ "0 0 0 0 1 "
-					     /*                   */ "0.2126 0.7152 0.0722 0 0\"/>\n"
-					     "</filter>\n");
-		break;
-	    case CAIRO_SVG_FILTER_ALL_INVERT:
-	        // (r, g, b, a) -> (1 - r, 1 - g, 1 - b, 1 - a)
-		_cairo_output_stream_printf (document->xml_node_filters,
-					     "<filter id=\"filter-all-invert\" "
-					     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
-					     "<feColorMatrix values=\"-1 0 0 0 1 "
-					     /*                   */ "0 -1 0 0 1 "
-					     /*                   */ "0 0 -1 0 1 "
-					     /*                   */ "0 0 0 -1 1\"/>\n"
-					     "</filter>\n");
-		break;
-	    default:
-		ASSERT_NOT_REACHED;
-	}
-    }
-
-    switch (filter) {
 	case CAIRO_SVG_FILTER_REMOVE_COLOR:
-	    return "filter-remove-color";
+	    // (r, g, b, a) -> (1, 1, 1, a)
+	    _cairo_output_stream_printf (document->xml_node_filters,
+					 "<filter id=\"filter-remove-color\" "
+					 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
+					 "<feColorMatrix values=\"0 0 0 0 1 "
+					 /*                   */ "0 0 0 0 1 "
+					 /*                   */ "0 0 0 0 1 "
+					 /*                   */ "0 0 0 1 0\"/>\n"
+					 "</filter>\n");
+	    break;
+	case CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA:
+	    // (r, g, b, a) -> (1, 1, 1, 1 - a)
+	    _cairo_output_stream_printf (document->xml_node_filters,
+					 "<filter id=\"filter-remove-color-and-invert-alpha\" "
+					 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
+					 "<feColorMatrix values=\"0 0 0 0 1 "
+					 /*                   */ "0 0 0 0 1 "
+					 /*                   */ "0 0 0 0 1 "
+					 /*                   */ "0 0 0 -1 1\"/>\n"
+					 "</filter>\n");
+	    break;
 	case CAIRO_SVG_FILTER_COLOR_TO_ALPHA:
-	    return "filter-color-to-alpha";
-	case CAIRO_SVG_FILTER_ALL_INVERT:
-	    return "filter-all-invert";
+	    // (r, g, b, a) -> (1, 1, 1, 0.2126 * r + 0.7152 * g + 0.0722 * b)
+	    _cairo_output_stream_printf (document->xml_node_filters,
+					 "<filter id=\"filter-color-to-alpha\" "
+					 "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
+					 "<feColorMatrix values=\"0 0 0 0 1 "
+					 /*                   */ "0 0 0 0 1 "
+					 /*                   */ "0 0 0 0 1 "
+					 /*                   */ "0.2126 0.7152 0.0722 0 0\"/>\n"
+					 "</filter>\n");
+	    break;
 	default:
 	    ASSERT_NOT_REACHED;
+	}
+    }
+
+    switch (filter) {
+    case CAIRO_SVG_FILTER_REMOVE_COLOR:
+	return "remove-color";
+    case CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA:
+	return "remove-color-and-invert-alpha";
+    case CAIRO_SVG_FILTER_COLOR_TO_ALPHA:
+	return "color-to-alpha";
+    default:
+	ASSERT_NOT_REACHED;
     }
 }
 
+static unsigned int
+_cairo_svg_surface_emit_parametric_filter (cairo_svg_document_t *document,
+					   enum cairo_svg_filter filter,
+					   unsigned int source_composing_group_id,
+					   unsigned int destination_composing_group_id)
+{
+    unsigned int filter_id = document->filter_id++;
+    switch (filter) {
+    case CAIRO_SVG_FILTER_ADD:
+	_cairo_output_stream_printf (document->xml_node_filters,
+				     "<filter id=\"filter-%d\" filterUnits=\"userSpaceOnUse\" "
+				     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
+				     "<feImage xlink:href=\"#composing-group-%d\" result=\"source\"/>\n"
+				     "<feImage xlink:href=\"#composing-group-%d\" result=\"destination\"/>\n"
+				     "<feComposite in=\"source\" in2=\"destination\" "
+				     "operator=\"arithmetic\" k1=\"0\" k2=\"1\" k3=\"1\" k4=\"0\" "
+				     "color-interpolation-filters=\"sRGB\"/>\n"
+				     "</filter>\n",
+				     filter_id,
+				     source_composing_group_id,
+				     destination_composing_group_id);
+	break;
+    default:
+	ASSERT_NOT_REACHED;
+    }
+    return filter_id;
+}
+
 typedef struct {
     cairo_output_stream_t *output;
     unsigned int in_mem;
@@ -1520,9 +1549,9 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t   *outp
 
     if (pattern->surface->content == CAIRO_CONTENT_ALPHA) {
 	_cairo_output_stream_printf (output,
-				     "<g filter=\"url(#%s)\">\n",
-				     _cairo_svg_surface_emit_filter (svg_surface->document,
-								     CAIRO_SVG_FILTER_COLOR_TO_ALPHA));
+				     "<g filter=\"url(#filter-%s)\">\n",
+				     _cairo_svg_surface_emit_static_filter (svg_surface->document,
+									    CAIRO_SVG_FILTER_COLOR_TO_ALPHA));
     }
 
     _cairo_output_stream_printf (output,
@@ -1611,8 +1640,8 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
 
     if (source->base.content == CAIRO_CONTENT_ALPHA) {
 	_cairo_output_stream_printf (document->xml_node_defs,
-				     " filter=\"url(#%s)\"",
-				     _cairo_svg_surface_emit_filter (document, CAIRO_SVG_FILTER_REMOVE_COLOR));
+				     " filter=\"url(#filter-%s)\"",
+				     _cairo_svg_surface_emit_static_filter (document, CAIRO_SVG_FILTER_REMOVE_COLOR));
     }
 
     _cairo_output_stream_printf (document->xml_node_defs, ">\n");
@@ -2439,10 +2468,12 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 				     composing_group_id);
 	_cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
 
-	_cairo_output_stream_printf (surface->xml_node,
-				     "<g mask=\"url(#mask-%d)\">\n",
+	unsigned int source_composing_group_id = document->composing_group_id++;
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     "<g id=\"composing-group-%d\" mask=\"url(#mask-%d)\">\n",
+				     source_composing_group_id,
 				     source_mask_id);
-	status = _cairo_svg_surface_emit_paint (surface->xml_node,
+	status = _cairo_svg_surface_emit_paint (document->xml_node_defs,
 						surface,
 						source,
 						NULL);
@@ -2451,32 +2482,78 @@ _cairo_svg_surface_do_operator (cairo_output_stream_t *output,
 	    return status;
 	    (void) ignore;
 	}
-	_cairo_output_stream_printf (surface->xml_node, "</g>\n");
+	_cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
 
 	unsigned int destination_mask_id = document->mask_id++;
 	_cairo_output_stream_printf (document->xml_node_defs,
 				     "<mask id=\"mask-%d\">\n",
 				     destination_mask_id);
 	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<use xlink:href=\"#composing-group-%d\"  filter=\"url(#%s)\"/>\n",
+				     "<use xlink:href=\"#composing-group-%d\" filter=\"url(#filter-%s)\"/>\n",
 				     composing_group_id,
-				     _cairo_svg_surface_emit_filter (document, CAIRO_SVG_FILTER_ALL_INVERT));
+				     _cairo_svg_surface_emit_static_filter (document,
+									    CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA));
 	_cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
 
-	_cairo_output_stream_printf (surface->xml_node,
-				     "<g mask=\"url(#mask-%d)\">\n",
+	unsigned int destination_composing_group_id = document->composing_group_id++;
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     "<g id=\"composing-group-%d\" mask=\"url(#mask-%d)\">\n",
+				     destination_composing_group_id,
 				     destination_mask_id);
-	_cairo_memory_stream_copy (destination_stream, surface->xml_node);
+	_cairo_memory_stream_copy (destination_stream, document->xml_node_defs);
 	status = _cairo_output_stream_destroy (destination_stream);
 	if (unlikely (status)) {
 	    return status;
 	}
+	_cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
+
+	_cairo_output_stream_printf (surface->xml_node,
+				     "<g filter=\"url(#filter-%d)\">\n",
+				     _cairo_svg_surface_emit_parametric_filter (document,
+										CAIRO_SVG_FILTER_ADD,
+										source_composing_group_id,
+										destination_composing_group_id));
+	_cairo_output_stream_printf (surface->xml_node,
+				     "<use xlink:href=\"#composing-group-%d\"/>\n",
+				     source_composing_group_id);
+	_cairo_output_stream_printf (surface->xml_node,
+				     "<use xlink:href=\"#composing-group-%d\"/>\n",
+				     destination_composing_group_id);
 	_cairo_output_stream_printf (surface->xml_node, "</g>\n");
     }
 
     return CAIRO_STATUS_SUCCESS;
 }
 
+#define _CAIRO_SVG_SURFACE_CALL_OPERATOR_IMPL(OPERATOR_IMPL, source, ...) \
+    if (op == CAIRO_OPERATOR_OVER) { \
+        status = _cairo_svg_surface_set_clip (surface, surface->xml_node, clip); \
+        if (unlikely (status)) { \
+            return status; \
+        } \
+        return OPERATOR_IMPL (surface->xml_node, surface, source, ## __VA_ARGS__); \
+    } else { \
+        _cairo_svg_surface_reset_clip (surface); \
+        cairo_output_stream_t *mask_stream = _cairo_memory_stream_create (); \
+        cairo_pattern_t *white_pattern = cairo_pattern_create_rgb (1.0, 1.0, 1.0); \
+        status = OPERATOR_IMPL (mask_stream, surface, white_pattern, ## __VA_ARGS__); \
+        cairo_pattern_destroy (white_pattern); \
+        if (unlikely (status)) { \
+            cairo_status_t ignore = _cairo_output_stream_destroy (mask_stream); \
+            return status; \
+            (void) ignore; \
+        } \
+        cairo_output_stream_t *destination_stream = surface->xml_node; \
+        surface->xml_node = _cairo_memory_stream_create (); \
+        return _cairo_svg_surface_do_operator (surface->xml_node, \
+                                               surface, \
+                                               op, \
+                                               clip, \
+                                               mask_stream, \
+                                               source, \
+                                               destination_stream); \
+    }
+
 static cairo_int_status_t
 _cairo_svg_surface_paint_impl (cairo_output_stream_t *output,
 			       cairo_svg_surface_t *surface,
@@ -2526,58 +2603,19 @@ _cairo_svg_surface_paint (void *abstract_surface,
 	       : CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    if (op == CAIRO_OPERATOR_OVER) {
-	status = _cairo_svg_surface_set_clip (surface, surface->xml_node, clip);
-	if (unlikely (status)) {
-	    return status;
-	}
-	return _cairo_svg_surface_paint_impl (surface->xml_node, surface, source);
-    } else {
-	_cairo_svg_surface_reset_clip (surface);
-        cairo_output_stream_t *mask_stream = _cairo_memory_stream_create ();
-	cairo_pattern_t *white_pattern = cairo_pattern_create_rgb (1.0, 1.0, 1.0);
-	status = _cairo_svg_surface_paint_impl (mask_stream, surface, white_pattern);
-	cairo_pattern_destroy (white_pattern);
-	if (unlikely (status)) {
-	    cairo_status_t ignore = _cairo_output_stream_destroy (mask_stream);
-	    return status;
-	    (void) ignore;
-	}
-	cairo_output_stream_t *destination_stream = surface->xml_node;
-	surface->xml_node = _cairo_memory_stream_create ();
-	return _cairo_svg_surface_do_operator (surface->xml_node,
-					       surface,
-					       op,
-					       clip,
-					       mask_stream,
-					       source,
-					       destination_stream);
-    }
+    _CAIRO_SVG_SURFACE_CALL_OPERATOR_IMPL (_cairo_svg_surface_paint_impl,
+					   source)
 }
 
 static cairo_int_status_t
-_cairo_svg_surface_mask (void		    *abstract_surface,
-			 cairo_operator_t     op,
-			 const cairo_pattern_t	    *source,
-			 const cairo_pattern_t	    *mask,
-			 const cairo_clip_t	    *clip)
+_cairo_svg_surface_mask_impl (cairo_output_stream_t *output,
+			      cairo_svg_surface_t *surface,
+			      const cairo_pattern_t *source,
+			      const cairo_pattern_t *mask)
 {
     cairo_status_t status;
-    cairo_svg_surface_t *surface = abstract_surface;
     cairo_svg_document_t *document = surface->document;
 
-    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
-	return _cairo_svg_surface_is_pattern_supported (surface, source) &&
-	       _cairo_svg_surface_is_pattern_supported (surface, mask)
-	       ? CAIRO_STATUS_SUCCESS
-	       : CAIRO_INT_STATUS_UNSUPPORTED;
-    }
-
-    status = _cairo_svg_surface_set_clip (surface, surface->xml_node, clip);
-    if (unlikely (status)) {
-	return status;
-    }
-
     /* _cairo_svg_surface_emit_paint() will output a pattern definition to
      * document->xml_node_defs so we need to write the mask element to
      * a temporary stream and then copy that to xml_node_defs. */
@@ -2589,8 +2627,8 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
 				 "<mask id=\"mask-%d\">\n",
 				 mask_id);
     _cairo_output_stream_printf (temporary_mask_stream,
-				 "<g filter=\"url(#%s)\">\n",
-				 _cairo_svg_surface_emit_filter (document, CAIRO_SVG_FILTER_REMOVE_COLOR));
+				 "<g filter=\"url(#filter-%s)\">\n",
+				 _cairo_svg_surface_emit_static_filter (document, CAIRO_SVG_FILTER_REMOVE_COLOR));
     status = _cairo_svg_surface_emit_paint (temporary_mask_stream, surface, mask, source);
     if (unlikely (status)) {
 	cairo_status_t ignore = _cairo_output_stream_destroy (temporary_mask_stream);
@@ -2608,11 +2646,11 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
 	return status;
     }
 
-    _cairo_output_stream_printf (surface->xml_node,
+    _cairo_output_stream_printf (output,
 				 "<g mask=\"url(#mask-%d)\">\n",
 				 mask_id);
 
-    status = _cairo_svg_surface_emit_paint (surface->xml_node,
+    status = _cairo_svg_surface_emit_paint (output,
 					    surface,
 					    source,
 					    NULL);
@@ -2620,11 +2658,33 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
 	return status;
     }
 
-    _cairo_output_stream_printf (surface->xml_node, "</g>\n");
+    _cairo_output_stream_printf (output, "</g>\n");
 
     return CAIRO_STATUS_SUCCESS;
 }
 
+static cairo_int_status_t
+_cairo_svg_surface_mask (void *abstract_surface,
+			 cairo_operator_t op,
+			 const cairo_pattern_t *source,
+			 const cairo_pattern_t *mask,
+			 const cairo_clip_t *clip)
+{
+    cairo_status_t status;
+    cairo_svg_surface_t *surface = abstract_surface;
+
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+	return _cairo_svg_surface_is_pattern_supported (surface, source) &&
+	       _cairo_svg_surface_is_pattern_supported (surface, mask)
+	       ? CAIRO_STATUS_SUCCESS
+	       : CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    _CAIRO_SVG_SURFACE_CALL_OPERATOR_IMPL (_cairo_svg_surface_mask_impl,
+					   source,
+					   mask)
+}
+
 static cairo_int_status_t
 _cairo_svg_surface_stroke (void			*abstract_dst,
 			   cairo_operator_t      op,
@@ -3053,8 +3113,9 @@ _cairo_svg_document_create (cairo_output_stream_t	 *output_stream,
     document->clip_id = 0;
     document->mask_id = 0;
     document->composing_group_id = 0;
+    document->filter_id = 0;
 
-    for (enum cairo_svg_filter filter = 0; filter < CAIRO_SVG_FILTER_LAST_FILTER; filter++) {
+    for (enum cairo_svg_filter filter = 0; filter < CAIRO_SVG_FILTER_LAST_STATIC_FILTER; filter++) {
 	document->filters_emitted[filter] = FALSE;
     }
 
commit a89960a67cdb239b17bb127f5cf08bb787307445
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Fri Apr 9 04:18:42 2021 +0200

    Add support for the source and clear operators for the paint operation

diff --git a/src/cairo-svg-surface-private.h b/src/cairo-svg-surface-private.h
index 564316812..f64814fe2 100644
--- a/src/cairo-svg-surface-private.h
+++ b/src/cairo-svg-surface-private.h
@@ -71,6 +71,7 @@ typedef struct cairo_svg_surface {
     cairo_hash_table_t    *source_surfaces;
 
     cairo_surface_clipper_t clipper;
+    cairo_output_stream_t *current_clipper_output_stream;
     unsigned int clip_level;
 
     cairo_paginated_mode_t paginated_mode;
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index c0505518a..ef2429293 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -114,12 +114,6 @@ static const char * _cairo_svg_version_strings[CAIRO_SVG_VERSION_LAST] =
     "SVG 1.2"
 };
 
-static const char * _cairo_svg_internal_version_strings[CAIRO_SVG_VERSION_LAST] =
-{
-    "1.1",
-    "1.2"
-};
-
 static const char * _cairo_svg_unit_strings[] =
 {
     "",
@@ -137,6 +131,7 @@ static const char * _cairo_svg_unit_strings[] =
 enum cairo_svg_filter {
     CAIRO_SVG_FILTER_REMOVE_COLOR,
     CAIRO_SVG_FILTER_COLOR_TO_ALPHA,
+    CAIRO_SVG_FILTER_ALL_INVERT,
     CAIRO_SVG_FILTER_LAST_FILTER,
 };
 
@@ -164,6 +159,7 @@ struct cairo_svg_document {
     unsigned int pattern_id;
     unsigned int clip_id;
     unsigned int mask_id;
+    unsigned int composing_group_id;
 
     cairo_bool_t filters_emitted[CAIRO_SVG_FILTER_LAST_FILTER];
 
@@ -188,9 +184,6 @@ _cairo_svg_document_finish (cairo_svg_document_t *document);
 static cairo_svg_document_t *
 _cairo_svg_document_reference (cairo_svg_document_t *document);
 
-static unsigned int
-_cairo_svg_document_allocate_mask_id (cairo_svg_document_t *document);
-
 static cairo_surface_t *
 _cairo_svg_surface_create_for_document (cairo_svg_document_t	*document,
 					cairo_content_t		 content,
@@ -613,7 +606,7 @@ _cairo_svg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper
 
     if (path == NULL) {
 	for (unsigned int i = 0; i < surface->clip_level; i++) {
-	    _cairo_output_stream_printf (surface->xml_node, "</g>\n");
+	    _cairo_output_stream_printf (surface->current_clipper_output_stream, "</g>\n");
 	}
 	surface->clip_level = 0;
 	return CAIRO_STATUS_SUCCESS;
@@ -625,7 +618,7 @@ _cairo_svg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper
     }
 
     _cairo_output_stream_printf (document->xml_node_defs,
-				 "<clipPath id=\"clip%d\">\n"
+				 "<clipPath id=\"clip-%d\">\n"
 				 "<path ",
 				 document->clip_id);
     _cairo_svg_surface_emit_path (document->xml_node_defs, path, NULL);
@@ -634,8 +627,8 @@ _cairo_svg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper
 				 "/>\n"
 				 "</clipPath>\n");
 
-    _cairo_output_stream_printf (surface->xml_node,
-				 "<g clip-path=\"url(#clip%d)\" "
+    _cairo_output_stream_printf (surface->current_clipper_output_stream,
+				 "<g clip-path=\"url(#clip-%d)\" "
 				 "clip-rule=\"%s\">\n",
 				 document->clip_id,
 				 fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero");
@@ -646,20 +639,28 @@ _cairo_svg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper
     return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_status_t
-_cairo_svg_surface_set_clip (cairo_svg_surface_t *surface, const cairo_clip_t *clip)
-{
-    return _cairo_surface_clipper_set_clip (&surface->clipper, clip);
-}
-
 static void
 _cairo_svg_surface_reset_clip (cairo_svg_surface_t *surface)
 {
-    for (unsigned int i = 0; i < surface->clip_level; i++) {
-	_cairo_output_stream_printf (surface->xml_node, "</g>\n");
+    _cairo_surface_clipper_reset (&surface->clipper);
+    if (surface->current_clipper_output_stream != NULL) {
+	for (unsigned int i = 0; i < surface->clip_level; i++) {
+	    _cairo_output_stream_printf (surface->current_clipper_output_stream, "</g>\n");
+	}
     }
     surface->clip_level = 0;
-    _cairo_surface_clipper_reset (&surface->clipper);
+}
+
+static cairo_status_t
+_cairo_svg_surface_set_clip (cairo_svg_surface_t *surface,
+			     cairo_output_stream_t *clipper_output_stream,
+			     const cairo_clip_t *clip)
+{
+    if (surface->current_clipper_output_stream != clipper_output_stream) {
+	_cairo_svg_surface_reset_clip (surface);
+	surface->current_clipper_output_stream = clipper_output_stream;
+    }
+    return _cairo_surface_clipper_set_clip (&surface->clipper, clip);
 }
 
 static cairo_surface_t *
@@ -689,9 +690,9 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t	*document,
 
     surface->document = _cairo_svg_document_reference (document);
 
+    _cairo_surface_clipper_init (&surface->clipper, _cairo_svg_surface_clipper_intersect_clip_path);
+    surface->current_clipper_output_stream = NULL;
     surface->clip_level = 0;
-    _cairo_surface_clipper_init (&surface->clipper,
-				 _cairo_svg_surface_clipper_intersect_clip_path);
 
     surface->xml_node = _cairo_memory_stream_create ();
 
@@ -1024,7 +1025,7 @@ _cairo_svg_document_emit_glyph (cairo_svg_document_t	*document,
     cairo_int_status_t	     status;
 
     _cairo_output_stream_printf (document->xml_node_glyphs,
-				 "<symbol overflow=\"visible\" id=\"glyph%d-%d\">\n",
+				 "<symbol overflow=\"visible\" id=\"glyph-%d-%d\">\n",
 				 font_id,
 				 subset_glyph_index);
 
@@ -1087,26 +1088,6 @@ _cairo_svg_document_emit_font_subsets (cairo_svg_document_t *document)
     return status;
 }
 
-static char const *
-_cairo_svg_surface_operators[] = {
-    "clear",
-
-    "src", "src-over", "src-in",
-    "src-out", "src-atop",
-
-    "dst", "dst-over", "dst-in",
-    "dst-out", "dst-atop",
-
-    "xor", "plus",
-    "color-dodge", /* FIXME: saturate ? */
-
-    "multiply",	"screen", "overlay",
-    "darken", "lighten",
-    "color-dodge", "color-burn",
-    "hard-light", "soft-light",
-    "difference", "exclusion"
-};
-
 static cairo_bool_t
 _cairo_svg_surface_is_pattern_supported (cairo_svg_surface_t *surface,
 					 const cairo_pattern_t *pattern)
@@ -1199,6 +1180,17 @@ _cairo_svg_surface_emit_filter (cairo_svg_document_t *document, enum cairo_svg_f
 					     /*                   */ "0.2126 0.7152 0.0722 0 0\"/>\n"
 					     "</filter>\n");
 		break;
+	    case CAIRO_SVG_FILTER_ALL_INVERT:
+	        // (r, g, b, a) -> (1 - r, 1 - g, 1 - b, 1 - a)
+		_cairo_output_stream_printf (document->xml_node_filters,
+					     "<filter id=\"filter-all-invert\" "
+					     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
+					     "<feColorMatrix values=\"-1 0 0 0 1 "
+					     /*                   */ "0 -1 0 0 1 "
+					     /*                   */ "0 0 -1 0 1 "
+					     /*                   */ "0 0 0 -1 1\"/>\n"
+					     "</filter>\n");
+		break;
 	    default:
 		ASSERT_NOT_REACHED;
 	}
@@ -1209,6 +1201,8 @@ _cairo_svg_surface_emit_filter (cairo_svg_document_t *document, enum cairo_svg_f
 	    return "filter-remove-color";
 	case CAIRO_SVG_FILTER_COLOR_TO_ALPHA:
 	    return "filter-color-to-alpha";
+	case CAIRO_SVG_FILTER_ALL_INVERT:
+	    return "filter-all-invert";
 	default:
 	    ASSERT_NOT_REACHED;
     }
@@ -1392,32 +1386,6 @@ _cairo_surface_base64_encode (cairo_surface_t       *surface,
     return status;
 }
 
-static void
-_cairo_svg_surface_emit_operator (cairo_output_stream_t *output,
-				  cairo_svg_surface_t   *surface,
-				  cairo_operator_t	 op)
-{
-    if (surface->document->svg_version >= CAIRO_SVG_VERSION_1_2 &&
-	op != CAIRO_OPERATOR_OVER) {
-	_cairo_output_stream_printf (output, " comp-op=\"%s\"", _cairo_svg_surface_operators[op]);
-	if (!_cairo_operator_bounded_by_source (op))
-	   _cairo_output_stream_printf (output, " clip-to-self=\"true\"");
-    }
-}
-
-static void
-_cairo_svg_surface_emit_operator_for_style (cairo_output_stream_t *output,
-					    cairo_svg_surface_t   *surface,
-					    cairo_operator_t	 op)
-{
-    if (surface->document->svg_version >= CAIRO_SVG_VERSION_1_2 &&
-	op != CAIRO_OPERATOR_OVER) {
-	_cairo_output_stream_printf (output, "comp-op:%s;", _cairo_svg_surface_operators[op]);
-	if (!_cairo_operator_bounded_by_source (op))
-	   _cairo_output_stream_printf (output, "clip-to-self:true;");
-    }
-}
-
 /**
  * _cairo_svg_surface_emit_attr_value:
  *
@@ -1472,7 +1440,7 @@ _cairo_svg_surface_emit_surface (cairo_svg_document_t *document,
     assert (is_bounded);
 
     _cairo_output_stream_printf (document->xml_node_defs,
-				 "<image id=\"image%d\" x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" xlink:href=\"",
+				 "<image id=\"image-%d\" x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" xlink:href=\"",
 				 source_id,
 				 extents.x, extents.y,
 				 extents.width, extents.height);
@@ -1497,7 +1465,6 @@ _cairo_svg_surface_emit_surface (cairo_svg_document_t *document,
 static cairo_status_t
 _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t   *output,
 						   cairo_svg_surface_t	 *svg_surface,
-						   cairo_operator_t	  op,
 						   cairo_surface_pattern_t *pattern,
 						   unsigned int		  pattern_id,
 						   const cairo_matrix_t	 *parent_matrix)
@@ -1535,7 +1502,7 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t   *outp
 	assert (is_bounded);
 
 	_cairo_output_stream_printf (output,
-				     "<pattern id=\"pattern%d\" "
+				     "<pattern id=\"pattern-%d\" "
 				     "patternUnits=\"userSpaceOnUse\" "
 				     "x=\"%d\" y=\"%d\" "
 				     "width=\"%d\" height=\"%d\" "
@@ -1559,11 +1526,10 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t   *outp
     }
 
     _cairo_output_stream_printf (output,
-				 "<use xlink:href=\"#image%d\"",
+				 "<use xlink:href=\"#image-%d\"",
 				 source_id);
 
     if (pattern_id == invalid_pattern_id) {
-	_cairo_svg_surface_emit_operator (output, svg_surface, op);
 	_cairo_svg_surface_emit_transform (output,
 					   " transform",
 					   &p2u, parent_matrix);
@@ -1623,7 +1589,7 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
 
     if (bounded) {
 	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<clipPath id=\"clip%d\">\n"
+				     "<clipPath id=\"clip-%d\">\n"
 				     "<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"/>\n"
 				     "</clipPath>\n",
 				     svg_surface->document->clip_id,
@@ -1634,12 +1600,12 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
     }
 
     _cairo_output_stream_printf (document->xml_node_defs,
-				 "<g id=\"surface%d\"",
+				 "<g id=\"surface-%d\"",
 				 source_id);
 
     if (bounded) {
 	_cairo_output_stream_printf (document->xml_node_defs,
-				     " clip-path=\"url(#clip%d)\"",
+				     " clip-path=\"url(#clip-%d)\"",
 				     svg_surface->document->clip_id);
     }
 
@@ -1707,7 +1673,6 @@ _cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (const cairo_pattern_t *p
 static cairo_status_t
 _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t	*output,
 						     cairo_svg_surface_t	*surface,
-						     cairo_operator_t	         op,
 						     cairo_surface_pattern_t	*pattern,
 						     unsigned int		 pattern_id,
 						     const cairo_matrix_t	*parent_matrix)
@@ -1741,7 +1706,7 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t	*outp
     if (pattern_id != invalid_pattern_id) {
         assert (!recording_surface->unbounded);
 	_cairo_output_stream_printf (output,
-				     "<pattern id=\"pattern%d\" "
+				     "<pattern id=\"pattern-%d\" "
 				     "patternUnits=\"userSpaceOnUse\" "
 				     "x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" "
 				     "viewBox=\"%f %f %f %f\"",
@@ -1759,11 +1724,10 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t	*outp
     }
 
     _cairo_output_stream_printf (output,
-				 "<use xlink:href=\"#surface%d\"",
+				 "<use xlink:href=\"#surface-%d\"",
 				 source_id);
 
     if (pattern_id == invalid_pattern_id) {
-	_cairo_svg_surface_emit_operator (output, surface, op);
 	_cairo_svg_surface_emit_transform (output, " transform", &p2u, parent_matrix);
     }
 
@@ -1778,7 +1742,6 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t	*outp
 static cairo_status_t
 _cairo_svg_surface_emit_composite_pattern (cairo_output_stream_t   *output,
 					   cairo_svg_surface_t	   *surface,
-					   cairo_operator_t	    op,
 					   cairo_surface_pattern_t *pattern,
 					   unsigned int		    pattern_id,
 					   const cairo_matrix_t	   *parent_matrix)
@@ -1789,13 +1752,13 @@ _cairo_svg_surface_emit_composite_pattern (cairo_output_stream_t   *output,
 
     if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
 	return _cairo_svg_surface_emit_composite_recording_pattern (output, surface,
-								    op, pattern,
+								    pattern,
 								    pattern_id,
 								    parent_matrix);
     }
 
     return _cairo_svg_surface_emit_composite_surface_pattern (output, surface,
-							      op, pattern,
+							      pattern,
 							      pattern_id,
 							      parent_matrix);
 }
@@ -1826,17 +1789,17 @@ _cairo_svg_surface_emit_surface_pattern (cairo_svg_surface_t	 *surface,
 {
     cairo_svg_document_t *document = surface->document;
     cairo_status_t status;
-    unsigned int pattern_id;
 
-    pattern_id = document->pattern_id++;
+    unsigned int pattern_id = document->pattern_id++;
+
     status = _cairo_svg_surface_emit_composite_pattern (document->xml_node_defs,
-	                                                surface, CAIRO_OPERATOR_SOURCE, pattern,
+	                                                surface, pattern,
 							pattern_id, parent_matrix);
     if (unlikely (status))
 	return status;
 
     _cairo_output_stream_printf (style,
-				 "%s:url(#pattern%d);",
+				 "%s:url(#pattern-%d);",
 				 is_stroke ? "stroke" : "fill",
 				 pattern_id);
 
@@ -2040,7 +2003,7 @@ _cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t    *surface,
     assert (status == CAIRO_STATUS_SUCCESS);
 
     _cairo_output_stream_printf (document->xml_node_defs,
-				 "<linearGradient id=\"linear%d\" "
+				 "<linearGradient id=\"linear-%d\" "
 				 "gradientUnits=\"userSpaceOnUse\" "
 				 "x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" ",
 				 document->linear_pattern_id,
@@ -2061,7 +2024,7 @@ _cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t    *surface,
 				 "</linearGradient>\n");
 
     _cairo_output_stream_printf (style,
-				 "%s:url(#linear%d);",
+				 "%s:url(#linear-%d);",
 				 is_stroke ? "stroke" : "fill",
 				 document->linear_pattern_id);
 
@@ -2114,7 +2077,7 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t    *surface,
 	unsigned int n_stops = pattern->base.n_stops;
 
 	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<radialGradient id=\"radial%d\" "
+				     "<radialGradient id=\"radial-%d\" "
 				     "gradientUnits=\"userSpaceOnUse\" "
 				     "cx=\"%f\" cy=\"%f\" "
 				     "fx=\"%f\" fy=\"%f\" r=\"%f\" ",
@@ -2195,7 +2158,7 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t    *surface,
 	}
 
 	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<radialGradient id=\"radial%d\" "
+				     "<radialGradient id=\"radial-%d\" "
 				     "gradientUnits=\"userSpaceOnUse\" "
 				     "cx=\"%f\" cy=\"%f\" "
 				     "fx=\"%f\" fy=\"%f\" r=\"%f\" ",
@@ -2243,7 +2206,7 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t    *surface,
 				 "</radialGradient>\n");
 
     _cairo_output_stream_printf (style,
-				 "%s:url(#radial%d);",
+				 "%s:url(#radial-%d);",
 				 is_stroke ? "stroke" : "fill",
 				 document->radial_pattern_id);
 
@@ -2286,7 +2249,6 @@ _cairo_svg_surface_emit_pattern (cairo_svg_surface_t   *surface,
 static cairo_status_t
 _cairo_svg_surface_emit_fill_style (cairo_output_stream_t	*output,
 				    cairo_svg_surface_t		*surface,
-				    cairo_operator_t		 op,
 				    const cairo_pattern_t	*source,
 				    cairo_fill_rule_t		 fill_rule,
 				    const cairo_matrix_t	*parent_matrix)
@@ -2295,14 +2257,12 @@ _cairo_svg_surface_emit_fill_style (cairo_output_stream_t	*output,
 				 "fill-rule:%s;",
 				 fill_rule == CAIRO_FILL_RULE_EVEN_ODD ?
 				 "evenodd" : "nonzero");
-    _cairo_svg_surface_emit_operator_for_style (output, surface, op);
     return _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, parent_matrix);
 }
 
 static cairo_status_t
 _cairo_svg_surface_emit_stroke_style (cairo_output_stream_t	   *output,
 				      cairo_svg_surface_t	   *surface,
-				      cairo_operator_t		    op,
 				      const cairo_pattern_t	   *source,
 				      const cairo_stroke_style_t   *stroke_style,
 				      const cairo_matrix_t	   *parent_matrix)
@@ -2351,8 +2311,6 @@ _cairo_svg_surface_emit_stroke_style (cairo_output_stream_t	   *output,
      if (unlikely (status))
 	 return status;
 
-     _cairo_svg_surface_emit_operator_for_style (output, surface, op);
-
     if (stroke_style->num_dashes > 0) {
 	_cairo_output_stream_printf (output, "stroke-dasharray:");
 	for (i = 0; i < stroke_style->num_dashes; i++) {
@@ -2399,7 +2357,6 @@ _cairo_svg_surface_get_extents (void		        *abstract_surface,
 static cairo_status_t
 _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
 			       cairo_svg_surface_t   *surface,
-			       cairo_operator_t	      op,
 			       const cairo_pattern_t	     *source,
 			       const cairo_pattern_t	     *mask_source)
 {
@@ -2408,7 +2365,6 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
     if (_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used(source))
 	return _cairo_svg_surface_emit_composite_pattern (output,
 							  surface,
-							  op,
 							  (cairo_surface_pattern_t *) source,
 							  invalid_pattern_id,
 							  mask_source ? &mask_source->matrix : NULL);
@@ -2417,7 +2373,6 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
 				 "<rect x=\"-1000000%%\" y=\"-1000000%%\" "
 				 "width=\"2000000%%\" height=\"2000000%%\" "
 				 "style=\"");
-    _cairo_svg_surface_emit_operator_for_style (output, surface, op);
     status = _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, NULL);
     if (unlikely (status))
 	return status;
@@ -2430,10 +2385,111 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
 }
 
 static cairo_int_status_t
-_cairo_svg_surface_paint (void		    *abstract_surface,
-			  cairo_operator_t   op,
-			  const cairo_pattern_t   *source,
-			  const cairo_clip_t	  *clip)
+_cairo_svg_surface_do_operator (cairo_output_stream_t *output,
+				cairo_svg_surface_t *surface,
+				cairo_operator_t op,
+				const cairo_clip_t *clip,
+				cairo_output_stream_t *mask_stream,
+				const cairo_pattern_t *source,
+				cairo_output_stream_t *destination_stream)
+{
+    cairo_status_t status;
+    cairo_svg_document_t *document = surface->document;
+
+    if (op == CAIRO_OPERATOR_CLEAR) {
+	cairo_pattern_t *transparent_pattern = cairo_pattern_create_rgba (0.0, 0.0, 0.0, 0.0);
+	status = _cairo_svg_surface_do_operator (output,
+						 surface,
+						 CAIRO_OPERATOR_SOURCE,
+						 clip,
+						 mask_stream,
+						 transparent_pattern,
+						 destination_stream);
+	cairo_pattern_destroy (transparent_pattern);
+	return status;
+    }
+
+    if (op == CAIRO_OPERATOR_SOURCE) {
+	unsigned int composing_group_id = document->composing_group_id++;
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     "<g id=\"composing-group-%d\">\n",
+				     composing_group_id);
+	status = _cairo_svg_surface_set_clip (surface, document->xml_node_defs, clip);
+	if (unlikely (status)) {
+	    cairo_status_t ignore1 = _cairo_output_stream_destroy (mask_stream);
+	    cairo_status_t ignore2 = _cairo_output_stream_destroy (destination_stream);
+	    return status;
+	    (void) ignore1;
+	    (void) ignore2;
+	}
+	_cairo_memory_stream_copy (mask_stream, document->xml_node_defs);
+	status = _cairo_output_stream_destroy (mask_stream);
+	if (unlikely (status)) {
+	    return status;
+	}
+	_cairo_svg_surface_reset_clip (surface);
+	_cairo_output_stream_printf (document->xml_node_defs, "</g>\n");
+
+	unsigned int source_mask_id = document->mask_id++;
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     "<mask id=\"mask-%d\">\n",
+				     source_mask_id);
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     "<use xlink:href=\"#composing-group-%d\"/>\n",
+				     composing_group_id);
+	_cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
+
+	_cairo_output_stream_printf (surface->xml_node,
+				     "<g mask=\"url(#mask-%d)\">\n",
+				     source_mask_id);
+	status = _cairo_svg_surface_emit_paint (surface->xml_node,
+						surface,
+						source,
+						NULL);
+	if (unlikely (status)) {
+	    cairo_status_t ignore = _cairo_output_stream_destroy (destination_stream);
+	    return status;
+	    (void) ignore;
+	}
+	_cairo_output_stream_printf (surface->xml_node, "</g>\n");
+
+	unsigned int destination_mask_id = document->mask_id++;
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     "<mask id=\"mask-%d\">\n",
+				     destination_mask_id);
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     "<use xlink:href=\"#composing-group-%d\"  filter=\"url(#%s)\"/>\n",
+				     composing_group_id,
+				     _cairo_svg_surface_emit_filter (document, CAIRO_SVG_FILTER_ALL_INVERT));
+	_cairo_output_stream_printf (document->xml_node_defs, "</mask>\n");
+
+	_cairo_output_stream_printf (surface->xml_node,
+				     "<g mask=\"url(#mask-%d)\">\n",
+				     destination_mask_id);
+	_cairo_memory_stream_copy (destination_stream, surface->xml_node);
+	status = _cairo_output_stream_destroy (destination_stream);
+	if (unlikely (status)) {
+	    return status;
+	}
+	_cairo_output_stream_printf (surface->xml_node, "</g>\n");
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_svg_surface_paint_impl (cairo_output_stream_t *output,
+			       cairo_svg_surface_t *surface,
+			       const cairo_pattern_t *source)
+{
+    return _cairo_svg_surface_emit_paint (output, surface, source, NULL);
+}
+
+static cairo_int_status_t
+_cairo_svg_surface_paint (void *abstract_surface,
+			  cairo_operator_t op,
+			  const cairo_pattern_t *source,
+			  const cairo_clip_t *clip)
 {
     cairo_status_t status;
     cairo_svg_surface_t *surface = abstract_surface;
@@ -2449,7 +2505,6 @@ _cairo_svg_surface_paint (void		    *abstract_surface,
 	case CAIRO_PAGINATED_MODE_RENDER:
 	    status = _cairo_output_stream_destroy (surface->xml_node);
 	    if (unlikely (status)) {
-		surface->xml_node = NULL;
 		return status;
 	    }
 
@@ -2471,12 +2526,33 @@ _cairo_svg_surface_paint (void		    *abstract_surface,
 	       : CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    status = _cairo_svg_surface_set_clip (surface, clip);
-    if (unlikely (status))
-	return status;
-
-    return _cairo_svg_surface_emit_paint (surface->xml_node,
-					  surface, op, source, NULL);
+    if (op == CAIRO_OPERATOR_OVER) {
+	status = _cairo_svg_surface_set_clip (surface, surface->xml_node, clip);
+	if (unlikely (status)) {
+	    return status;
+	}
+	return _cairo_svg_surface_paint_impl (surface->xml_node, surface, source);
+    } else {
+	_cairo_svg_surface_reset_clip (surface);
+        cairo_output_stream_t *mask_stream = _cairo_memory_stream_create ();
+	cairo_pattern_t *white_pattern = cairo_pattern_create_rgb (1.0, 1.0, 1.0);
+	status = _cairo_svg_surface_paint_impl (mask_stream, surface, white_pattern);
+	cairo_pattern_destroy (white_pattern);
+	if (unlikely (status)) {
+	    cairo_status_t ignore = _cairo_output_stream_destroy (mask_stream);
+	    return status;
+	    (void) ignore;
+	}
+	cairo_output_stream_t *destination_stream = surface->xml_node;
+	surface->xml_node = _cairo_memory_stream_create ();
+	return _cairo_svg_surface_do_operator (surface->xml_node,
+					       surface,
+					       op,
+					       clip,
+					       mask_stream,
+					       source,
+					       destination_stream);
+    }
 }
 
 static cairo_int_status_t
@@ -2489,8 +2565,6 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
     cairo_status_t status;
     cairo_svg_surface_t *surface = abstract_surface;
     cairo_svg_document_t *document = surface->document;
-    cairo_output_stream_t *mask_stream;
-    unsigned int mask_id;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
 	return _cairo_svg_surface_is_pattern_supported (surface, source) &&
@@ -2499,47 +2573,47 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
 	       : CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    status = _cairo_svg_surface_set_clip (surface, clip);
-    if (unlikely (status))
+    status = _cairo_svg_surface_set_clip (surface, surface->xml_node, clip);
+    if (unlikely (status)) {
 	return status;
+    }
 
     /* _cairo_svg_surface_emit_paint() will output a pattern definition to
      * document->xml_node_defs so we need to write the mask element to
      * a temporary stream and then copy that to xml_node_defs. */
-    mask_stream = _cairo_memory_stream_create ();
+    cairo_output_stream_t *temporary_mask_stream = _cairo_memory_stream_create ();
 
-    mask_id = _cairo_svg_document_allocate_mask_id (document);
+    unsigned int mask_id = document->mask_id++;
 
-    _cairo_output_stream_printf (mask_stream,
-				 "<mask id=\"mask%d\">\n",
+    _cairo_output_stream_printf (temporary_mask_stream,
+				 "<mask id=\"mask-%d\">\n",
 				 mask_id);
-    _cairo_output_stream_printf (mask_stream,
+    _cairo_output_stream_printf (temporary_mask_stream,
 				 "<g filter=\"url(#%s)\">\n",
 				 _cairo_svg_surface_emit_filter (document, CAIRO_SVG_FILTER_REMOVE_COLOR));
-    status = _cairo_svg_surface_emit_paint (mask_stream, surface, CAIRO_OPERATOR_OVER, mask, source);
+    status = _cairo_svg_surface_emit_paint (temporary_mask_stream, surface, mask, source);
     if (unlikely (status)) {
-	cairo_status_t ignore = _cairo_output_stream_destroy (mask_stream);
+	cairo_status_t ignore = _cairo_output_stream_destroy (temporary_mask_stream);
 	return status;
 	(void) ignore;
     }
 
-    _cairo_output_stream_printf (mask_stream,
+    _cairo_output_stream_printf (temporary_mask_stream,
 				 "</g>\n"
 				 "</mask>\n");
-    _cairo_memory_stream_copy (mask_stream, document->xml_node_defs);
+    _cairo_memory_stream_copy (temporary_mask_stream, document->xml_node_defs);
 
-    status = _cairo_output_stream_destroy (mask_stream);
+    status = _cairo_output_stream_destroy (temporary_mask_stream);
     if (unlikely (status)) {
 	return status;
     }
 
     _cairo_output_stream_printf (surface->xml_node,
-				 "<g mask=\"url(#mask%d)\">\n",
+				 "<g mask=\"url(#mask-%d)\">\n",
 				 mask_id);
 
     status = _cairo_svg_surface_emit_paint (surface->xml_node,
 					    surface,
-					    op,
 					    source,
 					    NULL);
     if (unlikely (status)) {
@@ -2572,7 +2646,7 @@ _cairo_svg_surface_stroke (void			*abstract_dst,
 	       : CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    status = _cairo_svg_surface_set_clip (surface, clip);
+    status = _cairo_svg_surface_set_clip (surface, surface->xml_node, clip);
     if (unlikely (status)) {
 	return status;
     }
@@ -2582,12 +2656,12 @@ _cairo_svg_surface_stroke (void			*abstract_dst,
     cairo_output_stream_t *output_stream = surface->xml_node;
     cairo_pattern_t *white_pattern;
     if (svg_clip_or_svg_mask_should_be_used) {
-	mask_id = _cairo_svg_document_allocate_mask_id (surface->document);
+	mask_id = surface->document->mask_id++;
 
 	output_stream = surface->document->xml_node_defs;
 
 	_cairo_output_stream_printf (output_stream,
-				     "<mask id=\"mask%d\">\n",
+				     "<mask id=\"mask-%d\">\n",
 				     mask_id);
 
 	white_pattern = cairo_pattern_create_rgb(1.0, 1.0, 1.0);
@@ -2596,7 +2670,6 @@ _cairo_svg_surface_stroke (void			*abstract_dst,
     _cairo_output_stream_printf (output_stream, "<path style=\"fill:none;");
     status = _cairo_svg_surface_emit_stroke_style (output_stream,
 						   surface,
-						   svg_clip_or_svg_mask_should_be_used ? CAIRO_OPERATOR_OVER : op,
 						   svg_clip_or_svg_mask_should_be_used ? white_pattern : source,
 						   stroke_style,
 						   ctm_inverse);
@@ -2620,12 +2693,11 @@ _cairo_svg_surface_stroke (void			*abstract_dst,
 				     "</mask>\n");
 
 	_cairo_output_stream_printf (surface->xml_node,
-				     "<g mask=\"url(#mask%d)\">\n",
+				     "<g mask=\"url(#mask-%d)\">\n",
 				     mask_id);
 
 	status = _cairo_svg_surface_emit_composite_pattern (surface->xml_node,
 							    surface,
-							    op,
 							    (cairo_surface_pattern_t *) source,
 							    invalid_pattern_id,
 							    NULL);
@@ -2658,14 +2730,14 @@ _cairo_svg_surface_fill (void *abstract_surface,
 	       : CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    status = _cairo_svg_surface_set_clip (surface, clip);
+    status = _cairo_svg_surface_set_clip (surface, surface->xml_node, clip);
     if (unlikely (status)) {
 	return status;
     }
 
     if (_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (source)) {
 	_cairo_output_stream_printf (surface->document->xml_node_defs,
-				     "<clipPath id=\"clip%d\">\n"
+				     "<clipPath id=\"clip-%d\">\n"
 				     "<path ",
 				     surface->document->clip_id);
 
@@ -2676,7 +2748,7 @@ _cairo_svg_surface_fill (void *abstract_surface,
 				     "</clipPath>\n");
 
 	_cairo_output_stream_printf (surface->xml_node,
-				     "<g clip-path=\"url(#clip%d)\" "
+				     "<g clip-path=\"url(#clip-%d)\" "
 				     "clip-rule=\"%s\" "
 				     "style=\"",
 				     surface->document->clip_id,
@@ -2684,13 +2756,10 @@ _cairo_svg_surface_fill (void *abstract_surface,
 
 	surface->document->clip_id++;
 
-	_cairo_svg_surface_emit_operator_for_style (surface->xml_node, surface, op);
-
 	_cairo_output_stream_printf (surface->xml_node, "\">\n");
 
 	status = _cairo_svg_surface_emit_composite_pattern (surface->xml_node,
 							    surface,
-							    op,
 							    (cairo_surface_pattern_t *) source,
 							    invalid_pattern_id,
 							    NULL);
@@ -2701,7 +2770,7 @@ _cairo_svg_surface_fill (void *abstract_surface,
 	_cairo_output_stream_printf (surface->xml_node, "</g>");
     } else {
 	_cairo_output_stream_printf (surface->xml_node, "<path style=\"");
-	status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, op, source, fill_rule, NULL);
+	status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, source, fill_rule, NULL);
 	if (unlikely (status)) {
 	    return status;
 	}
@@ -2761,19 +2830,19 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface,
 	       : CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    status = _cairo_svg_surface_set_clip (surface, clip);
+    status = _cairo_svg_surface_set_clip (surface, surface->xml_node, clip);
     if (unlikely (status)) {
 	return status;
     }
 
     _cairo_output_stream_printf (surface->xml_node, "<path style=\"");
-    status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, fill_op,
+    status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface,
 						 fill_source, fill_rule, stroke_ctm_inverse);
     if (unlikely (status)) {
 	return status;
     }
 
-    status = _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface, stroke_op,
+    status = _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface,
 						   stroke_source, stroke_style, stroke_ctm_inverse);
     if (unlikely (status)) {
 	return status;
@@ -2814,9 +2883,10 @@ _cairo_svg_surface_show_glyphs (void			*abstract_surface,
     if (num_glyphs <= 0)
 	return CAIRO_STATUS_SUCCESS;
 
-    status = _cairo_svg_surface_set_clip (surface, clip);
-    if (unlikely (status))
+    status = _cairo_svg_surface_set_clip (surface, surface->xml_node, clip);
+    if (unlikely (status)) {
 	return status;
+    }
 
     /* FIXME it's probably possible to apply a pattern of a gradient to
      * a group of symbols, but I don't know how yet. Gradients or patterns
@@ -2830,8 +2900,6 @@ _cairo_svg_surface_show_glyphs (void			*abstract_surface,
     if (unlikely (status))
 	return status;
 
-    _cairo_svg_surface_emit_operator_for_style (surface->xml_node, surface, op);
-
     _cairo_output_stream_printf (surface->xml_node, "\">\n");
 
     for (i = 0; i < num_glyphs; i++) {
@@ -2851,7 +2919,7 @@ _cairo_svg_surface_show_glyphs (void			*abstract_surface,
 	    return status;
 
 	_cairo_output_stream_printf (surface->xml_node,
-				     "<use xlink:href=\"#glyph%d-%d\" "
+				     "<use xlink:href=\"#glyph-%d-%d\" "
 				     "x=\"%f\" y=\"%f\"/>\n",
 				     subset_glyph.font_id,
                                      subset_glyph.subset_glyph_index,
@@ -2906,11 +2974,7 @@ _cairo_svg_surface_get_supported_mime_types (void	   *abstract_surface)
 static cairo_status_t
 _cairo_svg_surface_emit_paint_black (cairo_svg_surface_t *surface) {
     cairo_pattern_t *black_pattern = cairo_pattern_create_rgb (0.0, 0.0, 0.0);
-    cairo_status_t status = _cairo_svg_surface_emit_paint (surface->xml_node,
-							   surface,
-							   CAIRO_OPERATOR_OVER,
-							   black_pattern,
-							   NULL);
+    cairo_status_t status = _cairo_svg_surface_emit_paint (surface->xml_node, surface, black_pattern, NULL);
     cairo_pattern_destroy(black_pattern);
     return status;
 }
@@ -2988,6 +3052,7 @@ _cairo_svg_document_create (cairo_output_stream_t	 *output_stream,
     document->pattern_id = 0;
     document->clip_id = 0;
     document->mask_id = 0;
+    document->composing_group_id = 0;
 
     for (enum cairo_svg_filter filter = 0; filter < CAIRO_SVG_FILTER_LAST_FILTER; filter++) {
 	document->filters_emitted[filter] = FALSE;
@@ -3015,12 +3080,6 @@ _cairo_svg_document_reference (cairo_svg_document_t *document)
     return document;
 }
 
-static unsigned int
-_cairo_svg_document_allocate_mask_id (cairo_svg_document_t *document)
-{
-    return document->mask_id++;
-}
-
 static cairo_status_t
 _cairo_svg_document_destroy (cairo_svg_document_t *document)
 {
@@ -3075,11 +3134,10 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
 				 "<svg xmlns=\"http://www.w3.org/2000/svg\" "
 				 "xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
 				 "width=\"%f%s\" height=\"%f%s\" "
-				 "viewBox=\"0 0 %f %f\" version=\"%s\">\n",
+				 "viewBox=\"0 0 %f %f\">\n",
 				 document->width, _cairo_svg_unit_strings [document->unit],
 				 document->height, _cairo_svg_unit_strings [document->unit],
-				 document->width, document->height,
-				 _cairo_svg_internal_version_strings [document->svg_version]);
+				 document->width, document->height);
 
     status = _cairo_svg_document_emit_font_subsets (document);
 
@@ -3120,7 +3178,7 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
 		page = _cairo_array_index (&surface->page_set, i);
 		_cairo_output_stream_printf (output, "<page>\n");
 		_cairo_output_stream_printf (output,
-					     "<g id=\"surface%d\">\n",
+					     "<g id=\"surface-%d\">\n",
 					     page->surface_id);
 		_cairo_memory_stream_copy (page->xml_node, output);
 		_cairo_output_stream_printf (output, "</g>\n</page>\n");
@@ -3129,7 +3187,7 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
 	} else if (surface->page_set.num_elements > 0) {
 	    page = _cairo_array_index (&surface->page_set, surface->page_set.num_elements - 1);
 	    _cairo_output_stream_printf (output,
-					 "<g id=\"surface%d\">\n",
+					 "<g id=\"surface-%d\">\n",
 					 page->surface_id);
 	    _cairo_memory_stream_copy (page->xml_node, output);
 	    _cairo_output_stream_printf (output, "</g>\n");
commit f6f73ba83607a2d2ee20b550803b2a2de001c515
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Fri Apr 9 02:13:28 2021 +0200

    Add a layer of indiraction to calls to the clipper

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index af4bfded8..c0505518a 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -142,7 +142,6 @@ enum cairo_svg_filter {
 
 struct cairo_svg_page {
     unsigned int surface_id;
-    unsigned int clip_level;
     cairo_output_stream_t *xml_node;
 };
 
@@ -611,23 +610,23 @@ _cairo_svg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper
 						       cairo_svg_surface_t,
 						       clipper);
     cairo_svg_document_t *document = surface->document;
-    unsigned int i;
 
     if (path == NULL) {
-	for (i = 0; i < surface->clip_level; i++)
+	for (unsigned int i = 0; i < surface->clip_level; i++) {
 	    _cairo_output_stream_printf (surface->xml_node, "</g>\n");
-
+	}
 	surface->clip_level = 0;
 	return CAIRO_STATUS_SUCCESS;
     }
 
     /* skip trivial whole-page clips */
-    if (_cairo_svg_surface_cliprect_covers_surface (surface, path))
+    if (_cairo_svg_surface_cliprect_covers_surface (surface, path)) {
 	return CAIRO_STATUS_SUCCESS;
+    }
 
     _cairo_output_stream_printf (document->xml_node_defs,
 				 "<clipPath id=\"clip%d\">\n"
-				 "  <path ",
+				 "<path ",
 				 document->clip_id);
     _cairo_svg_surface_emit_path (document->xml_node_defs, path, NULL);
 
@@ -639,8 +638,7 @@ _cairo_svg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper
 				 "<g clip-path=\"url(#clip%d)\" "
 				 "clip-rule=\"%s\">\n",
 				 document->clip_id,
-				 fill_rule == CAIRO_FILL_RULE_EVEN_ODD ?
-				 "evenodd" : "nonzero");
+				 fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero");
 
     document->clip_id++;
     surface->clip_level++;
@@ -648,6 +646,22 @@ _cairo_svg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper
     return CAIRO_STATUS_SUCCESS;
 }
 
+static cairo_status_t
+_cairo_svg_surface_set_clip (cairo_svg_surface_t *surface, const cairo_clip_t *clip)
+{
+    return _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+}
+
+static void
+_cairo_svg_surface_reset_clip (cairo_svg_surface_t *surface)
+{
+    for (unsigned int i = 0; i < surface->clip_level; i++) {
+	_cairo_output_stream_printf (surface->xml_node, "</g>\n");
+    }
+    surface->clip_level = 0;
+    _cairo_surface_clipper_reset (&surface->clipper);
+}
+
 static cairo_surface_t *
 _cairo_svg_surface_create_for_document (cairo_svg_document_t	*document,
 					cairo_content_t		 content,
@@ -760,12 +774,12 @@ _cairo_svg_surface_store_page (cairo_svg_surface_t *surface)
     cairo_svg_page_t page;
     cairo_output_stream_t *stream;
     cairo_int_status_t status;
-    unsigned int i;
+
+    _cairo_svg_surface_reset_clip (surface);
 
     stream = _cairo_memory_stream_create ();
 
     page.surface_id = surface->base.unique_id;
-    page.clip_level = surface->clip_level;
     page.xml_node = surface->xml_node;
 
     if (_cairo_array_append (&surface->page_set, &page)) {
@@ -774,11 +788,6 @@ _cairo_svg_surface_store_page (cairo_svg_surface_t *surface)
     }
 
     surface->xml_node = stream;
-    surface->clip_level = 0;
-    for (i = 0; i < page.clip_level; i++)
-	_cairo_output_stream_printf (page.xml_node, "</g>\n");
-
-    _cairo_surface_clipper_reset (&surface->clipper);
 
     return _cairo_array_index (&surface->page_set,
 			       surface->page_set.num_elements - 1);
@@ -1172,30 +1181,22 @@ _cairo_svg_surface_emit_filter (cairo_svg_document_t *document, enum cairo_svg_f
 	        // (r, g, b, a) -> (1, 1, 1, a)
 		_cairo_output_stream_printf (document->xml_node_filters,
 					     "<filter id=\"filter-remove-color\" "
-					     "filterUnits=\"objectBoundingBox\" "
-					     "x=\"0%%\" y=\"0%%\" "
-					     "width=\"100%%\" height=\"100%%\">\n"
-					     "<feColorMatrix type=\"matrix\" "
-					     "in=\"SourceGraphic\" "
-					     "values=\"0 0 0 0 1 "
-					     /*    */ "0 0 0 0 1 "
-					     /*    */ "0 0 0 0 1 "
-					     /*    */ "0 0 0 1 0\"/>\n"
+					     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
+					     "<feColorMatrix values=\"0 0 0 0 1 "
+					     /*                   */ "0 0 0 0 1 "
+					     /*                   */ "0 0 0 0 1 "
+					     /*                   */ "0 0 0 1 0\"/>\n"
 					     "</filter>\n");
 		break;
 	    case CAIRO_SVG_FILTER_COLOR_TO_ALPHA:
 	        // (r, g, b, a) -> (1, 1, 1, 0.2126 * r + 0.7152 * g + 0.0722 * b)
 		_cairo_output_stream_printf (document->xml_node_filters,
 					     "<filter id=\"filter-color-to-alpha\" "
-					     "filterUnits=\"objectBoundingBox\" "
-					     "x=\"0%%\" y=\"0%%\" "
-					     "width=\"100%%\" height=\"100%%\">\n"
-					     "<feColorMatrix type=\"matrix\" "
-					     "in=\"SourceGraphic\" "
-					     "values=\"0 0 0 0 1 "
-					     /*    */ "0 0 0 0 1 "
-					     /*    */ "0 0 0 0 1 "
-					     /*    */ "0.2126 0.7152 0.0722 0 0\"/>\n"
+					     "x=\"0%%\" y=\"0%%\" width=\"100%%\" height=\"100%%\">\n"
+					     "<feColorMatrix values=\"0 0 0 0 1 "
+					     /*                   */ "0 0 0 0 1 "
+					     /*                   */ "0 0 0 0 1 "
+					     /*                   */ "0.2126 0.7152 0.0722 0 0\"/>\n"
 					     "</filter>\n");
 		break;
 	    default:
@@ -1471,13 +1472,11 @@ _cairo_svg_surface_emit_surface (cairo_svg_document_t *document,
     assert (is_bounded);
 
     _cairo_output_stream_printf (document->xml_node_defs,
-				 "<image id=\"image%d\" x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"",
+				 "<image id=\"image%d\" x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" xlink:href=\"",
 				 source_id,
 				 extents.x, extents.y,
 				 extents.width, extents.height);
 
-    _cairo_output_stream_printf (document->xml_node_defs, " xlink:href=\"");
-
     cairo_surface_get_mime_data (surface, CAIRO_MIME_TYPE_URI,
 				 &uri, &uri_len);
     if (uri != NULL) {
@@ -1540,7 +1539,7 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t   *outp
 				     "patternUnits=\"userSpaceOnUse\" "
 				     "x=\"%d\" y=\"%d\" "
 				     "width=\"%d\" height=\"%d\" "
-				     "viewBox=\"%d %d %d %d\" ",
+				     "viewBox=\"%d %d %d %d\"",
 				     pattern_id,
 				     extents.x, extents.y,
 				     extents.width, extents.height,
@@ -1549,7 +1548,7 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t   *outp
 	_cairo_svg_surface_emit_transform (output,
 					   " patternTransform",
 					   &p2u, parent_matrix);
-	_cairo_output_stream_printf (output, ">\n  ");
+	_cairo_output_stream_printf (output, ">\n");
     }
 
     if (pattern->surface->content == CAIRO_CONTENT_ALPHA) {
@@ -1650,8 +1649,7 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
 				     _cairo_svg_surface_emit_filter (document, CAIRO_SVG_FILTER_REMOVE_COLOR));
     }
 
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 ">\n");
+    _cairo_output_stream_printf (document->xml_node_defs, ">\n");
 
     if (bounded) {
 	svg_surface->document->clip_id++;
@@ -2473,7 +2471,7 @@ _cairo_svg_surface_paint (void		    *abstract_surface,
 	       : CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+    status = _cairo_svg_surface_set_clip (surface, clip);
     if (unlikely (status))
 	return status;
 
@@ -2501,7 +2499,7 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
 	       : CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+    status = _cairo_svg_surface_set_clip (surface, clip);
     if (unlikely (status))
 	return status;
 
@@ -2574,7 +2572,7 @@ _cairo_svg_surface_stroke (void			*abstract_dst,
 	       : CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+    status = _cairo_svg_surface_set_clip (surface, clip);
     if (unlikely (status)) {
 	return status;
     }
@@ -2660,7 +2658,7 @@ _cairo_svg_surface_fill (void *abstract_surface,
 	       : CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+    status = _cairo_svg_surface_set_clip (surface, clip);
     if (unlikely (status)) {
 	return status;
     }
@@ -2763,7 +2761,7 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface,
 	       : CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+    status = _cairo_svg_surface_set_clip (surface, clip);
     if (unlikely (status)) {
 	return status;
     }
@@ -2816,7 +2814,7 @@ _cairo_svg_surface_show_glyphs (void			*abstract_surface,
     if (num_glyphs <= 0)
 	return CAIRO_STATUS_SUCCESS;
 
-    status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+    status = _cairo_svg_surface_set_clip (surface, clip);
     if (unlikely (status))
 	return status;
 
@@ -2853,7 +2851,7 @@ _cairo_svg_surface_show_glyphs (void			*abstract_surface,
 	    return status;
 
 	_cairo_output_stream_printf (surface->xml_node,
-				     "  <use xlink:href=\"#glyph%d-%d\" "
+				     "<use xlink:href=\"#glyph%d-%d\" "
 				     "x=\"%f\" y=\"%f\"/>\n",
 				     subset_glyph.font_id,
                                      subset_glyph.subset_glyph_index,
commit daeb9736e9e25a88d9b9f46fca7fe7d2699915ca
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Fri Apr 9 01:26:29 2021 +0200

    Update the analyze mode of operations

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index b532b952f..af4bfded8 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -45,7 +45,6 @@
 #include "cairo-svg.h"
 
 #include "cairo-array-private.h"
-#include "cairo-analysis-surface-private.h"
 #include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-image-info-private.h"
@@ -1100,62 +1099,24 @@ _cairo_svg_surface_operators[] = {
 };
 
 static cairo_bool_t
-_cairo_svg_surface_analyze_operator (cairo_svg_surface_t   *surface,
-				      cairo_operator_t	     op)
+_cairo_svg_surface_is_pattern_supported (cairo_svg_surface_t *surface,
+					 const cairo_pattern_t *pattern)
 {
-    /* guard against newly added operators */
-    if (op >= ARRAY_LENGTH (_cairo_svg_surface_operators))
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    /* allow operators being NULL if they are unsupported */
-    if (_cairo_svg_surface_operators[op] == NULL)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_svg_surface_analyze_operation (cairo_svg_surface_t   *surface,
-				      cairo_operator_t	     op,
-				      const cairo_pattern_t *pattern)
-{
-    cairo_svg_document_t *document = surface->document;
-
-    if (surface->force_fallbacks &&
-	surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
-    {
-	return CAIRO_INT_STATUS_UNSUPPORTED;
+    if (surface->force_fallbacks) {
+	return FALSE;
     }
 
-    if (pattern->type == CAIRO_PATTERN_TYPE_MESH)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
+    if (pattern->type == CAIRO_PATTERN_TYPE_MESH) {
+	return FALSE;
+    }
 
     /* SVG doesn't support extends reflect and pad for surface pattern */
-    if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE &&
-	pattern->extend != CAIRO_EXTEND_NONE &&
-	pattern->extend != CAIRO_EXTEND_REPEAT)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    if (document->svg_version >= CAIRO_SVG_VERSION_1_2)
-	return _cairo_svg_surface_analyze_operator (surface, op);
-
-    if (op == CAIRO_OPERATOR_OVER)
-	return CAIRO_STATUS_SUCCESS;
-
-    /* The SOURCE operator is only supported if there is nothing
-     * painted underneath. */
-    if (op == CAIRO_OPERATOR_SOURCE)
-	return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
-
-    return CAIRO_INT_STATUS_UNSUPPORTED;
-}
+    if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE && (pattern->extend != CAIRO_EXTEND_NONE &&
+							pattern->extend != CAIRO_EXTEND_REPEAT)) {
+	return FALSE;
+    }
 
-static cairo_int_status_t
-_cairo_svg_surface_operation_supported (cairo_svg_surface_t	*surface,
-					cairo_operator_t	 op,
-					const cairo_pattern_t	*pattern)
-{
-    return _cairo_svg_surface_analyze_operation (surface, op, pattern) != CAIRO_INT_STATUS_UNSUPPORTED;
+    return TRUE;
 }
 
 static cairo_status_t
@@ -1664,7 +1625,7 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
     if (bounded) {
 	_cairo_output_stream_printf (document->xml_node_defs,
 				     "<clipPath id=\"clip%d\">\n"
-				     "  <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"/>\n"
+				     "<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"/>\n"
 				     "</clipPath>\n",
 				     svg_surface->document->clip_id,
 				     extents.x,
@@ -2418,140 +2379,6 @@ _cairo_svg_surface_emit_stroke_style (cairo_output_stream_t	   *output,
     return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_int_status_t
-_cairo_svg_surface_fill_stroke (void			*abstract_surface,
-				cairo_operator_t	 fill_op,
-				const cairo_pattern_t	*fill_source,
-				cairo_fill_rule_t	 fill_rule,
-				double			 fill_tolerance,
-				cairo_antialias_t	 fill_antialias,
-				const cairo_path_fixed_t*path,
-				cairo_operator_t	 stroke_op,
-				const cairo_pattern_t	*stroke_source,
-				const cairo_stroke_style_t	*stroke_style,
-				const cairo_matrix_t		*stroke_ctm,
-				const cairo_matrix_t		*stroke_ctm_inverse,
-				double			 stroke_tolerance,
-				cairo_antialias_t	 stroke_antialias,
-				const cairo_clip_t	*clip)
-{
-    cairo_svg_surface_t *surface = abstract_surface;
-    cairo_status_t status;
-
-    if (_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (fill_source) ||
-	_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (stroke_source)) {
-	status = _cairo_surface_fill (&surface->base, fill_op, fill_source, path,
-				      fill_rule, fill_tolerance, fill_antialias,
-				      clip);
-	if (unlikely (status))
-	    return status;
-
-	status = _cairo_surface_stroke (&surface->base, stroke_op, stroke_source, path,
-					stroke_style, stroke_ctm, stroke_ctm_inverse,
-					stroke_tolerance, stroke_antialias,
-					clip);
-	if (unlikely (status))
-	    return status;
-    }
-
-    status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
-    if (unlikely (status))
-	return status;
-
-    _cairo_output_stream_printf (surface->xml_node, "<path style=\"");
-    status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, fill_op,
-						 fill_source, fill_rule, stroke_ctm_inverse);
-    if (unlikely (status))
-	return status;
-
-    status = _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface, stroke_op,
-						   stroke_source, stroke_style, stroke_ctm_inverse);
-    if (unlikely (status))
-	return status;
-
-    _cairo_output_stream_printf (surface->xml_node, "\" ");
-
-    _cairo_svg_surface_emit_path (surface->xml_node, path, stroke_ctm_inverse);
-
-    _cairo_svg_surface_emit_transform (surface->xml_node, " transform", stroke_ctm, NULL);
-    _cairo_output_stream_printf (surface->xml_node, "/>\n");
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_svg_surface_fill (void			*abstract_surface,
-			 cairo_operator_t	 op,
-			 const cairo_pattern_t	*source,
-			 const cairo_path_fixed_t*path,
-			 cairo_fill_rule_t	 fill_rule,
-			 double			 tolerance,
-			 cairo_antialias_t	 antialias,
-			 const cairo_clip_t	*clip)
-{
-    cairo_svg_surface_t *surface = abstract_surface;
-    cairo_status_t status;
-
-    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
-	return _cairo_svg_surface_analyze_operation (surface, op, source);
-
-    assert (_cairo_svg_surface_operation_supported (surface, op, source));
-
-    status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
-    if (unlikely (status))
-	return status;
-
-    if (_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (source)) {
-	_cairo_output_stream_printf (surface->document->xml_node_defs,
-				     "<clipPath id=\"clip%d\">\n"
-				     "<path ",
-				     surface->document->clip_id);
-
-	_cairo_svg_surface_emit_path (surface->document->xml_node_defs, path, NULL);
-
-	_cairo_output_stream_printf (surface->document->xml_node_defs,
-				     "/>\n"
-				     "</clipPath>\n");
-
-	_cairo_output_stream_printf (surface->xml_node,
-				     "<g clip-path=\"url(#clip%d)\" "
-				     "clip-rule=\"%s\" "
-				     "style=\"",
-				     surface->document->clip_id,
-				     fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero");
-
-	surface->document->clip_id++;
-
-	_cairo_svg_surface_emit_operator_for_style (surface->xml_node, surface, op);
-
-	_cairo_output_stream_printf (surface->xml_node, "\">\n");
-
-	status = _cairo_svg_surface_emit_composite_pattern (surface->xml_node,
-							    surface,
-							    op,
-							    (cairo_surface_pattern_t *) source,
-							    invalid_pattern_id,
-							    NULL);
-	if (unlikely (status))
-	    return status;
-
-	_cairo_output_stream_printf (surface->xml_node, "</g>");
-    } else {
-	_cairo_output_stream_printf (surface->xml_node, "<path style=\"");
-	status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, op, source, fill_rule, NULL);
-	if (unlikely (status))
-	    return status;
-
-	_cairo_output_stream_printf (surface->xml_node, "\" ");
-
-	_cairo_svg_surface_emit_path (surface->xml_node, path, NULL);
-
-	_cairo_output_stream_printf (surface->xml_node, "/>\n");
-    }
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
 static cairo_bool_t
 _cairo_svg_surface_get_extents (void		        *abstract_surface,
 				cairo_rectangle_int_t   *rectangle)
@@ -2640,11 +2467,10 @@ _cairo_svg_surface_paint (void		    *abstract_surface,
 	case CAIRO_PAGINATED_MODE_FALLBACK:
 	    ASSERT_NOT_REACHED;
 	}
-    } else {
-	if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
-	    return _cairo_svg_surface_analyze_operation (surface, op, source);
-
-	assert (_cairo_svg_surface_operation_supported (surface, op, source));
+    } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+	return _cairo_svg_surface_is_pattern_supported (surface, source)
+	       ? CAIRO_STATUS_SUCCESS
+	       : CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
     status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
@@ -2669,27 +2495,12 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
     unsigned int mask_id;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
-	cairo_status_t source_status, mask_status;
-
-	source_status = _cairo_svg_surface_analyze_operation (surface, op, source);
-	if (_cairo_status_is_error (source_status))
-	    return source_status;
-
-	if (mask->has_component_alpha) {
-	    mask_status = CAIRO_INT_STATUS_UNSUPPORTED;
-	} else {
-	    mask_status = _cairo_svg_surface_analyze_operation (surface, op, mask);
-	    if (_cairo_status_is_error (mask_status))
-		return mask_status;
-	}
-
-	return _cairo_analysis_surface_merge_status (source_status,
-						     mask_status);
+	return _cairo_svg_surface_is_pattern_supported (surface, source) &&
+	       _cairo_svg_surface_is_pattern_supported (surface, mask)
+	       ? CAIRO_STATUS_SUCCESS
+	       : CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    assert (_cairo_svg_surface_operation_supported (surface, op, source));
-    assert (_cairo_svg_surface_operation_supported (surface, CAIRO_OPERATOR_OVER, mask));
-
     status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
     if (unlikely (status))
 	return status;
@@ -2757,10 +2568,11 @@ _cairo_svg_surface_stroke (void			*abstract_dst,
     cairo_svg_surface_t *surface = abstract_dst;
     cairo_status_t status;
 
-    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
-	return _cairo_svg_surface_analyze_operation (surface, op, source);
-
-    assert (_cairo_svg_surface_operation_supported (surface, op, source));
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+	return _cairo_svg_surface_is_pattern_supported (surface, source)
+	       ? CAIRO_STATUS_SUCCESS
+	       : CAIRO_INT_STATUS_UNSUPPORTED;
+    }
 
     status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
     if (unlikely (status)) {
@@ -2829,6 +2641,156 @@ _cairo_svg_surface_stroke (void			*abstract_dst,
     return CAIRO_STATUS_SUCCESS;
 }
 
+static cairo_int_status_t
+_cairo_svg_surface_fill (void *abstract_surface,
+			 cairo_operator_t op,
+			 const cairo_pattern_t *source,
+			 const cairo_path_fixed_t *path,
+			 cairo_fill_rule_t fill_rule,
+			 double tolerance,
+			 cairo_antialias_t antialias,
+			 const cairo_clip_t *clip)
+{
+    cairo_svg_surface_t *surface = abstract_surface;
+    cairo_status_t status;
+
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+	return _cairo_svg_surface_is_pattern_supported (surface, source)
+	       ? CAIRO_STATUS_SUCCESS
+	       : CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+    if (unlikely (status)) {
+	return status;
+    }
+
+    if (_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (source)) {
+	_cairo_output_stream_printf (surface->document->xml_node_defs,
+				     "<clipPath id=\"clip%d\">\n"
+				     "<path ",
+				     surface->document->clip_id);
+
+	_cairo_svg_surface_emit_path (surface->document->xml_node_defs, path, NULL);
+
+	_cairo_output_stream_printf (surface->document->xml_node_defs,
+				     "/>\n"
+				     "</clipPath>\n");
+
+	_cairo_output_stream_printf (surface->xml_node,
+				     "<g clip-path=\"url(#clip%d)\" "
+				     "clip-rule=\"%s\" "
+				     "style=\"",
+				     surface->document->clip_id,
+				     fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero");
+
+	surface->document->clip_id++;
+
+	_cairo_svg_surface_emit_operator_for_style (surface->xml_node, surface, op);
+
+	_cairo_output_stream_printf (surface->xml_node, "\">\n");
+
+	status = _cairo_svg_surface_emit_composite_pattern (surface->xml_node,
+							    surface,
+							    op,
+							    (cairo_surface_pattern_t *) source,
+							    invalid_pattern_id,
+							    NULL);
+	if (unlikely (status)) {
+	    return status;
+	}
+
+	_cairo_output_stream_printf (surface->xml_node, "</g>");
+    } else {
+	_cairo_output_stream_printf (surface->xml_node, "<path style=\"");
+	status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, op, source, fill_rule, NULL);
+	if (unlikely (status)) {
+	    return status;
+	}
+
+	_cairo_output_stream_printf (surface->xml_node, "\" ");
+
+	_cairo_svg_surface_emit_path (surface->xml_node, path, NULL);
+
+	_cairo_output_stream_printf (surface->xml_node, "/>\n");
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_svg_surface_fill_stroke (void *abstract_surface,
+				cairo_operator_t fill_op,
+				const cairo_pattern_t *fill_source,
+				cairo_fill_rule_t fill_rule,
+				double fill_tolerance,
+				cairo_antialias_t fill_antialias,
+				const cairo_path_fixed_t *path,
+				cairo_operator_t stroke_op,
+				const cairo_pattern_t *stroke_source,
+				const cairo_stroke_style_t *stroke_style,
+				const cairo_matrix_t *stroke_ctm,
+				const cairo_matrix_t *stroke_ctm_inverse,
+				double stroke_tolerance,
+				cairo_antialias_t stroke_antialias,
+				const cairo_clip_t *clip)
+{
+    cairo_svg_surface_t *surface = abstract_surface;
+    cairo_status_t status;
+
+    if (_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (fill_source) ||
+	_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (stroke_source)) {
+	status = _cairo_svg_surface_fill (abstract_surface, fill_op, fill_source, path,
+					  fill_rule, fill_tolerance, fill_antialias,
+					  clip);
+	if (unlikely (status)) {
+	    return status;
+	}
+
+	status = _cairo_svg_surface_stroke (abstract_surface, stroke_op, stroke_source, path,
+					    stroke_style, stroke_ctm, stroke_ctm_inverse,
+					    stroke_tolerance, stroke_antialias,
+					    clip);
+	if (unlikely (status)) {
+	    return status;
+	}
+    }
+
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+	return _cairo_svg_surface_is_pattern_supported (surface, fill_source)
+	       && _cairo_svg_surface_is_pattern_supported (surface, stroke_source)
+	       ? CAIRO_STATUS_SUCCESS
+	       : CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
+    if (unlikely (status)) {
+	return status;
+    }
+
+    _cairo_output_stream_printf (surface->xml_node, "<path style=\"");
+    status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, fill_op,
+						 fill_source, fill_rule, stroke_ctm_inverse);
+    if (unlikely (status)) {
+	return status;
+    }
+
+    status = _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface, stroke_op,
+						   stroke_source, stroke_style, stroke_ctm_inverse);
+    if (unlikely (status)) {
+	return status;
+    }
+
+    _cairo_output_stream_printf (surface->xml_node, "\" ");
+
+    _cairo_svg_surface_emit_path (surface->xml_node, path, stroke_ctm_inverse);
+
+    _cairo_svg_surface_emit_transform (surface->xml_node, " transform", stroke_ctm, NULL);
+    _cairo_output_stream_printf (surface->xml_node, "/>\n");
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
 static cairo_int_status_t
 _cairo_svg_surface_show_glyphs (void			*abstract_surface,
 				cairo_operator_t	 op,
@@ -2845,10 +2807,11 @@ _cairo_svg_surface_show_glyphs (void			*abstract_surface,
     cairo_scaled_font_subsets_glyph_t subset_glyph;
     int i;
 
-    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
-	return _cairo_svg_surface_analyze_operation (surface, op, pattern);
-
-    assert (_cairo_svg_surface_operation_supported (surface, op, pattern));
+    if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+	return _cairo_svg_surface_is_pattern_supported (surface, pattern)
+	       ? CAIRO_STATUS_SUCCESS
+	       : CAIRO_INT_STATUS_UNSUPPORTED;
+    }
 
     if (num_glyphs <= 0)
 	return CAIRO_STATUS_SUCCESS;
@@ -3210,17 +3173,9 @@ _cairo_svg_surface_set_paginated_mode (void			*abstract_surface,
 }
 
 static cairo_bool_t
-_cairo_svg_surface_supports_fine_grained_fallbacks (void	*abstract_surface)
+_cairo_svg_surface_supports_fine_grained_fallbacks (void *abstract_surface)
 {
-    cairo_svg_surface_t *surface = abstract_surface;
-    cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
-
-    if (surface->document->svg_version >= CAIRO_SVG_VERSION_1_2) {
-	status =  _cairo_svg_surface_analyze_operator (surface,
-						       CAIRO_OPERATOR_SOURCE);
-    }
-
-    return status == CAIRO_INT_STATUS_SUCCESS;
+    return TRUE;
 }
 
 static const cairo_paginated_surface_backend_t cairo_svg_surface_paginated_backend = {
commit 2a9e189410326d08989ce99e0f5ad99b821ad3ed
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Fri Apr 9 00:00:28 2021 +0200

    Remove the use of extra_attributes

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index a9034145e..b532b952f 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -573,8 +573,9 @@ _cairo_svg_surface_add_source_surface (cairo_svg_surface_t  *surface,
     source_entry->unique_id = unique_id;
     _cairo_svg_source_surface_init_key (source_entry);
     status = _cairo_hash_table_insert (surface->source_surfaces, &source_entry->base);
-    if (unlikely(status))
+    if (unlikely (status)) {
 	goto fail;
+    }
 
     *is_new = TRUE;
     *source_id = source_entry->id;
@@ -1539,8 +1540,7 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t   *outp
 						   cairo_operator_t	  op,
 						   cairo_surface_pattern_t *pattern,
 						   unsigned int		  pattern_id,
-						   const cairo_matrix_t	 *parent_matrix,
-						   const char		 *extra_attributes)
+						   const cairo_matrix_t	 *parent_matrix)
 {
     cairo_status_t status;
     cairo_matrix_t p2u;
@@ -1602,9 +1602,6 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t   *outp
 				 "<use xlink:href=\"#image%d\"",
 				 source_id);
 
-    if (extra_attributes)
-	_cairo_output_stream_printf (output, " %s", extra_attributes);
-
     if (pattern_id == invalid_pattern_id) {
 	_cairo_svg_surface_emit_operator (output, svg_surface, op);
 	_cairo_svg_surface_emit_transform (output,
@@ -1754,8 +1751,7 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t	*outp
 						     cairo_operator_t	         op,
 						     cairo_surface_pattern_t	*pattern,
 						     unsigned int		 pattern_id,
-						     const cairo_matrix_t	*parent_matrix,
-						     const char			*extra_attributes)
+						     const cairo_matrix_t	*parent_matrix)
 {
     cairo_svg_document_t *document = surface->document;
     cairo_recording_surface_t *recording_surface;
@@ -1812,9 +1808,6 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t	*outp
 	_cairo_svg_surface_emit_transform (output, " transform", &p2u, parent_matrix);
     }
 
-    if (extra_attributes)
-	_cairo_output_stream_printf (output, " %s", extra_attributes);
-
     _cairo_output_stream_printf (output, "/>\n");
 
     if (pattern_id != invalid_pattern_id)
@@ -1829,8 +1822,7 @@ _cairo_svg_surface_emit_composite_pattern (cairo_output_stream_t   *output,
 					   cairo_operator_t	    op,
 					   cairo_surface_pattern_t *pattern,
 					   unsigned int		    pattern_id,
-					   const cairo_matrix_t	   *parent_matrix,
-					   const char		   *extra_attributes)
+					   const cairo_matrix_t	   *parent_matrix)
 {
     if (pattern_id != invalid_pattern_id) {
         assert (_cairo_svg_surface_svg_pattern_should_be_used(&pattern->base));
@@ -1840,15 +1832,13 @@ _cairo_svg_surface_emit_composite_pattern (cairo_output_stream_t   *output,
 	return _cairo_svg_surface_emit_composite_recording_pattern (output, surface,
 								    op, pattern,
 								    pattern_id,
-								    parent_matrix,
-								    extra_attributes);
+								    parent_matrix);
     }
 
     return _cairo_svg_surface_emit_composite_surface_pattern (output, surface,
 							      op, pattern,
 							      pattern_id,
-							      parent_matrix,
-							      extra_attributes);
+							      parent_matrix);
 }
 
 static cairo_status_t
@@ -1882,7 +1872,7 @@ _cairo_svg_surface_emit_surface_pattern (cairo_svg_surface_t	 *surface,
     pattern_id = document->pattern_id++;
     status = _cairo_svg_surface_emit_composite_pattern (document->xml_node_defs,
 	                                                surface, CAIRO_OPERATOR_SOURCE, pattern,
-							pattern_id, parent_matrix, NULL);
+							pattern_id, parent_matrix);
     if (unlikely (status))
 	return status;
 
@@ -2541,7 +2531,6 @@ _cairo_svg_surface_fill (void			*abstract_surface,
 							    op,
 							    (cairo_surface_pattern_t *) source,
 							    invalid_pattern_id,
-							    NULL,
 							    NULL);
 	if (unlikely (status))
 	    return status;
@@ -2587,8 +2576,7 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
 			       cairo_svg_surface_t   *surface,
 			       cairo_operator_t	      op,
 			       const cairo_pattern_t	     *source,
-			       const cairo_pattern_t	     *mask_source,
-			       const char	     *extra_attributes)
+			       const cairo_pattern_t	     *mask_source)
 {
     cairo_status_t status;
 
@@ -2598,8 +2586,7 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
 							  op,
 							  (cairo_surface_pattern_t *) source,
 							  invalid_pattern_id,
-							  mask_source ? &mask_source->matrix : NULL,
-							  extra_attributes);
+							  mask_source ? &mask_source->matrix : NULL);
 
     _cairo_output_stream_printf (output,
 				 "<rect x=\"-1000000%%\" y=\"-1000000%%\" "
@@ -2612,9 +2599,6 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
 
     _cairo_output_stream_printf (output, "\"");
 
-    if (extra_attributes)
-	_cairo_output_stream_printf (output, " %s", extra_attributes);
-
     _cairo_output_stream_printf (output, "/>\n");
 
     return CAIRO_STATUS_SUCCESS;
@@ -2668,7 +2652,7 @@ _cairo_svg_surface_paint (void		    *abstract_surface,
 	return status;
 
     return _cairo_svg_surface_emit_paint (surface->xml_node,
-					  surface, op, source, NULL, NULL);
+					  surface, op, source, NULL);
 }
 
 static cairo_int_status_t
@@ -2723,7 +2707,7 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
     _cairo_output_stream_printf (mask_stream,
 				 "<g filter=\"url(#%s)\">\n",
 				 _cairo_svg_surface_emit_filter (document, CAIRO_SVG_FILTER_REMOVE_COLOR));
-    status = _cairo_svg_surface_emit_paint (mask_stream, surface, CAIRO_OPERATOR_OVER, mask, source, NULL);
+    status = _cairo_svg_surface_emit_paint (mask_stream, surface, CAIRO_OPERATOR_OVER, mask, source);
     if (unlikely (status)) {
 	cairo_status_t ignore = _cairo_output_stream_destroy (mask_stream);
 	return status;
@@ -2736,30 +2720,24 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
     _cairo_memory_stream_copy (mask_stream, document->xml_node_defs);
 
     status = _cairo_output_stream_destroy (mask_stream);
-    if (unlikely (status))
+    if (unlikely (status)) {
 	return status;
+    }
 
-    cairo_output_stream_t *extra_attributes_stream = _cairo_memory_stream_create ();
-
-    _cairo_output_stream_printf (extra_attributes_stream,
-				 "mask=\"url(#mask%d)\"",
+    _cairo_output_stream_printf (surface->xml_node,
+				 "<g mask=\"url(#mask%d)\">\n",
 				 mask_id);
 
     status = _cairo_svg_surface_emit_paint (surface->xml_node,
 					    surface,
 					    op,
 					    source,
-					    NULL,
-					    _cairo_memory_stream_to_string (extra_attributes_stream));
+					    NULL);
     if (unlikely (status)) {
-	cairo_status_t ignore = _cairo_output_stream_destroy (extra_attributes_stream);
 	return status;
-	(void) ignore;
     }
 
-    status = _cairo_output_stream_destroy (extra_attributes_stream);
-    if (unlikely (status))
-	return status;
+    _cairo_output_stream_printf (surface->xml_node, "</g>\n");
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -2785,8 +2763,9 @@ _cairo_svg_surface_stroke (void			*abstract_dst,
     assert (_cairo_svg_surface_operation_supported (surface, op, source));
 
     status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
-    if (unlikely (status))
+    if (unlikely (status)) {
 	return status;
+    }
 
     cairo_bool_t svg_clip_or_svg_mask_should_be_used = _cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (source);
     unsigned int mask_id;
@@ -2812,8 +2791,9 @@ _cairo_svg_surface_stroke (void			*abstract_dst,
 						   stroke_style,
 						   ctm_inverse);
 
-    if (unlikely (status))
+    if (unlikely (status)) {
 	return status;
+    }
 
     _cairo_output_stream_printf (output_stream, "\" ");
 
@@ -2829,33 +2809,21 @@ _cairo_svg_surface_stroke (void			*abstract_dst,
 	_cairo_output_stream_printf (output_stream,
 				     "</mask>\n");
 
-	cairo_output_stream_t *extra_attributes_stream = _cairo_memory_stream_create ();
-
-	_cairo_output_stream_printf (extra_attributes_stream,
-				     "mask=\"url(#mask%d)\" style=\"",
+	_cairo_output_stream_printf (surface->xml_node,
+				     "<g mask=\"url(#mask%d)\">\n",
 				     mask_id);
 
-	_cairo_svg_surface_emit_operator_for_style (extra_attributes_stream, surface, op);
-
-	_cairo_output_stream_printf (extra_attributes_stream,
-				     "\"");
-
 	status = _cairo_svg_surface_emit_composite_pattern (surface->xml_node,
 							    surface,
 							    op,
 							    (cairo_surface_pattern_t *) source,
 							    invalid_pattern_id,
-							    NULL,
-							    _cairo_memory_stream_to_string (extra_attributes_stream));
+							    NULL);
 	if (unlikely (status)) {
-	    cairo_status_t ignore = _cairo_output_stream_destroy (extra_attributes_stream);
 	    return status;
-	    (void) ignore;
 	}
 
-	status = _cairo_output_stream_destroy (extra_attributes_stream);
-	if (unlikely (status))
-	    return status;
+	_cairo_output_stream_printf (surface->xml_node, "</g>\n");
     }
 
     return CAIRO_STATUS_SUCCESS;
@@ -2981,7 +2949,6 @@ _cairo_svg_surface_emit_paint_black (cairo_svg_surface_t *surface) {
 							   surface,
 							   CAIRO_OPERATOR_OVER,
 							   black_pattern,
-							   NULL,
 							   NULL);
     cairo_pattern_destroy(black_pattern);
     return status;
commit d59c7fb71f18d22e368494278047716b5293100d
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Thu Apr 8 23:48:51 2021 +0200

    Remove the use of discard_filter

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 1ba2e918f..a9034145e 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -137,6 +137,7 @@ static const char * _cairo_svg_unit_strings[] =
 
 enum cairo_svg_filter {
     CAIRO_SVG_FILTER_REMOVE_COLOR,
+    CAIRO_SVG_FILTER_COLOR_TO_ALPHA,
     CAIRO_SVG_FILTER_LAST_FILTER,
 };
 
@@ -943,7 +944,7 @@ _cairo_svg_document_emit_outline_glyph_data (cairo_svg_document_t	*document,
 	return status;
 
     _cairo_output_stream_printf (document->xml_node_glyphs,
-				 "<path style=\"stroke:none;\" ");
+				 "<path ");
 
     _cairo_svg_surface_emit_path (document->xml_node_glyphs,
 				  scaled_glyph->path, NULL);
@@ -1214,7 +1215,25 @@ _cairo_svg_surface_emit_filter (cairo_svg_document_t *document, enum cairo_svg_f
 					     "width=\"100%%\" height=\"100%%\">\n"
 					     "<feColorMatrix type=\"matrix\" "
 					     "in=\"SourceGraphic\" "
-					     "values=\"0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0\"/>\n"
+					     "values=\"0 0 0 0 1 "
+					     /*    */ "0 0 0 0 1 "
+					     /*    */ "0 0 0 0 1 "
+					     /*    */ "0 0 0 1 0\"/>\n"
+					     "</filter>\n");
+		break;
+	    case CAIRO_SVG_FILTER_COLOR_TO_ALPHA:
+	        // (r, g, b, a) -> (1, 1, 1, 0.2126 * r + 0.7152 * g + 0.0722 * b)
+		_cairo_output_stream_printf (document->xml_node_filters,
+					     "<filter id=\"filter-color-to-alpha\" "
+					     "filterUnits=\"objectBoundingBox\" "
+					     "x=\"0%%\" y=\"0%%\" "
+					     "width=\"100%%\" height=\"100%%\">\n"
+					     "<feColorMatrix type=\"matrix\" "
+					     "in=\"SourceGraphic\" "
+					     "values=\"0 0 0 0 1 "
+					     /*    */ "0 0 0 0 1 "
+					     /*    */ "0 0 0 0 1 "
+					     /*    */ "0.2126 0.7152 0.0722 0 0\"/>\n"
 					     "</filter>\n");
 		break;
 	    default:
@@ -1225,6 +1244,8 @@ _cairo_svg_surface_emit_filter (cairo_svg_document_t *document, enum cairo_svg_f
     switch (filter) {
 	case CAIRO_SVG_FILTER_REMOVE_COLOR:
 	    return "filter-remove-color";
+	case CAIRO_SVG_FILTER_COLOR_TO_ALPHA:
+	    return "filter-color-to-alpha";
 	default:
 	    ASSERT_NOT_REACHED;
     }
@@ -1570,9 +1591,17 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t   *outp
 	_cairo_output_stream_printf (output, ">\n  ");
     }
 
+    if (pattern->surface->content == CAIRO_CONTENT_ALPHA) {
+	_cairo_output_stream_printf (output,
+				     "<g filter=\"url(#%s)\">\n",
+				     _cairo_svg_surface_emit_filter (svg_surface->document,
+								     CAIRO_SVG_FILTER_COLOR_TO_ALPHA));
+    }
+
     _cairo_output_stream_printf (output,
 				 "<use xlink:href=\"#image%d\"",
 				 source_id);
+
     if (extra_attributes)
 	_cairo_output_stream_printf (output, " %s", extra_attributes);
 
@@ -1584,6 +1613,9 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t   *outp
     }
     _cairo_output_stream_printf (output, "/>\n");
 
+    if (pattern->surface->content == CAIRO_CONTENT_ALPHA) {
+	_cairo_output_stream_printf (output, "</g>\n");
+    }
 
     if (pattern_id != invalid_pattern_id)
 	_cairo_output_stream_printf (output, "</pattern>\n");
@@ -2482,7 +2514,7 @@ _cairo_svg_surface_fill (void			*abstract_surface,
     if (_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (source)) {
 	_cairo_output_stream_printf (surface->document->xml_node_defs,
 				     "<clipPath id=\"clip%d\">\n"
-				     "  <path ",
+				     "<path ",
 				     surface->document->clip_id);
 
 	_cairo_svg_surface_emit_path (surface->document->xml_node_defs, path, NULL);
@@ -2496,15 +2528,13 @@ _cairo_svg_surface_fill (void			*abstract_surface,
 				     "clip-rule=\"%s\" "
 				     "style=\"",
 				     surface->document->clip_id,
-				     fill_rule == CAIRO_FILL_RULE_EVEN_ODD ?
-				     "evenodd" : "nonzero");
+				     fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero");
 
 	surface->document->clip_id++;
 
 	_cairo_svg_surface_emit_operator_for_style (surface->xml_node, surface, op);
 
-	_cairo_output_stream_printf (surface->xml_node,
-				     "\">\n");
+	_cairo_output_stream_printf (surface->xml_node, "\">\n");
 
 	status = _cairo_svg_surface_emit_composite_pattern (surface->xml_node,
 							    surface,
@@ -2516,10 +2546,9 @@ _cairo_svg_surface_fill (void			*abstract_surface,
 	if (unlikely (status))
 	    return status;
 
-	_cairo_output_stream_printf (surface->xml_node,
-				     "</g>");
+	_cairo_output_stream_printf (surface->xml_node, "</g>");
     } else {
-	_cairo_output_stream_printf (surface->xml_node, "<path style=\"stroke:none;");
+	_cairo_output_stream_printf (surface->xml_node, "<path style=\"");
 	status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, op, source, fill_rule, NULL);
 	if (unlikely (status))
 	    return status;
@@ -2581,7 +2610,7 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
     if (unlikely (status))
 	return status;
 
-    _cairo_output_stream_printf (output, "stroke:none;\"");
+    _cairo_output_stream_printf (output, "\"");
 
     if (extra_attributes)
 	_cairo_output_stream_printf (output, " %s", extra_attributes);
@@ -2653,7 +2682,6 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
     cairo_svg_surface_t *surface = abstract_surface;
     cairo_svg_document_t *document = surface->document;
     cairo_output_stream_t *mask_stream;
-    cairo_bool_t discard_filter = FALSE;
     unsigned int mask_id;
 
     if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
@@ -2682,13 +2710,6 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
     if (unlikely (status))
 	return status;
 
-    if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
-	const cairo_surface_pattern_t *surface_pattern = (const cairo_surface_pattern_t*) mask;
-	cairo_content_t content = surface_pattern->surface->content;
-	if (content == CAIRO_CONTENT_ALPHA)
-	    discard_filter = TRUE;
-    }
-
     /* _cairo_svg_surface_emit_paint() will output a pattern definition to
      * document->xml_node_defs so we need to write the mask element to
      * a temporary stream and then copy that to xml_node_defs. */
@@ -2699,11 +2720,9 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
     _cairo_output_stream_printf (mask_stream,
 				 "<mask id=\"mask%d\">\n",
 				 mask_id);
-    if (!discard_filter) {
-	_cairo_output_stream_printf (mask_stream,
-				     "<g filter=\"url(#%s)\">\n",
-				     _cairo_svg_surface_emit_filter (document, CAIRO_SVG_FILTER_REMOVE_COLOR));
-    }
+    _cairo_output_stream_printf (mask_stream,
+				 "<g filter=\"url(#%s)\">\n",
+				 _cairo_svg_surface_emit_filter (document, CAIRO_SVG_FILTER_REMOVE_COLOR));
     status = _cairo_svg_surface_emit_paint (mask_stream, surface, CAIRO_OPERATOR_OVER, mask, source, NULL);
     if (unlikely (status)) {
 	cairo_status_t ignore = _cairo_output_stream_destroy (mask_stream);
@@ -2712,9 +2731,8 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
     }
 
     _cairo_output_stream_printf (mask_stream,
-				 "%s"
-				 "</mask>\n",
-				 discard_filter ? "" : "  </g>\n");
+				 "</g>\n"
+				 "</mask>\n");
     _cairo_memory_stream_copy (mask_stream, document->xml_node_defs);
 
     status = _cairo_output_stream_destroy (mask_stream);
commit 0cddf4769c73073f1cf9569791063de3287a6802
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Thu Apr 8 22:43:55 2021 +0200

    Introduce _cairo_svg_surface_svg_clip_or_svg_mask_should_be_used

diff --git a/src/cairo-misc.c b/src/cairo-misc.c
index 81f9325ca..d7af82147 100644
--- a/src/cairo-misc.c
+++ b/src/cairo-misc.c
@@ -404,10 +404,9 @@ _cairo_operator_bounded_by_mask (cairo_operator_t op)
     case CAIRO_OPERATOR_DEST_IN:
     case CAIRO_OPERATOR_DEST_ATOP:
 	return FALSE;
+    default:
+	ASSERT_NOT_REACHED;
     }
-
-    ASSERT_NOT_REACHED;
-    return FALSE;
 }
 
 /**
@@ -459,18 +458,15 @@ _cairo_operator_bounded_by_source (cairo_operator_t op)
     case CAIRO_OPERATOR_DEST_IN:
     case CAIRO_OPERATOR_DEST_ATOP:
 	return FALSE;
+    default:
+	ASSERT_NOT_REACHED;
     }
-
-    ASSERT_NOT_REACHED;
-    return FALSE;
 }
 
 uint32_t
 _cairo_operator_bounded_by_either (cairo_operator_t op)
 {
     switch (op) {
-    default:
-	ASSERT_NOT_REACHED;
     case CAIRO_OPERATOR_OVER:
     case CAIRO_OPERATOR_ATOP:
     case CAIRO_OPERATOR_DEST:
@@ -503,6 +499,8 @@ _cairo_operator_bounded_by_either (cairo_operator_t op)
     case CAIRO_OPERATOR_DEST_IN:
     case CAIRO_OPERATOR_DEST_ATOP:
 	return 0;
+    default:
+	ASSERT_NOT_REACHED;
     }
 
 }
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index c4c893465..1ba2e918f 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -1711,6 +1711,11 @@ _cairo_svg_surface_svg_pattern_should_be_used (const cairo_pattern_t *pattern) {
 	   _cairo_surface_get_extents (((cairo_surface_pattern_t *) pattern)->surface, &extents);
 }
 
+static cairo_bool_t
+_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (const cairo_pattern_t *pattern) {
+    return pattern->type == CAIRO_PATTERN_TYPE_SURFACE && !_cairo_svg_surface_svg_pattern_should_be_used (pattern);
+}
+
 static cairo_status_t
 _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t	*output,
 						     cairo_svg_surface_t	*surface,
@@ -2411,8 +2416,8 @@ _cairo_svg_surface_fill_stroke (void			*abstract_surface,
     cairo_svg_surface_t *surface = abstract_surface;
     cairo_status_t status;
 
-    if (_cairo_svg_surface_svg_pattern_should_be_used (fill_source) ||
-	_cairo_svg_surface_svg_pattern_should_be_used (stroke_source)) {
+    if (_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (fill_source) ||
+	_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (stroke_source)) {
 	status = _cairo_surface_fill (&surface->base, fill_op, fill_source, path,
 				      fill_rule, fill_tolerance, fill_antialias,
 				      clip);
@@ -2474,7 +2479,7 @@ _cairo_svg_surface_fill (void			*abstract_surface,
     if (unlikely (status))
 	return status;
 
-    if (source->type == CAIRO_PATTERN_TYPE_SURFACE && !_cairo_svg_surface_svg_pattern_should_be_used (source)) {
+    if (_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (source)) {
 	_cairo_output_stream_printf (surface->document->xml_node_defs,
 				     "<clipPath id=\"clip%d\">\n"
 				     "  <path ",
@@ -2558,7 +2563,7 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
 {
     cairo_status_t status;
 
-    if (source->type == CAIRO_PATTERN_TYPE_SURFACE && !_cairo_svg_surface_svg_pattern_should_be_used(source))
+    if (_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used(source))
 	return _cairo_svg_surface_emit_composite_pattern (output,
 							  surface,
 							  op,
@@ -2599,12 +2604,8 @@ _cairo_svg_surface_paint (void		    *abstract_surface,
      * is defined. We just delete existing content of surface root node,
      * and exit early if operator is clear.
      */
-    if ((op == CAIRO_OPERATOR_CLEAR || op == CAIRO_OPERATOR_SOURCE) &&
-	clip == NULL)
-    {
+    if ((op == CAIRO_OPERATOR_CLEAR || op == CAIRO_OPERATOR_SOURCE) && clip == NULL) {
 	switch (surface->paginated_mode) {
-	case CAIRO_PAGINATED_MODE_FALLBACK:
-	    ASSERT_NOT_REACHED;
 	case CAIRO_PAGINATED_MODE_ANALYZE:
 	    return CAIRO_STATUS_SUCCESS;
 	case CAIRO_PAGINATED_MODE_RENDER:
@@ -2618,16 +2619,13 @@ _cairo_svg_surface_paint (void		    *abstract_surface,
 
 	    if (op == CAIRO_OPERATOR_CLEAR) {
 		if (surface->content == CAIRO_CONTENT_COLOR) {
-		    _cairo_output_stream_printf (surface->xml_node,
-						 "<rect x=\"-1000000%%\" y=\"-1000000%%\" "
-						 "width=\"2000000%%\" height=\"2000000%%\" "
-						 "style=\"opacity:1;"
-						 "stroke:none;"
-						 "fill:rgb(0,0,0);\"/>\n");
+		    return _cairo_svg_surface_emit_paint_black (surface);
 		}
 		return CAIRO_STATUS_SUCCESS;
 	    }
 	    break;
+	case CAIRO_PAGINATED_MODE_FALLBACK:
+	    ASSERT_NOT_REACHED;
 	}
     } else {
 	if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
@@ -2772,12 +2770,11 @@ _cairo_svg_surface_stroke (void			*abstract_dst,
     if (unlikely (status))
 	return status;
 
-    cairo_bool_t svg_pattern_should_not_be_used = source->type == CAIRO_PATTERN_TYPE_SURFACE &&
-						  !_cairo_svg_surface_svg_pattern_should_be_used (source);
+    cairo_bool_t svg_clip_or_svg_mask_should_be_used = _cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (source);
     unsigned int mask_id;
     cairo_output_stream_t *output_stream = surface->xml_node;
     cairo_pattern_t *white_pattern;
-    if (svg_pattern_should_not_be_used) {
+    if (svg_clip_or_svg_mask_should_be_used) {
 	mask_id = _cairo_svg_document_allocate_mask_id (surface->document);
 
 	output_stream = surface->document->xml_node_defs;
@@ -2792,8 +2789,8 @@ _cairo_svg_surface_stroke (void			*abstract_dst,
     _cairo_output_stream_printf (output_stream, "<path style=\"fill:none;");
     status = _cairo_svg_surface_emit_stroke_style (output_stream,
 						   surface,
-						   svg_pattern_should_not_be_used ? CAIRO_OPERATOR_OVER : op,
-						   svg_pattern_should_not_be_used ? white_pattern : source,
+						   svg_clip_or_svg_mask_should_be_used ? CAIRO_OPERATOR_OVER : op,
+						   svg_clip_or_svg_mask_should_be_used ? white_pattern : source,
 						   stroke_style,
 						   ctm_inverse);
 
@@ -2808,7 +2805,7 @@ _cairo_svg_surface_stroke (void			*abstract_dst,
 				       " transform", ctm, NULL);
     _cairo_output_stream_printf (output_stream, "/>\n");
 
-    if (svg_pattern_should_not_be_used) {
+    if (svg_clip_or_svg_mask_should_be_used) {
         cairo_pattern_destroy(white_pattern);
 
 	_cairo_output_stream_printf (output_stream,
commit 7a21a930e9da8a43d9a32071b90b84184fc01451
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Thu Apr 8 21:59:01 2021 +0200

    Add warning supression in one place and remove them in others

diff --git a/src/cairo-malloc-private.h b/src/cairo-malloc-private.h
index 570f7cb0e..a06450892 100644
--- a/src/cairo-malloc-private.h
+++ b/src/cairo-malloc-private.h
@@ -60,7 +60,7 @@
  **/
 
 #define _cairo_malloc(size) \
-   ((size) > 0 ? malloc((unsigned) (size)) : NULL)
+   ((size) > 0 ? malloc((unsigned) (size)) : NULL) // NOLINT(bugprone-sizeof-expression)
 
 /**
  * _cairo_malloc_ab:
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 51bf98871..c4c893465 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -376,7 +376,7 @@ void
 cairo_svg_surface_restrict_to_version (cairo_surface_t		*abstract_surface,
 				       cairo_svg_version_t	 version)
 {
-    cairo_svg_surface_t *surface = NULL; /* hide compiler warning */
+    cairo_svg_surface_t *surface;
 
     if (! _extract_svg_surface (abstract_surface, &surface))
 	return;
@@ -454,7 +454,7 @@ void
 cairo_svg_surface_set_document_unit (cairo_surface_t	*abstract_surface,
 				     cairo_svg_unit_t	 unit)
 {
-    cairo_svg_surface_t *surface = NULL; /* hide compiler warning */
+    cairo_svg_surface_t *surface;
 
     if (! _extract_svg_surface (abstract_surface, &surface))
 	return;
@@ -480,7 +480,7 @@ cairo_svg_surface_set_document_unit (cairo_surface_t	*abstract_surface,
 cairo_svg_unit_t
 cairo_svg_surface_get_document_unit (cairo_surface_t	*abstract_surface)
 {
-    cairo_svg_surface_t *surface = NULL; /* hide compiler warning */
+    cairo_svg_surface_t *surface;
 
     if (! _extract_svg_surface (abstract_surface, &surface)) {
 	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
@@ -724,7 +724,7 @@ _cairo_svg_surface_create_for_stream_internal (cairo_output_stream_t	*stream,
 					       double			 height,
 					       cairo_svg_version_t	 version)
 {
-    cairo_svg_document_t *document = NULL; /* silence compiler */
+    cairo_svg_document_t *document;
     cairo_surface_t *surface;
     cairo_status_t status;
 
commit 3b6ea32854383e52a8ebe548b3ea11d654ba6780
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Thu Apr 8 21:47:32 2021 +0200

    Do not check the status after creating a memory stream
    
    As we do not check the status after _cairo_output_stream_printf
    and _cairo_memory_stream_copy (which are more common operations)
    anyway.
    
    This simplifies the code, but keeps it correct, as the status
    will be propagated anyway, just a bit later.

diff --git a/src/cairo-error-private.h b/src/cairo-error-private.h
index 1ab57ddf8..d8cc7c004 100644
--- a/src/cairo-error-private.h
+++ b/src/cairo-error-private.h
@@ -112,10 +112,10 @@ enum _cairo_int_status {
 typedef enum _cairo_int_status cairo_int_status_t;
 
 #define _cairo_status_is_error(status) \
-    (status != CAIRO_STATUS_SUCCESS && status < CAIRO_STATUS_LAST_STATUS)
+    ((status) != CAIRO_STATUS_SUCCESS && (status) < CAIRO_STATUS_LAST_STATUS)
 
 #define _cairo_int_status_is_error(status) \
-    (status != CAIRO_INT_STATUS_SUCCESS && status < CAIRO_INT_STATUS_LAST_STATUS)
+    ((status) != CAIRO_INT_STATUS_SUCCESS && (status) < CAIRO_INT_STATUS_LAST_STATUS)
 
 cairo_private cairo_status_t
 _cairo_error (cairo_status_t status);
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 975fc4503..51bf98871 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -679,9 +679,6 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t	*document,
 				 _cairo_svg_surface_clipper_intersect_clip_path);
 
     surface->xml_node = _cairo_memory_stream_create ();
-    status = _cairo_output_stream_get_status (surface->xml_node);
-    if (unlikely (status))
-	goto CLEANUP;
 
     _cairo_array_init (&surface->page_set, sizeof (cairo_svg_page_t));
 
@@ -765,10 +762,6 @@ _cairo_svg_surface_store_page (cairo_svg_surface_t *surface)
     unsigned int i;
 
     stream = _cairo_memory_stream_create ();
-    if (_cairo_output_stream_get_status (stream)) {
-	status = _cairo_output_stream_destroy (stream);
-	return NULL;
-    }
 
     page.surface_id = surface->base.unique_id;
     page.clip_level = surface->clip_level;
@@ -2614,7 +2607,6 @@ _cairo_svg_surface_paint (void		    *abstract_surface,
 	    ASSERT_NOT_REACHED;
 	case CAIRO_PAGINATED_MODE_ANALYZE:
 	    return CAIRO_STATUS_SUCCESS;
-
 	case CAIRO_PAGINATED_MODE_RENDER:
 	    status = _cairo_output_stream_destroy (surface->xml_node);
 	    if (unlikely (status)) {
@@ -2623,11 +2615,6 @@ _cairo_svg_surface_paint (void		    *abstract_surface,
 	    }
 
 	    surface->xml_node = _cairo_memory_stream_create ();
-	    if (_cairo_output_stream_get_status (surface->xml_node)) {
-		status = _cairo_output_stream_destroy (surface->xml_node);
-		surface->xml_node = NULL;
-		return status;
-	    }
 
 	    if (op == CAIRO_OPERATOR_CLEAR) {
 		if (surface->content == CAIRO_CONTENT_COLOR) {
@@ -2708,8 +2695,6 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
      * document->xml_node_defs so we need to write the mask element to
      * a temporary stream and then copy that to xml_node_defs. */
     mask_stream = _cairo_memory_stream_create ();
-    if (_cairo_output_stream_get_status (mask_stream))
-	return _cairo_output_stream_destroy (mask_stream);
 
     mask_id = _cairo_svg_document_allocate_mask_id (document);
 
@@ -2739,8 +2724,6 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
 	return status;
 
     cairo_output_stream_t *extra_attributes_stream = _cairo_memory_stream_create ();
-    if (_cairo_output_stream_get_status (extra_attributes_stream))
-	return _cairo_output_stream_destroy (extra_attributes_stream);
 
     _cairo_output_stream_printf (extra_attributes_stream,
 				 "mask=\"url(#mask%d)\"",
@@ -2832,8 +2815,6 @@ _cairo_svg_surface_stroke (void			*abstract_dst,
 				     "</mask>\n");
 
 	cairo_output_stream_t *extra_attributes_stream = _cairo_memory_stream_create ();
-	if (_cairo_output_stream_get_status (extra_attributes_stream))
-	    return _cairo_output_stream_destroy (extra_attributes_stream);
 
 	_cairo_output_stream_printf (extra_attributes_stream,
 				     "mask=\"url(#mask%d)\" style=\"",
@@ -3035,7 +3016,7 @@ _cairo_svg_document_create (cairo_output_stream_t	 *output_stream,
 			    cairo_svg_document_t	**document_out)
 {
     cairo_svg_document_t *document;
-    cairo_status_t status, status_ignored;
+    cairo_status_t status;
 
     if (output_stream->status)
 	return output_stream->status;
@@ -3070,32 +3051,14 @@ _cairo_svg_document_create (cairo_output_stream_t	 *output_stream,
     }
 
     document->xml_node_defs = _cairo_memory_stream_create ();
-    status = _cairo_output_stream_get_status (document->xml_node_defs);
-    if (unlikely (status))
-	goto CLEANUP_NODE_DEFS;
-
     document->xml_node_glyphs = _cairo_memory_stream_create ();
-    status = _cairo_output_stream_get_status (document->xml_node_glyphs);
-    if (unlikely (status))
-	goto CLEANUP_NODE_GLYPHS;
-
     document->xml_node_filters = _cairo_memory_stream_create ();
-    status = _cairo_output_stream_get_status (document->xml_node_filters);
-    if (unlikely (status))
-	goto CLEANUP_NODE_FILTERS;
 
     document->svg_version = version;
 
     *document_out = document;
     return CAIRO_STATUS_SUCCESS;
 
-  CLEANUP_NODE_FILTERS:
-    status_ignored = _cairo_output_stream_destroy (document->xml_node_filters);
-  CLEANUP_NODE_GLYPHS:
-    status_ignored = _cairo_output_stream_destroy (document->xml_node_glyphs);
-  CLEANUP_NODE_DEFS:
-    status_ignored = _cairo_output_stream_destroy (document->xml_node_defs);
-    _cairo_scaled_font_subsets_destroy (document->font_subsets);
   CLEANUP_DOCUMENT:
     free (document);
     return status;
commit 170fa0f9bb66198bb2f6aeb9d29cc7a5234a1183
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Thu Apr 8 21:27:24 2021 +0200

    Fix using signed types where unsigned ones were needed

diff --git a/src/cairo-image-info-private.h b/src/cairo-image-info-private.h
index e64928e40..3808d07b3 100644
--- a/src/cairo-image-info-private.h
+++ b/src/cairo-image-info-private.h
@@ -48,7 +48,7 @@ typedef struct _cairo_image_info {
 cairo_private cairo_int_status_t
 _cairo_image_info_get_jpeg_info (cairo_image_info_t	*info,
 				 const unsigned char	*data,
-				 long			 length);
+				 unsigned long		 length);
 
 cairo_private cairo_int_status_t
 _cairo_image_info_get_jpx_info (cairo_image_info_t	*info,
diff --git a/src/cairo-image-info.c b/src/cairo-image-info.c
index d147e3723..f207ae887 100644
--- a/src/cairo-image-info.c
+++ b/src/cairo-image-info.c
@@ -90,7 +90,7 @@ _jpeg_extract_info (cairo_image_info_t *info, const unsigned char *p)
 cairo_int_status_t
 _cairo_image_info_get_jpeg_info (cairo_image_info_t	*info,
 				 const unsigned char	*data,
-				 long			 length)
+				 unsigned long		 length)
 {
     const unsigned char *p = data;
 
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index f0e6b9e1a..975fc4503 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -52,7 +52,6 @@
 #include "cairo-image-surface-private.h"
 #include "cairo-recording-surface-inline.h"
 #include "cairo-output-stream-private.h"
-#include "cairo-path-fixed-private.h"
 #include "cairo-paginated-private.h"
 #include "cairo-scaled-font-subsets-private.h"
 #include "cairo-surface-clipper-private.h"
@@ -528,7 +527,7 @@ _cairo_svg_source_surface_pluck (void *entry, void *closure)
 static cairo_status_t
 _cairo_svg_surface_add_source_surface (cairo_svg_surface_t  *surface,
 				       cairo_surface_t	    *source_surface,
-				       int                  *source_id,
+				       unsigned int         *source_id,
 				       cairo_bool_t         *is_new)
 {
     cairo_svg_source_surface_t source_key;
@@ -1484,7 +1483,7 @@ _cairo_svg_surface_emit_attr_value (cairo_output_stream_t *stream,
 static cairo_status_t
 _cairo_svg_surface_emit_surface (cairo_svg_document_t *document,
 				 cairo_surface_t *surface,
-				 int source_id)
+				 unsigned int source_id)
 {
     cairo_rectangle_int_t extents;
     cairo_bool_t is_bounded;
@@ -1525,13 +1524,13 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t   *outp
 						   cairo_svg_surface_t	 *svg_surface,
 						   cairo_operator_t	  op,
 						   cairo_surface_pattern_t *pattern,
-						   int			  pattern_id,
+						   unsigned int		  pattern_id,
 						   const cairo_matrix_t	 *parent_matrix,
 						   const char		 *extra_attributes)
 {
     cairo_status_t status;
     cairo_matrix_t p2u;
-    int source_id;
+    unsigned int source_id;
     cairo_bool_t is_new;
 
     p2u = pattern->base.matrix;
@@ -1602,7 +1601,7 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t   *outp
 static cairo_status_t
 _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
 					   cairo_recording_surface_t *source,
-					   int                        source_id)
+					   unsigned int               source_id)
 {
     cairo_status_t status;
     cairo_surface_t *paginated_surface;
@@ -1724,7 +1723,7 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t	*outp
 						     cairo_svg_surface_t	*surface,
 						     cairo_operator_t	         op,
 						     cairo_surface_pattern_t	*pattern,
-						     int			 pattern_id,
+						     unsigned int		 pattern_id,
 						     const cairo_matrix_t	*parent_matrix,
 						     const char			*extra_attributes)
 {
@@ -1732,7 +1731,7 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t	*outp
     cairo_recording_surface_t *recording_surface;
     cairo_matrix_t p2u;
     cairo_status_t status;
-    int source_id;
+    unsigned int source_id;
     cairo_bool_t is_new;
 
     p2u = pattern->base.matrix;
@@ -1799,7 +1798,7 @@ _cairo_svg_surface_emit_composite_pattern (cairo_output_stream_t   *output,
 					   cairo_svg_surface_t	   *surface,
 					   cairo_operator_t	    op,
 					   cairo_surface_pattern_t *pattern,
-					   int			    pattern_id,
+					   unsigned int		    pattern_id,
 					   const cairo_matrix_t	   *parent_matrix,
 					   const char		   *extra_attributes)
 {
@@ -1848,7 +1847,7 @@ _cairo_svg_surface_emit_surface_pattern (cairo_svg_surface_t	 *surface,
 {
     cairo_svg_document_t *document = surface->document;
     cairo_status_t status;
-    int pattern_id;
+    unsigned int pattern_id;
 
     pattern_id = document->pattern_id++;
     status = _cairo_svg_surface_emit_composite_pattern (document->xml_node_defs,
commit 7ade55ac5b95a989e81d3bb58e34472d76d01a62
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Thu Apr 8 01:33:43 2021 +0200

    Add new SVG filters system

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 61e087fbc..f0e6b9e1a 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -136,6 +136,11 @@ static const char * _cairo_svg_unit_strings[] =
     "%"
 };
 
+enum cairo_svg_filter {
+    CAIRO_SVG_FILTER_REMOVE_COLOR,
+    CAIRO_SVG_FILTER_LAST_FILTER,
+};
+
 struct cairo_svg_page {
     unsigned int surface_id;
     unsigned int clip_level;
@@ -154,15 +159,15 @@ struct cairo_svg_document {
 
     cairo_output_stream_t *xml_node_defs;
     cairo_output_stream_t *xml_node_glyphs;
+    cairo_output_stream_t *xml_node_filters;
 
     unsigned int linear_pattern_id;
     unsigned int radial_pattern_id;
     unsigned int pattern_id;
-    unsigned int filter_id;
     unsigned int clip_id;
     unsigned int mask_id;
 
-    cairo_bool_t alpha_filter;
+    cairo_bool_t filters_emitted[CAIRO_SVG_FILTER_LAST_FILTER];
 
     cairo_svg_version_t svg_version;
 
@@ -1202,23 +1207,35 @@ _cairo_svg_surface_finish (void *abstract_surface)
 }
 
 
-static void
-_cairo_svg_surface_emit_alpha_filter (cairo_svg_document_t *document)
-{
-    if (document->alpha_filter)
-	return;
-
-    _cairo_output_stream_printf (document->xml_node_defs,
-				 "<filter id=\"alpha\" "
-				 "filterUnits=\"objectBoundingBox\" "
-				 "x=\"0%%\" y=\"0%%\" "
-				 "width=\"100%%\" height=\"100%%\">\n"
-				 "  <feColorMatrix type=\"matrix\" "
-				 "in=\"SourceGraphic\" "
-				 "values=\"0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0\"/>\n"
-				 "</filter>\n");
+static char *
+_cairo_svg_surface_emit_filter (cairo_svg_document_t *document, enum cairo_svg_filter filter)
+{
+    if (!document->filters_emitted[filter]) {
+	document->filters_emitted[filter] = TRUE;
+	switch (filter) {
+	    case CAIRO_SVG_FILTER_REMOVE_COLOR:
+	        // (r, g, b, a) -> (1, 1, 1, a)
+		_cairo_output_stream_printf (document->xml_node_filters,
+					     "<filter id=\"filter-remove-color\" "
+					     "filterUnits=\"objectBoundingBox\" "
+					     "x=\"0%%\" y=\"0%%\" "
+					     "width=\"100%%\" height=\"100%%\">\n"
+					     "<feColorMatrix type=\"matrix\" "
+					     "in=\"SourceGraphic\" "
+					     "values=\"0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0\"/>\n"
+					     "</filter>\n");
+		break;
+	    default:
+		ASSERT_NOT_REACHED;
+	}
+    }
 
-    document->alpha_filter = TRUE;
+    switch (filter) {
+	case CAIRO_SVG_FILTER_REMOVE_COLOR:
+	    return "filter-remove-color";
+	default:
+	    ASSERT_NOT_REACHED;
+    }
 }
 
 typedef struct {
@@ -1635,10 +1652,6 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
 				     extents.height);
     }
 
-    if (source->base.content == CAIRO_CONTENT_ALPHA) {
-	_cairo_svg_surface_emit_alpha_filter (document);
-    }
-
     _cairo_output_stream_printf (document->xml_node_defs,
 				 "<g id=\"surface%d\"",
 				 source_id);
@@ -1651,7 +1664,8 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
 
     if (source->base.content == CAIRO_CONTENT_ALPHA) {
 	_cairo_output_stream_printf (document->xml_node_defs,
-				     " filter=\"url(#alpha)\"");
+				     " filter=\"url(#%s)\"",
+				     _cairo_svg_surface_emit_filter (document, CAIRO_SVG_FILTER_REMOVE_COLOR));
     }
 
     _cairo_output_stream_printf (document->xml_node_defs,
@@ -2691,9 +2705,6 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
 	    discard_filter = TRUE;
     }
 
-    if (!discard_filter)
-	_cairo_svg_surface_emit_alpha_filter (document);
-
     /* _cairo_svg_surface_emit_paint() will output a pattern definition to
      * document->xml_node_defs so we need to write the mask element to
      * a temporary stream and then copy that to xml_node_defs. */
@@ -2704,10 +2715,13 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
     mask_id = _cairo_svg_document_allocate_mask_id (document);
 
     _cairo_output_stream_printf (mask_stream,
-				 "<mask id=\"mask%d\">\n"
-				 "%s",
-				 mask_id,
-				 discard_filter ? "" : "  <g filter=\"url(#alpha)\">\n");
+				 "<mask id=\"mask%d\">\n",
+				 mask_id);
+    if (!discard_filter) {
+	_cairo_output_stream_printf (mask_stream,
+				     "<g filter=\"url(#%s)\">\n",
+				     _cairo_svg_surface_emit_filter (document, CAIRO_SVG_FILTER_REMOVE_COLOR));
+    }
     status = _cairo_svg_surface_emit_paint (mask_stream, surface, CAIRO_OPERATOR_OVER, mask, source, NULL);
     if (unlikely (status)) {
 	cairo_status_t ignore = _cairo_output_stream_destroy (mask_stream);
@@ -3049,10 +3063,13 @@ _cairo_svg_document_create (cairo_output_stream_t	 *output_stream,
     document->linear_pattern_id = 0;
     document->radial_pattern_id = 0;
     document->pattern_id = 0;
-    document->filter_id = 0;
     document->clip_id = 0;
     document->mask_id = 0;
 
+    for (enum cairo_svg_filter filter = 0; filter < CAIRO_SVG_FILTER_LAST_FILTER; filter++) {
+	document->filters_emitted[filter] = FALSE;
+    }
+
     document->xml_node_defs = _cairo_memory_stream_create ();
     status = _cairo_output_stream_get_status (document->xml_node_defs);
     if (unlikely (status))
@@ -3063,13 +3080,18 @@ _cairo_svg_document_create (cairo_output_stream_t	 *output_stream,
     if (unlikely (status))
 	goto CLEANUP_NODE_GLYPHS;
 
-    document->alpha_filter = FALSE;
+    document->xml_node_filters = _cairo_memory_stream_create ();
+    status = _cairo_output_stream_get_status (document->xml_node_filters);
+    if (unlikely (status))
+	goto CLEANUP_NODE_FILTERS;
 
     document->svg_version = version;
 
     *document_out = document;
     return CAIRO_STATUS_SUCCESS;
 
+  CLEANUP_NODE_FILTERS:
+    status_ignored = _cairo_output_stream_destroy (document->xml_node_filters);
   CLEANUP_NODE_GLYPHS:
     status_ignored = _cairo_output_stream_destroy (document->xml_node_glyphs);
   CLEANUP_NODE_DEFS:
@@ -3156,9 +3178,15 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
 
     status = _cairo_svg_document_emit_font_subsets (document);
 
-    if (_cairo_memory_stream_length (document->xml_node_glyphs) > 0 ||
+    if (_cairo_memory_stream_length (document->xml_node_filters) > 0 ||
+	_cairo_memory_stream_length (document->xml_node_glyphs) > 0 ||
 	_cairo_memory_stream_length (document->xml_node_defs) > 0) {
 	_cairo_output_stream_printf (output, "<defs>\n");
+	if (_cairo_memory_stream_length (document->xml_node_filters) > 0) {
+	    _cairo_output_stream_printf (output, "<g>\n");
+	    _cairo_memory_stream_copy (document->xml_node_filters, output);
+	    _cairo_output_stream_printf (output, "</g>\n");
+	}
 	if (_cairo_memory_stream_length (document->xml_node_glyphs) > 0) {
 	    _cairo_output_stream_printf (output, "<g>\n");
 	    _cairo_memory_stream_copy (document->xml_node_glyphs, output);
@@ -3205,6 +3233,10 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
 
     _cairo_output_stream_printf (output, "</svg>\n");
 
+    status2 = _cairo_output_stream_destroy (document->xml_node_filters);
+    if (status == CAIRO_STATUS_SUCCESS)
+	status = status2;
+
     status2 = _cairo_output_stream_destroy (document->xml_node_glyphs);
     if (status == CAIRO_STATUS_SUCCESS)
 	status = status2;
commit b340dc19f2a962071291358b861898650cd1b075
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Thu Apr 8 01:01:08 2021 +0200

    Fix emitting black background for color-only non-bounded SVG surfaces

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index d166afc62..61e087fbc 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -201,6 +201,9 @@ _cairo_svg_surface_create_for_stream_internal (cairo_output_stream_t	*stream,
 					       double			 height,
 					       cairo_svg_version_t	 version);
 
+static cairo_status_t
+_cairo_svg_surface_emit_paint_black (cairo_svg_surface_t *surface);
+
 static const cairo_surface_backend_t cairo_svg_surface_backend;
 static const cairo_paginated_surface_backend_t cairo_svg_surface_paginated_backend;
 
@@ -579,22 +582,17 @@ _cairo_svg_surface_add_source_surface (cairo_svg_surface_t  *surface,
 }
 
 static cairo_bool_t
-_cliprect_covers_surface (cairo_svg_surface_t *surface,
-			  cairo_path_fixed_t *path)
+_cairo_svg_surface_cliprect_covers_surface (cairo_svg_surface_t *surface,
+					    cairo_path_fixed_t *path)
 {
     cairo_box_t box;
 
-    if (_cairo_path_fixed_is_box (path, &box)) {
-	if (box.p1.x <= 0 &&
-	    box.p1.y <= 0 &&
-	    _cairo_fixed_to_double (box.p2.x) >= surface->width &&
-	    _cairo_fixed_to_double (box.p2.y) >= surface->height)
-	{
-	    return TRUE;
-	}
-    }
-
-    return FALSE;
+    return surface->surface_bounded &&
+	   _cairo_path_fixed_is_box (path, &box) &&
+	   box.p1.x <= 0 &&
+	   box.p1.y <= 0 &&
+	   _cairo_fixed_to_double (box.p2.x) >= surface->width &&
+	   _cairo_fixed_to_double (box.p2.y) >= surface->height;
 }
 
 static cairo_status_t
@@ -619,7 +617,7 @@ _cairo_svg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper
     }
 
     /* skip trivial whole-page clips */
-    if (surface->surface_bounded && _cliprect_covers_surface (surface, path))
+    if (_cairo_svg_surface_cliprect_covers_surface (surface, path))
 	return CAIRO_STATUS_SUCCESS;
 
     _cairo_output_stream_printf (document->xml_node_defs,
@@ -684,12 +682,7 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t	*document,
     _cairo_array_init (&surface->page_set, sizeof (cairo_svg_page_t));
 
     if (content == CAIRO_CONTENT_COLOR) {
-	_cairo_output_stream_printf (surface->xml_node,
-				     "<rect width=\"%f\" height=\"%f\" "
-				     "style=\"opacity:1;stroke:none;"
-				     "fill:rgb(0,0,0);\"/>\n",
-				     width, height);
-	status = _cairo_output_stream_get_status (surface->xml_node);
+	status = _cairo_svg_surface_emit_paint_black (surface);
 	if (unlikely (status))
 	    goto CLEANUP;
     }
@@ -1694,7 +1687,7 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
 }
 
 static cairo_recording_surface_t *
-to_recording_surface (const cairo_surface_pattern_t *pattern)
+_cairo_svg_surface_to_recording_surface (const cairo_surface_pattern_t *pattern)
 {
     cairo_surface_t *surface = pattern->surface;
     if (_cairo_surface_is_paginated (surface))
@@ -1740,7 +1733,7 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t	*outp
     if (unlikely (status))
 	return status;
 
-    recording_surface = to_recording_surface (pattern);
+    recording_surface = _cairo_svg_surface_to_recording_surface (pattern);
     if (is_new) {
 	status = _cairo_svg_surface_emit_recording_surface (document, recording_surface, source_id);
 	if (unlikely (status))
@@ -2972,6 +2965,19 @@ _cairo_svg_surface_get_supported_mime_types (void	   *abstract_surface)
     return _cairo_svg_supported_mime_types;
 }
 
+static cairo_status_t
+_cairo_svg_surface_emit_paint_black (cairo_svg_surface_t *surface) {
+    cairo_pattern_t *black_pattern = cairo_pattern_create_rgb (0.0, 0.0, 0.0);
+    cairo_status_t status = _cairo_svg_surface_emit_paint (surface->xml_node,
+							   surface,
+							   CAIRO_OPERATOR_OVER,
+							   black_pattern,
+							   NULL,
+							   NULL);
+    cairo_pattern_destroy(black_pattern);
+    return status;
+}
+
 static const cairo_surface_backend_t cairo_svg_surface_backend = {
 	CAIRO_SURFACE_TYPE_SVG,
 	_cairo_svg_surface_finish,
commit fa5179e9fd7362692f8fc421f4977dc18924c515
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Thu Apr 8 00:56:19 2021 +0200

    Add a test with operator samples from https://cairographics.org/operators/

diff --git a/test/Makefile.sources b/test/Makefile.sources
index 33d6e81af..bb999169b 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -232,6 +232,7 @@ test_sources = \
 	operator-alpha-alpha.c				\
 	operator-clear.c				\
 	operator-source.c				\
+	operator-www.c				\
 	outline-tolerance.c				\
 	over-above-source.c				\
 	over-around-source.c				\
diff --git a/test/meson.build b/test/meson.build
index 4dc976d43..cc5160876 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -232,6 +232,7 @@ test_sources = [
   'operator-alpha-alpha.c',
   'operator-clear.c',
   'operator-source.c',
+  'operator-www.c',
   'outline-tolerance.c',
   'over-above-source.c',
   'over-around-source.c',
diff --git a/test/operator-www.c b/test/operator-www.c
new file mode 100644
index 000000000..36bed8db3
--- /dev/null
+++ b/test/operator-www.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright © 2011 Nis Martensen
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "cairo-test.h"
+
+#define OPERATORS_COUNT 29
+#define WIDTH 160
+#define HEIGHT 120
+
+void
+example (cairo_t *cr, char *name)
+{
+    cairo_save (cr);
+
+    cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT);
+    cairo_clip (cr);
+
+    cairo_rectangle (cr, 0, 0, 120, 90);
+    cairo_set_source_rgba (cr, 0.7, 0, 0, 0.8);
+    cairo_fill (cr);
+
+    if (strcmp (name, "clear") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+
+    else if (strcmp (name, "source") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+    else if (strcmp (name, "over") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+    else if (strcmp (name, "in") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_IN);
+    else if (strcmp (name, "out") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_OUT);
+    else if (strcmp (name, "atop") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_ATOP);
+
+    else if (strcmp (name, "dest") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_DEST);
+    else if (strcmp (name, "dest_over") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OVER);
+    else if (strcmp (name, "dest_in") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_DEST_IN);
+    else if (strcmp (name, "dest_out") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OUT);
+    else if (strcmp (name, "dest_atop") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_DEST_ATOP);
+
+    else if (strcmp (name, "xor") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_XOR);
+    else if (strcmp (name, "add") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_ADD);
+    else if (strcmp (name, "saturate") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_SATURATE);
+    else if (strcmp (name, "multiply") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_MULTIPLY);
+    else if (strcmp (name, "screen") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_SCREEN);
+    else if (strcmp (name, "overlay") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_OVERLAY);
+    else if (strcmp (name, "darken") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_DARKEN);
+    else if (strcmp (name, "lighten") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_LIGHTEN);
+    else if (strcmp (name, "color_dodge") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_COLOR_DODGE);
+    else if (strcmp (name, "color_burn") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_COLOR_BURN);
+    else if (strcmp (name, "hard_light") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_HARD_LIGHT);
+    else if (strcmp (name, "soft_light") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_SOFT_LIGHT);
+    else if (strcmp (name, "difference") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_DIFFERENCE);
+    else if (strcmp (name, "exclusion") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_EXCLUSION);
+    else if (strcmp (name, "hsl_hue") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_HSL_HUE);
+    else if (strcmp (name, "hsl_saturation") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_HSL_SATURATION);
+    else if (strcmp (name, "hsl_color") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_HSL_COLOR);
+    else if (strcmp (name, "hsl_luminosity") == 0)
+	cairo_set_operator (cr, CAIRO_OPERATOR_HSL_LUMINOSITY);
+
+    cairo_rectangle (cr, 40, 30, 120, 90);
+    cairo_set_source_rgba (cr, 0, 0, 0.9, 0.4);
+    cairo_fill (cr);
+
+    cairo_restore (cr);
+
+    cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans",
+			    CAIRO_FONT_SLANT_NORMAL,
+			    CAIRO_FONT_WEIGHT_NORMAL);
+    cairo_set_font_size(cr, 17);
+    cairo_move_to (cr, WIDTH + 20, 70);
+    cairo_set_source_rgb (cr, 1, 1, 0);
+    cairo_show_text (cr, name);
+
+    cairo_translate (cr, 0, HEIGHT);
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    example (cr, "clear");
+
+    example (cr, "source");
+    example (cr, "over");
+    example (cr, "in");
+    example (cr, "out");
+    example (cr, "atop");
+
+    example (cr, "dest");
+    example (cr, "dest_over");
+    example (cr, "dest_in");
+    example (cr, "dest_out");
+    example (cr, "dest_atop");
+
+    example (cr, "xor");
+    example (cr, "add");
+    example (cr, "saturate");
+
+    example (cr, "multiply");
+    example (cr, "screen");
+    example (cr, "overlay");
+    example (cr, "darken");
+    example (cr, "lighten");
+    example (cr, "color_dodge");
+    example (cr, "color_burn");
+    example (cr, "hard_light");
+    example (cr, "soft_light");
+    example (cr, "difference");
+    example (cr, "exclusion");
+    example (cr, "hsl_hue");
+    example (cr, "hsl_saturation");
+    example (cr, "hsl_color");
+    example (cr, "hsl_luminosity");
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (operator_www,
+	    "Operator samples from https://cairographics.org/operators/",
+	    "operator", /* keywords */
+	    NULL, /* requirements */
+	    WIDTH * 2, HEIGHT * OPERATORS_COUNT,
+	    NULL, draw)
commit 170f8812fb0b186ea705b23e3cb794a9323c229f
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Tue Apr 6 18:20:49 2021 +0200

    Add a test for #361

diff --git a/test/Makefile.sources b/test/Makefile.sources
index 0fc7c52f6..33d6e81af 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -25,6 +25,7 @@ test_sources = \
 	big-trap.c					\
 	bilevel-image.c					\
 	bug-40410.c					\
+	bug-361.c					\
 	bug-448.c					\
 	bug-51910.c					\
 	bug-75705.c					\
diff --git a/test/bug-361.c b/test/bug-361.c
new file mode 100644
index 000000000..a0499223e
--- /dev/null
+++ b/test/bug-361.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright © 2019 Uli Schlachter
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "cairo-test.h"
+
+/* This is basically gears.shape.arrow */
+static void
+shape (cairo_t *cr, double width, double height)
+{
+    double shaft_length = height / 2;
+    double shaft_width = width / 2;
+    double head_width = width;
+    double head_length = height - shaft_length;
+
+    cairo_move_to (cr, width / 2, 0);
+    cairo_rel_line_to (cr, head_width / 2, head_length);
+    cairo_rel_line_to (cr, -(head_width - shaft_width) / 2, 0);
+    cairo_rel_line_to (cr, 0, shaft_length);
+    cairo_rel_line_to (cr, -shaft_width, 0);
+    cairo_rel_line_to (cr, 0, -shaft_length);
+    cairo_rel_line_to (cr, -(head_width - shaft_width) / 2, 0);
+    cairo_close_path (cr);
+}
+
+/* This is basically the drawing routine of wibox.container.background */
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    double bw = 1.5;
+
+    cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA);
+
+    /* Draw background */
+    cairo_set_source_rgb (cr, 0, 0, 1);
+    cairo_paint (cr);
+
+    /* Create shape */
+    cairo_translate (cr, bw, bw);
+    shape (cr, width - 2 * bw, height - 2 * bw);
+    cairo_translate (cr, -bw, -bw);
+
+    /* Now do the border */
+
+    cairo_push_group_with_content (cr, CAIRO_CONTENT_ALPHA);
+
+    /* Mark everything as "is border" */
+    cairo_set_source_rgba (cr, 0, 0, 0, 1);
+    cairo_paint (cr);
+
+    /* Remove inside of the shape */
+    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+    cairo_set_source_rgba (cr, 0, 0, 0, 0);
+    cairo_fill_preserve (cr);
+
+    cairo_pattern_t *mask = cairo_pop_group (cr);
+
+    /* Now actually draw the border via the mask */
+    cairo_set_source_rgb (cr, 1, 0, 0);
+    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+    cairo_mask (cr, mask);
+
+    cairo_pattern_destroy (mask);
+
+    /* We now have the right content in a temporary surface. Copy it to the
+     * target surface. Needs another mask.
+     */
+    cairo_push_group_with_content (cr, CAIRO_CONTENT_ALPHA);
+
+    cairo_set_line_width (cr, 2 * bw);
+    cairo_set_source_rgba (cr, 0, 0, 0, 1);
+    cairo_stroke_preserve (cr);
+    cairo_fill (cr);
+
+    mask = cairo_pop_group (cr);
+    cairo_pop_group_to_source (cr);
+
+    cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+    cairo_mask (cr, mask);
+
+    cairo_pattern_destroy (mask);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (bug_361,
+	    "Bug 361 (Problem with SVG backend and masks)",
+	    "mask, operator", /* keywords */
+	    NULL, /* requirements */
+	    100, 100,
+	    NULL, draw)
diff --git a/test/meson.build b/test/meson.build
index 0a7bf6d3a..4dc976d43 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -25,6 +25,7 @@ test_sources = [
   'big-trap.c',
   'bilevel-image.c',
   'bug-40410.c',
+  'bug-361.c',
   'bug-448.c',
   'bug-51910.c',
   'bug-75705.c',
diff --git a/test/reference/bug-361.ref.png b/test/reference/bug-361.ref.png
new file mode 100644
index 000000000..cf0385049
Binary files /dev/null and b/test/reference/bug-361.ref.png differ
commit 9563d6b66169785de215e7b4291a137c0b0ce06d
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Tue Apr 6 18:20:30 2021 +0200

    Ignore .idea, compile_commands.json and /build

diff --git a/.gitignore b/.gitignore
index 3259b47ee..23017d16f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
 .deps
 .libs
 .perf
+.idea
 cairo-*.*.*
 manual-*.*.*
 ChangeLog*
@@ -26,6 +27,7 @@ releases
 stamp-h
 stamp-h1
 stamp-h.in
+compile_commands.json
 *~
 .*.sw?
 *.la
@@ -36,3 +38,4 @@ stamp-h.in
 *-uninstalled.pc
 .vimrc
 gtk-doc.m4
+/build
commit 18c0196414ede7137886a588f95af99b5591622b
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Fri Nov 13 19:23:37 2020 +0100

    Fix generating syntactically invalid SVG files

diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index cbf5922fb..d166afc62 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -1642,6 +1642,10 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
 				     extents.height);
     }
 
+    if (source->base.content == CAIRO_CONTENT_ALPHA) {
+	_cairo_svg_surface_emit_alpha_filter (document);
+    }
+
     _cairo_output_stream_printf (document->xml_node_defs,
 				 "<g id=\"surface%d\"",
 				 source_id);
@@ -1653,7 +1657,6 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
     }
 
     if (source->base.content == CAIRO_CONTENT_ALPHA) {
-	_cairo_svg_surface_emit_alpha_filter (document);
 	_cairo_output_stream_printf (document->xml_node_defs,
 				     " filter=\"url(#alpha)\"");
     }
commit 8c08f499bd52d79d0ee13be5050d134e97e2211b
Author: Anton Danilkin <afdw at yandex.ru>
Date:   Fri Nov 13 17:23:13 2020 +0100

    Fix problems in the SVG backend related to outputting surfaces and patterns
    
    Now the SVG surface should work correctly work with bounded and unbounded image (-like) and recording surfaces with NONE and REPEAT extends as source for all operations.
    
    Fill or stroke with an unbounded surface as source now means using clip or mask respectively.
    
    Fix using unitialized memory in the SVG surface.
    
    Also fix unintialized memory and working with offsetted images in the recording surface.

diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index ff0cb8be7..561425fa9 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -937,9 +937,22 @@ _cairo_gstate_copy_transformed_pattern (cairo_gstate_t  *gstate,
 					const cairo_pattern_t *original,
 					const cairo_matrix_t  *ctm_inverse)
 {
+    /*
+     * What calculations bellow do can described in pseudo-code (so using nonexistent fields) as (using column vectors):
+     * pattern->matrix = surface->device_transform *
+     * 			 pattern->matrix *
+     * 			 ctm_inverse *
+     * 			 gstate->target->device_transform_inverse
+     *
+     * The inverse of which is:
+     * pattern->matrix_inverse = gstate->target->device_transform *
+     * 				 ctm *
+     * 				 pattern->matrix_inverse *
+     * 				 surface->device_transform_inverse
+     */
+
     _cairo_gstate_copy_pattern (pattern, original);
 
-    /* apply device_transform first so that it is transformed by ctm_inverse */
     if (original->type == CAIRO_PATTERN_TYPE_SURFACE) {
 	cairo_surface_pattern_t *surface_pattern;
 	cairo_surface_t *surface;
diff --git a/src/cairo-output-stream-private.h b/src/cairo-output-stream-private.h
index 2542646b8..91657c3c6 100644
--- a/src/cairo-output-stream-private.h
+++ b/src/cairo-output-stream-private.h
@@ -177,6 +177,9 @@ _cairo_memory_stream_copy (cairo_output_stream_t *base,
 cairo_private int
 _cairo_memory_stream_length (cairo_output_stream_t *stream);
 
+cairo_private char *
+_cairo_memory_stream_to_string (cairo_output_stream_t *stream);
+
 cairo_private cairo_status_t
 _cairo_memory_stream_destroy (cairo_output_stream_t *abstract_stream,
 			      unsigned char **data_out,
diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c
index 935fa44c3..f00419ecd 100644
--- a/src/cairo-output-stream.c
+++ b/src/cairo-output-stream.c
@@ -787,6 +787,16 @@ _cairo_memory_stream_length (cairo_output_stream_t *base)
     return _cairo_array_num_elements (&stream->array);
 }
 
+char *
+_cairo_memory_stream_to_string (cairo_output_stream_t *base)
+{
+    memory_stream_t *stream = (memory_stream_t *) base;
+
+    char zero = 0;
+    _cairo_array_append(&stream->array, &zero);
+    return _cairo_array_index (&stream->array, 0);
+}
+
 static cairo_status_t
 null_write (cairo_output_stream_t *base,
 	    const unsigned char *data, unsigned int length)
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index 71a44798f..8d0e5376a 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -613,6 +613,8 @@ _cairo_recording_surface_acquire_source_image (void			 *abstract_surface,
     if (unlikely (image->status))
 	return image->status;
 
+    cairo_surface_set_device_offset(image, -surface->extents.x, -surface->extents.y);
+
     /* Handle recursion by returning future reads from the current image */
     proxy = attach_proxy (abstract_surface, image);
     status = _cairo_recording_surface_replay (&surface->base, image);
@@ -1592,6 +1594,8 @@ _cairo_recording_surface_snapshot (void *abstract_other)
     surface->extents_pixels = other->extents_pixels;
     surface->extents = other->extents;
     surface->unbounded = other->unbounded;
+    surface->has_bilevel_alpha = other->has_bilevel_alpha;
+    surface->has_only_op_over = other->has_only_op_over;
 
     surface->base.is_clear = other->base.is_clear;
 
diff --git a/src/cairo-svg-surface-private.h b/src/cairo-svg-surface-private.h
index 6f693252a..564316812 100644
--- a/src/cairo-svg-surface-private.h
+++ b/src/cairo-svg-surface-private.h
@@ -72,8 +72,6 @@ typedef struct cairo_svg_surface {
 
     cairo_surface_clipper_t clipper;
     unsigned int clip_level;
-    unsigned int base_clip;
-    cairo_bool_t is_base_clip_emitted;
 
     cairo_paginated_mode_t paginated_mode;
 
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 7e7051eb6..cbf5922fb 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -619,7 +619,7 @@ _cairo_svg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper
     }
 
     /* skip trivial whole-page clips */
-    if (_cliprect_covers_surface (surface, path))
+    if (surface->surface_bounded && _cliprect_covers_surface (surface, path))
 	return CAIRO_STATUS_SUCCESS;
 
     _cairo_output_stream_printf (document->xml_node_defs,
@@ -676,9 +676,6 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t	*document,
     _cairo_surface_clipper_init (&surface->clipper,
 				 _cairo_svg_surface_clipper_intersect_clip_path);
 
-    surface->base_clip = document->clip_id++;
-    surface->is_base_clip_emitted = FALSE;
-
     surface->xml_node = _cairo_memory_stream_create ();
     status = _cairo_output_stream_get_status (surface->xml_node);
     if (unlikely (status))
@@ -1141,9 +1138,10 @@ _cairo_svg_surface_analyze_operation (cairo_svg_surface_t   *surface,
     if (pattern->type == CAIRO_PATTERN_TYPE_MESH)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    /* SVG doesn't support extend reflect for image pattern */
+    /* SVG doesn't support extends reflect and pad for surface pattern */
     if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE &&
-	pattern->extend == CAIRO_EXTEND_REFLECT)
+	pattern->extend != CAIRO_EXTEND_NONE &&
+	pattern->extend != CAIRO_EXTEND_REPEAT)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
     if (document->svg_version >= CAIRO_SVG_VERSION_1_2)
@@ -1488,8 +1486,9 @@ _cairo_svg_surface_emit_surface (cairo_svg_document_t *document,
     assert (is_bounded);
 
     _cairo_output_stream_printf (document->xml_node_defs,
-				 "<image id=\"image%d\" width=\"%d\" height=\"%d\"",
+				 "<image id=\"image%d\" x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"",
 				 source_id,
+				 extents.x, extents.y,
 				 extents.width, extents.height);
 
     _cairo_output_stream_printf (document->xml_node_defs, " xlink:href=\"");
@@ -1555,8 +1554,13 @@ _cairo_svg_surface_emit_composite_surface_pattern (cairo_output_stream_t   *outp
 	_cairo_output_stream_printf (output,
 				     "<pattern id=\"pattern%d\" "
 				     "patternUnits=\"userSpaceOnUse\" "
-				     "width=\"%d\" height=\"%d\" ",
+				     "x=\"%d\" y=\"%d\" "
+				     "width=\"%d\" height=\"%d\" "
+				     "viewBox=\"%d %d %d %d\" ",
 				     pattern_id,
+				     extents.x, extents.y,
+				     extents.width, extents.height,
+				     extents.x, extents.y,
 				     extents.width, extents.height);
 	_cairo_svg_surface_emit_transform (output,
 					   " patternTransform",
@@ -1601,9 +1605,9 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
     bounded = _cairo_surface_get_extents (&source->base, &extents);
     paginated_surface = _cairo_svg_surface_create_for_document (document,
 								source->base.content,
-								extents.width,
-								extents.height,
-								bounded);
+								0,
+								0,
+								FALSE);
     if (unlikely (paginated_surface->status))
 	return paginated_surface->status;
 
@@ -1612,9 +1616,6 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
     cairo_surface_set_fallback_resolution (paginated_surface,
 					   document->owner->x_fallback_resolution,
 					   document->owner->y_fallback_resolution);
-    cairo_surface_set_device_offset (&svg_surface->base,
-				     -source->extents_pixels.x,
-				     -source->extents_pixels.y);
 
     status = _cairo_recording_surface_replay (&source->base, paginated_surface);
     if (unlikely (status)) {
@@ -1629,35 +1630,39 @@ _cairo_svg_surface_emit_recording_surface (cairo_svg_document_t      *document,
 	return status;
     }
 
-    if (! svg_surface->is_base_clip_emitted) {
-	svg_surface->is_base_clip_emitted = TRUE;
-	if (_cairo_surface_get_extents (&svg_surface->base, &extents)) {
-	    _cairo_output_stream_printf (document->xml_node_defs,
-					 "<clipPath id=\"clip%d\">\n"
-					 "  <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"/>\n"
-					 "</clipPath>\n",
-					 svg_surface->base_clip,
-					 extents.x,
-					 extents.y,
-					 extents.width,
-					 extents.height);
-	}
+    if (bounded) {
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     "<clipPath id=\"clip%d\">\n"
+				     "  <rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\"/>\n"
+				     "</clipPath>\n",
+				     svg_surface->document->clip_id,
+				     extents.x,
+				     extents.y,
+				     extents.width,
+				     extents.height);
+    }
+
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 "<g id=\"surface%d\"",
+				 source_id);
+
+    if (bounded) {
+	_cairo_output_stream_printf (document->xml_node_defs,
+				     " clip-path=\"url(#clip%d)\"",
+				     svg_surface->document->clip_id);
     }
 
     if (source->base.content == CAIRO_CONTENT_ALPHA) {
 	_cairo_svg_surface_emit_alpha_filter (document);
 	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<g id=\"surface%d\" "
-				     "clip-path=\"url(#clip%d)\" "
-				     "filter=\"url(#alpha)\">\n",
-				     source_id,
-				     svg_surface->base_clip);
-    } else {
-	_cairo_output_stream_printf (document->xml_node_defs,
-				     "<g id=\"surface%d\" "
-				     "clip-path=\"url(#clip%d)\">\n",
-				     source_id,
-				     svg_surface->base_clip);
+				     " filter=\"url(#alpha)\"");
+    }
+
+    _cairo_output_stream_printf (document->xml_node_defs,
+				 ">\n");
+
+    if (bounded) {
+	svg_surface->document->clip_id++;
     }
 
     contents = svg_surface->xml_node;
@@ -1696,6 +1701,14 @@ to_recording_surface (const cairo_surface_pattern_t *pattern)
     return (cairo_recording_surface_t *) surface;
 }
 
+static cairo_bool_t
+_cairo_svg_surface_svg_pattern_should_be_used (const cairo_pattern_t *pattern) {
+    cairo_rectangle_int_t extents;
+    return pattern->type == CAIRO_PATTERN_TYPE_SURFACE &&
+	   pattern->extend == CAIRO_EXTEND_REPEAT &&
+	   _cairo_surface_get_extents (((cairo_surface_pattern_t *) pattern)->surface, &extents);
+}
+
 static cairo_status_t
 _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t	*output,
 						     cairo_svg_surface_t	*surface,
@@ -1732,13 +1745,21 @@ _cairo_svg_surface_emit_composite_recording_pattern (cairo_output_stream_t	*outp
     }
 
     if (pattern_id != invalid_pattern_id) {
+        assert (!recording_surface->unbounded);
 	_cairo_output_stream_printf (output,
 				     "<pattern id=\"pattern%d\" "
 				     "patternUnits=\"userSpaceOnUse\" "
-				     "width=\"%d\" height=\"%d\"",
+				     "x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" "
+				     "viewBox=\"%f %f %f %f\"",
 				     pattern_id,
-				     recording_surface->extents.width,
-				     recording_surface->extents.height);
+				     recording_surface->extents_pixels.x,
+				     recording_surface->extents_pixels.y,
+				     recording_surface->extents_pixels.width,
+				     recording_surface->extents_pixels.height,
+				     recording_surface->extents_pixels.x,
+				     recording_surface->extents_pixels.y,
+				     recording_surface->extents_pixels.width,
+				     recording_surface->extents_pixels.height);
 	_cairo_svg_surface_emit_transform (output, " patternTransform", &p2u, parent_matrix);
 	_cairo_output_stream_printf (output, ">\n");
     }
@@ -1772,6 +1793,9 @@ _cairo_svg_surface_emit_composite_pattern (cairo_output_stream_t   *output,
 					   const cairo_matrix_t	   *parent_matrix,
 					   const char		   *extra_attributes)
 {
+    if (pattern_id != invalid_pattern_id) {
+        assert (_cairo_svg_surface_svg_pattern_should_be_used(&pattern->base));
+    }
 
     if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
 	return _cairo_svg_surface_emit_composite_recording_pattern (output, surface,
@@ -2149,12 +2173,12 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t    *surface,
 	/* SVG doesn't support the inner circle and use instead a gradient focal.
 	 * That means we need to emulate the cairo behaviour by processing the
 	 * cairo gradient stops.
-	 * The CAIRO_EXTENT_NONE and CAIRO_EXTENT_PAD modes are quite easy to handle,
+	 * The CAIRO_EXTEND_NONE and CAIRO_EXTEND_PAD modes are quite easy to handle,
 	 * it's just a matter of stop position translation and calculation of
 	 * the corresponding SVG radial gradient focal.
-	 * The CAIRO_EXTENT_REFLECT and CAIRO_EXTEND_REPEAT modes require to compute a new
+	 * The CAIRO_EXTEND_REFLECT and CAIRO_EXTEND_REPEAT modes require to compute a new
 	 * radial gradient, with an new outer circle, equal to r1 - r0 in the CAIRO_EXTEND_REPEAT
-	 * case, and 2 * (r1 - r0) in the CAIRO_EXTENT_REFLECT case, and a new gradient stop
+	 * case, and 2 * (r1 - r0) in the CAIRO_EXTEND_REFLECT case, and a new gradient stop
 	 * list that maps to the original cairo stop list.
 	 */
 	if ((extend == CAIRO_EXTEND_REFLECT
@@ -2385,6 +2409,22 @@ _cairo_svg_surface_fill_stroke (void			*abstract_surface,
     cairo_svg_surface_t *surface = abstract_surface;
     cairo_status_t status;
 
+    if (_cairo_svg_surface_svg_pattern_should_be_used (fill_source) ||
+	_cairo_svg_surface_svg_pattern_should_be_used (stroke_source)) {
+	status = _cairo_surface_fill (&surface->base, fill_op, fill_source, path,
+				      fill_rule, fill_tolerance, fill_antialias,
+				      clip);
+	if (unlikely (status))
+	    return status;
+
+	status = _cairo_surface_stroke (&surface->base, stroke_op, stroke_source, path,
+					stroke_style, stroke_ctm, stroke_ctm_inverse,
+					stroke_tolerance, stroke_antialias,
+					clip);
+	if (unlikely (status))
+	    return status;
+    }
+
     status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
     if (unlikely (status))
 	return status;
@@ -2432,16 +2472,57 @@ _cairo_svg_surface_fill (void			*abstract_surface,
     if (unlikely (status))
 	return status;
 
-    _cairo_output_stream_printf (surface->xml_node, "<path style=\" stroke:none;");
-    status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, op, source, fill_rule, NULL);
-    if (unlikely (status))
-	return status;
+    if (source->type == CAIRO_PATTERN_TYPE_SURFACE && !_cairo_svg_surface_svg_pattern_should_be_used (source)) {
+	_cairo_output_stream_printf (surface->document->xml_node_defs,
+				     "<clipPath id=\"clip%d\">\n"
+				     "  <path ",
+				     surface->document->clip_id);
 
-    _cairo_output_stream_printf (surface->xml_node, "\" ");
+	_cairo_svg_surface_emit_path (surface->document->xml_node_defs, path, NULL);
 
-    _cairo_svg_surface_emit_path (surface->xml_node, path, NULL);
+	_cairo_output_stream_printf (surface->document->xml_node_defs,
+				     "/>\n"
+				     "</clipPath>\n");
 
-    _cairo_output_stream_printf (surface->xml_node, "/>\n");
+	_cairo_output_stream_printf (surface->xml_node,
+				     "<g clip-path=\"url(#clip%d)\" "
+				     "clip-rule=\"%s\" "
+				     "style=\"",
+				     surface->document->clip_id,
+				     fill_rule == CAIRO_FILL_RULE_EVEN_ODD ?
+				     "evenodd" : "nonzero");
+
+	surface->document->clip_id++;
+
+	_cairo_svg_surface_emit_operator_for_style (surface->xml_node, surface, op);
+
+	_cairo_output_stream_printf (surface->xml_node,
+				     "\">\n");
+
+	status = _cairo_svg_surface_emit_composite_pattern (surface->xml_node,
+							    surface,
+							    op,
+							    (cairo_surface_pattern_t *) source,
+							    invalid_pattern_id,
+							    NULL,
+							    NULL);
+	if (unlikely (status))
+	    return status;
+
+	_cairo_output_stream_printf (surface->xml_node,
+				     "</g>");
+    } else {
+	_cairo_output_stream_printf (surface->xml_node, "<path style=\"stroke:none;");
+	status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, op, source, fill_rule, NULL);
+	if (unlikely (status))
+	    return status;
+
+	_cairo_output_stream_printf (surface->xml_node, "\" ");
+
+	_cairo_svg_surface_emit_path (surface->xml_node, path, NULL);
+
+	_cairo_output_stream_printf (surface->xml_node, "/>\n");
+    }
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -2475,21 +2556,19 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
 {
     cairo_status_t status;
 
-    if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
-	source->extend == CAIRO_EXTEND_NONE)
+    if (source->type == CAIRO_PATTERN_TYPE_SURFACE && !_cairo_svg_surface_svg_pattern_should_be_used(source))
 	return _cairo_svg_surface_emit_composite_pattern (output,
 							  surface,
 							  op,
 							  (cairo_surface_pattern_t *) source,
 							  invalid_pattern_id,
-							  mask_source ? &mask_source->matrix :NULL,
+							  mask_source ? &mask_source->matrix : NULL,
 							  extra_attributes);
 
     _cairo_output_stream_printf (output,
-				 "<rect x=\"0\" y=\"0\" "
-				 "width=\"%f\" height=\"%f\" "
-				 "style=\"",
-				 surface->width, surface->height);
+				 "<rect x=\"-1000000%%\" y=\"-1000000%%\" "
+				 "width=\"2000000%%\" height=\"2000000%%\" "
+				 "style=\"");
     _cairo_svg_surface_emit_operator_for_style (output, surface, op);
     status = _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, NULL);
     if (unlikely (status))
@@ -2544,12 +2623,11 @@ _cairo_svg_surface_paint (void		    *abstract_surface,
 	    if (op == CAIRO_OPERATOR_CLEAR) {
 		if (surface->content == CAIRO_CONTENT_COLOR) {
 		    _cairo_output_stream_printf (surface->xml_node,
-						 "<rect "
-						 "width=\"%f\" height=\"%f\" "
+						 "<rect x=\"-1000000%%\" y=\"-1000000%%\" "
+						 "width=\"2000000%%\" height=\"2000000%%\" "
 						 "style=\"opacity:1;"
 						 "stroke:none;"
-						 "fill:rgb(0,0,0);\"/>\n",
-						 surface->width, surface->height);
+						 "fill:rgb(0,0,0);\"/>\n");
 		}
 		return CAIRO_STATUS_SUCCESS;
 	    }
@@ -2567,7 +2645,7 @@ _cairo_svg_surface_paint (void		    *abstract_surface,
 	return status;
 
     return _cairo_svg_surface_emit_paint (surface->xml_node,
-					  surface, op, source, 0, NULL);
+					  surface, op, source, NULL, NULL);
 }
 
 static cairo_int_status_t
@@ -2581,7 +2659,6 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
     cairo_svg_surface_t *surface = abstract_surface;
     cairo_svg_document_t *document = surface->document;
     cairo_output_stream_t *mask_stream;
-    char buffer[64];
     cairo_bool_t discard_filter = FALSE;
     unsigned int mask_id;
 
@@ -2652,9 +2729,27 @@ _cairo_svg_surface_mask (void		    *abstract_surface,
     if (unlikely (status))
 	return status;
 
-    snprintf (buffer, sizeof buffer, "mask=\"url(#mask%d)\"",
-	      mask_id);
-    status = _cairo_svg_surface_emit_paint (surface->xml_node, surface, op, source, 0, buffer);
+    cairo_output_stream_t *extra_attributes_stream = _cairo_memory_stream_create ();
+    if (_cairo_output_stream_get_status (extra_attributes_stream))
+	return _cairo_output_stream_destroy (extra_attributes_stream);
+
+    _cairo_output_stream_printf (extra_attributes_stream,
+				 "mask=\"url(#mask%d)\"",
+				 mask_id);
+
+    status = _cairo_svg_surface_emit_paint (surface->xml_node,
+					    surface,
+					    op,
+					    source,
+					    NULL,
+					    _cairo_memory_stream_to_string (extra_attributes_stream));
+    if (unlikely (status)) {
+	cairo_status_t ignore = _cairo_output_stream_destroy (extra_attributes_stream);
+	return status;
+	(void) ignore;
+    }
+
+    status = _cairo_output_stream_destroy (extra_attributes_stream);
     if (unlikely (status))
 	return status;
 
@@ -2685,18 +2780,78 @@ _cairo_svg_surface_stroke (void			*abstract_dst,
     if (unlikely (status))
 	return status;
 
-    _cairo_output_stream_printf (surface->xml_node, "<path style=\"fill:none;");
-    status = _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface, op,
-						   source, stroke_style, ctm_inverse);
+    cairo_bool_t svg_pattern_should_not_be_used = source->type == CAIRO_PATTERN_TYPE_SURFACE &&
+						  !_cairo_svg_surface_svg_pattern_should_be_used (source);
+    unsigned int mask_id;
+    cairo_output_stream_t *output_stream = surface->xml_node;
+    cairo_pattern_t *white_pattern;
+    if (svg_pattern_should_not_be_used) {
+	mask_id = _cairo_svg_document_allocate_mask_id (surface->document);
+
+	output_stream = surface->document->xml_node_defs;
+
+	_cairo_output_stream_printf (output_stream,
+				     "<mask id=\"mask%d\">\n",
+				     mask_id);
+
+	white_pattern = cairo_pattern_create_rgb(1.0, 1.0, 1.0);
+    }
+
+    _cairo_output_stream_printf (output_stream, "<path style=\"fill:none;");
+    status = _cairo_svg_surface_emit_stroke_style (output_stream,
+						   surface,
+						   svg_pattern_should_not_be_used ? CAIRO_OPERATOR_OVER : op,
+						   svg_pattern_should_not_be_used ? white_pattern : source,
+						   stroke_style,
+						   ctm_inverse);
+
     if (unlikely (status))
 	return status;
 
-    _cairo_output_stream_printf (surface->xml_node, "\" ");
+    _cairo_output_stream_printf (output_stream, "\" ");
 
-    _cairo_svg_surface_emit_path (surface->xml_node, path, ctm_inverse);
+    _cairo_svg_surface_emit_path (output_stream, path, ctm_inverse);
 
-    _cairo_svg_surface_emit_transform (surface->xml_node, " transform", ctm, NULL);
-    _cairo_output_stream_printf (surface->xml_node, "/>\n");
+    _cairo_svg_surface_emit_transform (output_stream,
+				       " transform", ctm, NULL);
+    _cairo_output_stream_printf (output_stream, "/>\n");
+
+    if (svg_pattern_should_not_be_used) {
+        cairo_pattern_destroy(white_pattern);
+
+	_cairo_output_stream_printf (output_stream,
+				     "</mask>\n");
+
+	cairo_output_stream_t *extra_attributes_stream = _cairo_memory_stream_create ();
+	if (_cairo_output_stream_get_status (extra_attributes_stream))
+	    return _cairo_output_stream_destroy (extra_attributes_stream);
+
+	_cairo_output_stream_printf (extra_attributes_stream,
+				     "mask=\"url(#mask%d)\" style=\"",
+				     mask_id);
+
+	_cairo_svg_surface_emit_operator_for_style (extra_attributes_stream, surface, op);
+
+	_cairo_output_stream_printf (extra_attributes_stream,
+				     "\"");
+
+	status = _cairo_svg_surface_emit_composite_pattern (surface->xml_node,
+							    surface,
+							    op,
+							    (cairo_surface_pattern_t *) source,
+							    invalid_pattern_id,
+							    NULL,
+							    _cairo_memory_stream_to_string (extra_attributes_stream));
+	if (unlikely (status)) {
+	    cairo_status_t ignore = _cairo_output_stream_destroy (extra_attributes_stream);
+	    return status;
+	    (void) ignore;
+	}
+
+	status = _cairo_output_stream_destroy (extra_attributes_stream);
+	if (unlikely (status))
+	    return status;
+    }
 
     return CAIRO_STATUS_SUCCESS;
 }


More information about the cairo-commit mailing list