[cairo-commit] 10 commits - src/cairo-analysis-surface.c src/cairo-beos-surface.cpp src/cairo-clip.c src/cairo-directfb-surface.c src/cairo-glitz-surface.c src/cairo-image-surface.c src/cairoint.h src/cairo-meta-surface.c src/cairo-os2-surface.c src/cairo-paginated-surface.c src/cairo-path-fixed.c src/cairo-pdf-surface.c src/cairo-ps-surface.c src/cairo-quartz-image-surface.c src/cairo-quartz-surface.c src/cairo-rectangle.c src/cairo-script-surface.c src/cairo-sdl-surface.c src/cairo-spans.c src/cairo-spans-private.h src/cairo-surface.c src/cairo-surface-fallback.c src/cairo-svg-surface.c src/cairo-tor-scan-converter.c src/cairo-type3-glyph-surface.c src/cairo-types-private.h src/cairo-win32-printing-surface.c src/cairo-win32-surface.c src/cairo-xcb-surface.c src/cairo-xlib-surface.c src/Makefile.sources src/test-fallback-surface.c src/test-meta-surface.c src/test-paginated-surface.c test/clip-fill-rule.pdf.argb32.ref.png test/clip-fill-rule.rgb24.ref.png test/clip-fill-rule.test-fallback.rgb24.ref.png test/clip-fill-rule.test-paginated.rgb24.ref.png test/clip-fill-rule.xlib.rgb24.ref.png test/clip-nesting.pdf.argb32.ref.png test/clip-nesting.rgb24.ref.png test/clip-nesting.test-fallback.rgb24.ref.png test/clip-nesting.test-paginated.rgb24.ref.png test/clip-nesting.xlib.rgb24.ref.png test/clip-operator.pdf.argb32.ref.png test/clip-operator.pdf.rgb24.ref.png test/clip-operator.ps2.rgb24.ref.png test/clip-operator.ps3.argb32.ref.png test/clip-operator.ps3.rgb24.ref.png test/clip-operator.ref.png test/clip-operator.rgb24.ref.png test/clip-operator.test-fallback.argb32.ref.png test/clip-operator.test-fallback.rgb24.ref.png test/clip-operator.test-paginated.argb32.ref.png test/clip-operator.xlib-fallback.rgb24.ref.png test/clip-operator.xlib.ref.png test/clip-operator.xlib.rgb24.ref.png test/clipped-group.pdf.argb32.ref.png test/clipped-group.pdf.rgb24.ref.png test/clip-twice.pdf.argb32.ref.png test/clip-twice.ref.png test/clip-twice.rgb24.ref.png test/clip-twice.test-fallback.argb32.ref.png test/clip-twice.test-fallback.rgb24.ref.png test/clip-twice.test-paginated.argb32.ref.png test/clip-twice.test-paginated.rgb24.ref.png test/clip-twice.xlib.ref.png test/clip-twice.xlib.rgb24.ref.png test/degenerate-arc.ref.png test/degenerate-arc.test-fallback.argb32.ref.png test/degenerate-arc.test-fallback.rgb24.ref.png test/degenerate-arc.xlib.ref.png test/device-offset-fractional.pdf.argb32.ref.png test/device-offset-fractional.pdf.rgb24.ref.png test/fill-alpha-pattern.pdf.argb32.ref.png test/fill-alpha-pattern.pdf.rgb24.ref.png test/fill-alpha-pattern.ps3.argb32.ref.png test/fill-alpha-pattern.ps3.rgb24.ref.png test/fill-alpha-pattern.ref.png test/fill-alpha-pattern.test-fallback.argb32.ref.png test/fill-alpha-pattern.test-fallback.rgb24.ref.png test/fill-alpha-pattern.xlib.ref.png test/fill-alpha.ref.png test/fill-alpha.test-fallback.argb32.ref.png test/fill-alpha.test-fallback.rgb24.ref.png test/fill-alpha.xlib.ref.png test/fill-degenerate-sort-order.ref.png test/fill-degenerate-sort-order.rgb24.ref.png test/fill-degenerate-sort-order.test-fallback.argb32.ref.png test/fill-degenerate-sort-order.test-fallback.rgb24.ref.png test/fill-degenerate-sort-order.xlib.ref.png test/fill-degenerate-sort-order.xlib.rgb24.ref.png test/fill-missed-stop.pdf.argb32.ref.png test/fill-rule.ref.png test/fill-rule.rgb24.ref.png test/fill-rule.test-fallback.argb32.ref.png test/fill-rule.test-fallback.rgb24.ref.png test/fill-rule.xlib.ref.png test/fill-rule.xlib.rgb24.ref.png test/filter-nearest-offset.pdf.argb32.ref.png test/filter-nearest-offset.pdf.rgb24.ref.png test/filter-nearest-transformed.pdf.argb32.ref.png test/filter-nearest-transformed.pdf.rgb24.ref.png test/finer-grained-fallbacks.ps2.argb32.ref.png test/finer-grained-fallbacks.ps2.rgb24.ref.png test/finer-grained-fallbacks.ps3.argb32.ref.png test/finer-grained-fallbacks.ps3.rgb24.ref.png test/finer-grained-fallbacks.ref.png test/finer-grained-fallbacks.rgb24.ref.png test/finer-grained-fallbacks.test-fallback.argb32.ref.png test/finer-grained-fallbacks.test-fallback.rgb24.ref.png test/finer-grained-fallbacks.xlib.ref.png test/finer-grained-fallbacks.xlib.rgb24.ref.png test/font-matrix-translation.svg11.argb32.ref.png test/font-matrix-translation.svg11.rgb24.ref.png test/font-matrix-translation.svg12.argb32.ref.png test/font-matrix-translation.svg12.rgb24.ref.png test/ft-show-glyphs-table.svg11.argb32.ref.png test/ft-show-glyphs-table.svg11.rgb24.ref.png test/ft-show-glyphs-table.svg12.argb32.ref.png test/ft-show-glyphs-table.svg12.rgb24.ref.png test/ft-text-vertical-layout-type1.pdf.argb32.ref.png test/ft-text-vertical-layout-type1.pdf.rgb24.ref.png test/ft-text-vertical-layout-type1.ref.png test/ft-text-vertical-layout-type1.svg11.argb32.ref.png test/ft-text-vertical-layout-type1.svg11.rgb24.ref.png test/ft-text-vertical-layout-type1.svg12.argb32.ref.png test/ft-text-vertical-layout-type1.svg12.rgb24.ref.png test/ft-text-vertical-layout-type1.test-fallback.argb32.ref.png test/ft-text-vertical-layout-type1.test-fallback.rgb24.ref.png test/ft-text-vertical-layout-type1.xlib.ref.png test/ft-text-vertical-layout-type3.pdf.argb32.ref.png test/ft-text-vertical-layout-type3.pdf.rgb24.ref.png test/ft-text-vertical-layout-type3.ref.png test/ft-text-vertical-layout-type3.svg11.argb32.ref.png test/ft-text-vertical-layout-type3.svg11.rgb24.ref.png test/ft-text-vertical-layout-type3.svg12.argb32.ref.png test/ft-text-vertical-layout-type3.svg12.rgb24.ref.png test/ft-text-vertical-layout-type3.test-fallback.argb32.ref.png test/ft-text-vertical-layout-type3.test-fallback.rgb24.ref.png test/ft-text-vertical-layout-type3.xlib.ref.png test/huge-pattern.pdf.argb32.ref.png test/linear-gradient.pdf.argb32.ref.png test/linear-gradient.pdf.rgb24.ref.png test/linear-gradient.ref.png test/linear-gradient.svg11.argb32.ref.png test/linear-gradient.svg11.rgb24.ref.png test/linear-gradient.svg12.argb32.ref.png test/linear-gradient.svg12.rgb24.ref.png test/linear-gradient.test-fallback.argb32.ref.png test/linear-gradient.test-fallback.rgb24.ref.png test/linear-gradient.xlib.ref.png test/mask-alpha.ref.png test/mask-alpha.svg11.argb32.ref.png test/mask-alpha.svg11.rgb24.ref.png test/mask-alpha.svg12.argb32.ref.png test/mask-alpha.svg12.rgb24.ref.png test/mask-alpha.test-fallback.argb32.ref.png test/mask-alpha.xlib.ref.png test/mask-alpha.xlib.rgb24.ref.png test/mask.pdf.argb32.ref.png test/mask.pdf.rgb24.ref.png test/mask.ref.png test/mask.rgb24.ref.png test/mask.svg11.argb32.ref.png test/mask.svg11.rgb24.ref.png test/mask.svg12.argb32.ref.png test/mask.svg12.rgb24.ref.png test/mask.test-fallback.argb32.ref.png test/mask.test-fallback.rgb24.ref.png test/mask.xlib-fallback.rgb24.ref.png test/mask.xlib.ref.png test/mask.xlib.rgb24.ref.png test/meta-surface-pattern.pdf.argb32.ref.png test/meta-surface-pattern.pdf.rgb24.ref.png test/meta-surface-pattern.svg11.argb32.ref.png test/meta-surface-pattern.svg11.rgb24.ref.png test/meta-surface-pattern.svg12.argb32.ref.png test/meta-surface-pattern.svg12.rgb24.ref.png test/operator-clear.pdf.argb32.ref.png test/operator-clear.ps2.argb32.ref.png test/operator-clear.ps3.argb32.ref.png test/operator-source.pdf.argb32.ref.png test/operator-source.pdf.rgb24.ref.png test/operator-source.ref.png test/operator-source.rgb24.ref.png test/operator-source.test-fallback.argb32.ref.png test/operator-source.test-fallback.rgb24.ref.png test/operator-source.xlib-fallback.rgb24.ref.png test/operator-source.xlib.ref.png test/operator-source.xlib.rgb24.ref.png test/over-above-source.ps2.argb32.ref.png test/over-above-source.ps3.argb32.ref.png test/over-above-source.ref.png test/over-above-source.rgb24.ref.png test/over-above-source.test-fallback.argb32.ref.png test/over-above-source.test-fallback.rgb24.ref.png test/over-above-source.xlib.ref.png test/over-above-source.xlib.rgb24.ref.png test/over-around-source.pdf.argb32.ref.png test/over-around-source.ps2.argb32.ref.png test/over-around-source.ps3.argb32.ref.png test/over-around-source.ref.png test/over-around-source.test-fallback.argb32.ref.png test/over-around-source.xlib.ref.png test/over-around-source.xlib.rgb24.ref.png test/over-below-source.pdf.argb32.ref.png test/over-between-source.ps2.argb32.ref.png test/over-between-source.ps3.argb32.ref.png test/over-between-source.ref.png test/over-between-source.test-fallback.argb32.ref.png test/over-between-source.xlib.ref.png test/over-between-source.xlib.rgb24.ref.png test/push-group.pdf.argb32.ref.png test/push-group.pdf.rgb24.ref.png test/push-group.ref.png test/push-group.rgb24.ref.png test/push-group.svg11.argb32.ref.png test/push-group.svg12.argb32.ref.png test/push-group.test-fallback.argb32.ref.png test/push-group.test-fallback.rgb24.ref.png test/push-group.xlib-fallback.rgb24.ref.png test/push-group.xlib.ref.png test/push-group.xlib.rgb24.ref.png test/radial-gradient.pdf.argb32.ref.png test/radial-gradient.pdf.rgb24.ref.png test/random-intersections.ref.png test/random-intersections.test-fallback.argb32.ref.png test/random-intersections.test-fallback.rgb24.ref.png test/random-intersections.xlib.ref.png test/rotate-image-surface-paint.pdf.argb32.ref.png test/rotate-image-surface-paint.pdf.rgb24.ref.png test/smask-fill.pdf.argb32.ref.png test/smask-fill.pdf.rgb24.ref.png test/smask-fill.ref.png test/smask-fill.svg11.argb32.ref.png test/smask-fill.svg11.rgb24.ref.png test/smask-fill.svg12.argb32.ref.png test/smask-fill.svg12.rgb24.ref.png test/smask-fill.test-fallback.argb32.ref.png test/smask-fill.test-fallback.rgb24.ref.png test/smask-fill.xlib-fallback.ref.png test/smask-fill.xlib.ref.png test/smask-image-mask.pdf.argb32.ref.png test/smask-image-mask.pdf.rgb24.ref.png test/smask-mask.pdf.argb32.ref.png test/smask-mask.pdf.rgb24.ref.png test/smask-paint.pdf.argb32.ref.png test/smask-paint.pdf.rgb24.ref.png test/smask.pdf.argb32.ref.png test/smask.pdf.rgb24.ref.png test/smask-stroke.pdf.argb32.ref.png test/smask-stroke.pdf.rgb24.ref.png test/smask-text.svg11.argb32.ref.png test/smask-text.svg11.rgb24.ref.png test/smask-text.svg12.argb32.ref.png test/smask-text.svg12.rgb24.ref.png test/surface-pattern.pdf.argb32.ref.png test/surface-pattern.pdf.rgb24.ref.png test/surface-pattern-scale-down.pdf.argb32.ref.png test/surface-pattern-scale-down.pdf.rgb24.ref.png test/surface-pattern-scale-up.pdf.argb32.ref.png test/surface-pattern-scale-up.pdf.rgb24.ref.png test/text-pattern.pdf.argb32.ref.png test/text-pattern.svg11.argb32.ref.png test/text-pattern.svg12.argb32.ref.png test/text-rotate.svg11.argb32.ref.png test/text-rotate.svg11.rgb24.ref.png test/text-rotate.svg12.argb32.ref.png test/text-rotate.svg12.rgb24.ref.png test/text-transform.svg11.argb32.ref.png test/text-transform.svg11.rgb24.ref.png test/text-transform.svg12.argb32.ref.png test/text-transform.svg12.rgb24.ref.png test/trap-clip.pdf.argb32.ref.png test/trap-clip.pdf.rgb24.ref.png test/trap-clip.ps2.argb32.ref.png test/trap-clip.ref.png test/trap-clip.rgb24.ref.png test/trap-clip.test-fallback.argb32.ref.png test/trap-clip.test-fallback.rgb24.ref.png test/trap-clip.test-paginated.argb32.ref.png test/trap-clip.xlib.ref.png test/trap-clip.xlib.rgb24.ref.png test/twin.svg11.argb32.ref.png test/twin.svg11.rgb24.ref.png test/twin.svg12.argb32.ref.png test/twin.svg12.rgb24.ref.png test/unbounded-operator.pdf.argb32.ref.png test/unbounded-operator.ps2.argb32.ref.png test/unbounded-operator.ps3.argb32.ref.png test/unbounded-operator.rgb24.ref.png test/unbounded-operator.test-fallback.rgb24.ref.png test/unbounded-operator.xlib.rgb24.ref.png test/user-font-proxy.pdf.argb32.ref.png test/user-font-proxy.pdf.rgb24.ref.png test/user-font-proxy.ref.png test/user-font-proxy.svg11.argb32.ref.png test/user-font-proxy.svg11.rgb24.ref.png test/user-font-proxy.svg12.argb32.ref.png test/user-font-proxy.svg12.rgb24.ref.png test/user-font-proxy.test-fallback.argb32.ref.png test/user-font-proxy.test-fallback.rgb24.ref.png test/user-font-proxy.xlib.ref.png test/user-font.ref.png test/user-font.svg11.argb32.ref.png test/user-font.svg11.rgb24.ref.png test/user-font.svg12.argb32.ref.png test/user-font.svg12.rgb24.ref.png test/user-font.test-fallback.argb32.ref.png test/user-font.test-fallback.rgb24.ref.png test/user-font.xlib.ref.png

M. Joonas Pihlaja joonas at kemper.freedesktop.org
Sat Dec 6 17:58:19 PST 2008


 src/Makefile.sources                                            |    3 
 src/cairo-analysis-surface.c                                    |    4 
 src/cairo-beos-surface.cpp                                      |    2 
 src/cairo-clip.c                                                |  140 
 src/cairo-directfb-surface.c                                    |    2 
 src/cairo-glitz-surface.c                                       |    2 
 src/cairo-image-surface.c                                       |  271 +
 src/cairo-meta-surface.c                                        |    2 
 src/cairo-os2-surface.c                                         |    2 
 src/cairo-paginated-surface.c                                   |    2 
 src/cairo-path-fixed.c                                          |  105 
 src/cairo-pdf-surface.c                                         |    2 
 src/cairo-ps-surface.c                                          |    2 
 src/cairo-quartz-image-surface.c                                |    2 
 src/cairo-quartz-surface.c                                      |    2 
 src/cairo-rectangle.c                                           |   21 
 src/cairo-script-surface.c                                      |    2 
 src/cairo-sdl-surface.c                                         |    2 
 src/cairo-spans-private.h                                       |  144 
 src/cairo-spans.c                                               |  395 +
 src/cairo-surface-fallback.c                                    |   86 
 src/cairo-surface.c                                             |   53 
 src/cairo-svg-surface.c                                         |    2 
 src/cairo-tor-scan-converter.c                                  | 2003 ++++++++++
 src/cairo-type3-glyph-surface.c                                 |    2 
 src/cairo-types-private.h                                       |   24 
 src/cairo-win32-printing-surface.c                              |    2 
 src/cairo-win32-surface.c                                       |    2 
 src/cairo-xcb-surface.c                                         |    2 
 src/cairo-xlib-surface.c                                        |    2 
 src/cairoint.h                                                  |   41 
 src/test-fallback-surface.c                                     |    2 
 src/test-meta-surface.c                                         |    2 
 src/test-paginated-surface.c                                    |    2 
 test/clip-fill-rule.pdf.argb32.ref.png                          |binary
 test/clip-fill-rule.rgb24.ref.png                               |binary
 test/clip-fill-rule.test-fallback.rgb24.ref.png                 |binary
 test/clip-fill-rule.test-paginated.rgb24.ref.png                |binary
 test/clip-fill-rule.xlib.rgb24.ref.png                          |binary
 test/clip-nesting.pdf.argb32.ref.png                            |binary
 test/clip-nesting.rgb24.ref.png                                 |binary
 test/clip-nesting.test-fallback.rgb24.ref.png                   |binary
 test/clip-nesting.test-paginated.rgb24.ref.png                  |binary
 test/clip-nesting.xlib.rgb24.ref.png                            |binary
 test/clip-operator.pdf.argb32.ref.png                           |binary
 test/clip-operator.pdf.rgb24.ref.png                            |binary
 test/clip-operator.ps2.rgb24.ref.png                            |binary
 test/clip-operator.ps3.argb32.ref.png                           |binary
 test/clip-operator.ps3.rgb24.ref.png                            |binary
 test/clip-operator.ref.png                                      |binary
 test/clip-operator.rgb24.ref.png                                |binary
 test/clip-operator.test-fallback.argb32.ref.png                 |binary
 test/clip-operator.test-fallback.rgb24.ref.png                  |binary
 test/clip-operator.test-paginated.argb32.ref.png                |binary
 test/clip-operator.xlib-fallback.rgb24.ref.png                  |binary
 test/clip-operator.xlib.ref.png                                 |binary
 test/clip-operator.xlib.rgb24.ref.png                           |binary
 test/clip-twice.pdf.argb32.ref.png                              |binary
 test/clip-twice.ref.png                                         |binary
 test/clip-twice.rgb24.ref.png                                   |binary
 test/clip-twice.test-fallback.argb32.ref.png                    |binary
 test/clip-twice.test-fallback.rgb24.ref.png                     |binary
 test/clip-twice.test-paginated.argb32.ref.png                   |binary
 test/clip-twice.test-paginated.rgb24.ref.png                    |binary
 test/clip-twice.xlib.ref.png                                    |binary
 test/clip-twice.xlib.rgb24.ref.png                              |binary
 test/clipped-group.pdf.argb32.ref.png                           |binary
 test/clipped-group.pdf.rgb24.ref.png                            |binary
 test/degenerate-arc.ref.png                                     |binary
 test/degenerate-arc.test-fallback.argb32.ref.png                |binary
 test/degenerate-arc.test-fallback.rgb24.ref.png                 |binary
 test/degenerate-arc.xlib.ref.png                                |binary
 test/device-offset-fractional.pdf.argb32.ref.png                |binary
 test/device-offset-fractional.pdf.rgb24.ref.png                 |binary
 test/fill-alpha-pattern.pdf.argb32.ref.png                      |binary
 test/fill-alpha-pattern.pdf.rgb24.ref.png                       |binary
 test/fill-alpha-pattern.ps3.argb32.ref.png                      |binary
 test/fill-alpha-pattern.ps3.rgb24.ref.png                       |binary
 test/fill-alpha-pattern.ref.png                                 |binary
 test/fill-alpha-pattern.test-fallback.argb32.ref.png            |binary
 test/fill-alpha-pattern.test-fallback.rgb24.ref.png             |binary
 test/fill-alpha-pattern.xlib.ref.png                            |binary
 test/fill-alpha.ref.png                                         |binary
 test/fill-alpha.test-fallback.argb32.ref.png                    |binary
 test/fill-alpha.test-fallback.rgb24.ref.png                     |binary
 test/fill-alpha.xlib.ref.png                                    |binary
 test/fill-degenerate-sort-order.ref.png                         |binary
 test/fill-degenerate-sort-order.rgb24.ref.png                   |binary
 test/fill-degenerate-sort-order.test-fallback.argb32.ref.png    |binary
 test/fill-degenerate-sort-order.test-fallback.rgb24.ref.png     |binary
 test/fill-degenerate-sort-order.xlib.ref.png                    |binary
 test/fill-degenerate-sort-order.xlib.rgb24.ref.png              |binary
 test/fill-missed-stop.pdf.argb32.ref.png                        |binary
 test/fill-rule.ref.png                                          |binary
 test/fill-rule.rgb24.ref.png                                    |binary
 test/fill-rule.test-fallback.argb32.ref.png                     |binary
 test/fill-rule.test-fallback.rgb24.ref.png                      |binary
 test/fill-rule.xlib.ref.png                                     |binary
 test/fill-rule.xlib.rgb24.ref.png                               |binary
 test/filter-nearest-offset.pdf.argb32.ref.png                   |binary
 test/filter-nearest-offset.pdf.rgb24.ref.png                    |binary
 test/filter-nearest-transformed.pdf.argb32.ref.png              |binary
 test/filter-nearest-transformed.pdf.rgb24.ref.png               |binary
 test/finer-grained-fallbacks.ps2.argb32.ref.png                 |binary
 test/finer-grained-fallbacks.ps2.rgb24.ref.png                  |binary
 test/finer-grained-fallbacks.ps3.argb32.ref.png                 |binary
 test/finer-grained-fallbacks.ps3.rgb24.ref.png                  |binary
 test/finer-grained-fallbacks.ref.png                            |binary
 test/finer-grained-fallbacks.rgb24.ref.png                      |binary
 test/finer-grained-fallbacks.test-fallback.argb32.ref.png       |binary
 test/finer-grained-fallbacks.test-fallback.rgb24.ref.png        |binary
 test/finer-grained-fallbacks.xlib.ref.png                       |binary
 test/finer-grained-fallbacks.xlib.rgb24.ref.png                 |binary
 test/font-matrix-translation.svg11.argb32.ref.png               |binary
 test/font-matrix-translation.svg11.rgb24.ref.png                |binary
 test/font-matrix-translation.svg12.argb32.ref.png               |binary
 test/font-matrix-translation.svg12.rgb24.ref.png                |binary
 test/ft-show-glyphs-table.svg11.argb32.ref.png                  |binary
 test/ft-show-glyphs-table.svg11.rgb24.ref.png                   |binary
 test/ft-show-glyphs-table.svg12.argb32.ref.png                  |binary
 test/ft-show-glyphs-table.svg12.rgb24.ref.png                   |binary
 test/ft-text-vertical-layout-type1.pdf.argb32.ref.png           |binary
 test/ft-text-vertical-layout-type1.pdf.rgb24.ref.png            |binary
 test/ft-text-vertical-layout-type1.ref.png                      |binary
 test/ft-text-vertical-layout-type1.svg11.argb32.ref.png         |binary
 test/ft-text-vertical-layout-type1.svg11.rgb24.ref.png          |binary
 test/ft-text-vertical-layout-type1.svg12.argb32.ref.png         |binary
 test/ft-text-vertical-layout-type1.svg12.rgb24.ref.png          |binary
 test/ft-text-vertical-layout-type1.test-fallback.argb32.ref.png |binary
 test/ft-text-vertical-layout-type1.test-fallback.rgb24.ref.png  |binary
 test/ft-text-vertical-layout-type1.xlib.ref.png                 |binary
 test/ft-text-vertical-layout-type3.pdf.argb32.ref.png           |binary
 test/ft-text-vertical-layout-type3.pdf.rgb24.ref.png            |binary
 test/ft-text-vertical-layout-type3.ref.png                      |binary
 test/ft-text-vertical-layout-type3.svg11.argb32.ref.png         |binary
 test/ft-text-vertical-layout-type3.svg11.rgb24.ref.png          |binary
 test/ft-text-vertical-layout-type3.svg12.argb32.ref.png         |binary
 test/ft-text-vertical-layout-type3.svg12.rgb24.ref.png          |binary
 test/ft-text-vertical-layout-type3.test-fallback.argb32.ref.png |binary
 test/ft-text-vertical-layout-type3.test-fallback.rgb24.ref.png  |binary
 test/ft-text-vertical-layout-type3.xlib.ref.png                 |binary
 test/huge-pattern.pdf.argb32.ref.png                            |binary
 test/linear-gradient.pdf.argb32.ref.png                         |binary
 test/linear-gradient.pdf.rgb24.ref.png                          |binary
 test/linear-gradient.ref.png                                    |binary
 test/linear-gradient.svg11.argb32.ref.png                       |binary
 test/linear-gradient.svg11.rgb24.ref.png                        |binary
 test/linear-gradient.svg12.argb32.ref.png                       |binary
 test/linear-gradient.svg12.rgb24.ref.png                        |binary
 test/linear-gradient.test-fallback.argb32.ref.png               |binary
 test/linear-gradient.test-fallback.rgb24.ref.png                |binary
 test/linear-gradient.xlib.ref.png                               |binary
 test/mask-alpha.ref.png                                         |binary
 test/mask-alpha.svg11.argb32.ref.png                            |binary
 test/mask-alpha.svg11.rgb24.ref.png                             |binary
 test/mask-alpha.svg12.argb32.ref.png                            |binary
 test/mask-alpha.svg12.rgb24.ref.png                             |binary
 test/mask-alpha.test-fallback.argb32.ref.png                    |binary
 test/mask-alpha.xlib.ref.png                                    |binary
 test/mask-alpha.xlib.rgb24.ref.png                              |binary
 test/mask.pdf.argb32.ref.png                                    |binary
 test/mask.pdf.rgb24.ref.png                                     |binary
 test/mask.ref.png                                               |binary
 test/mask.rgb24.ref.png                                         |binary
 test/mask.svg11.argb32.ref.png                                  |binary
 test/mask.svg11.rgb24.ref.png                                   |binary
 test/mask.svg12.argb32.ref.png                                  |binary
 test/mask.svg12.rgb24.ref.png                                   |binary
 test/mask.test-fallback.argb32.ref.png                          |binary
 test/mask.test-fallback.rgb24.ref.png                           |binary
 test/mask.xlib-fallback.rgb24.ref.png                           |binary
 test/mask.xlib.ref.png                                          |binary
 test/mask.xlib.rgb24.ref.png                                    |binary
 test/meta-surface-pattern.pdf.argb32.ref.png                    |binary
 test/meta-surface-pattern.pdf.rgb24.ref.png                     |binary
 test/meta-surface-pattern.svg11.argb32.ref.png                  |binary
 test/meta-surface-pattern.svg11.rgb24.ref.png                   |binary
 test/meta-surface-pattern.svg12.argb32.ref.png                  |binary
 test/meta-surface-pattern.svg12.rgb24.ref.png                   |binary
 test/operator-clear.pdf.argb32.ref.png                          |binary
 test/operator-clear.ps2.argb32.ref.png                          |binary
 test/operator-clear.ps3.argb32.ref.png                          |binary
 test/operator-source.pdf.argb32.ref.png                         |binary
 test/operator-source.pdf.rgb24.ref.png                          |binary
 test/operator-source.ref.png                                    |binary
 test/operator-source.rgb24.ref.png                              |binary
 test/operator-source.test-fallback.argb32.ref.png               |binary
 test/operator-source.test-fallback.rgb24.ref.png                |binary
 test/operator-source.xlib-fallback.rgb24.ref.png                |binary
 test/operator-source.xlib.ref.png                               |binary
 test/operator-source.xlib.rgb24.ref.png                         |binary
 test/over-above-source.ps2.argb32.ref.png                       |binary
 test/over-above-source.ps3.argb32.ref.png                       |binary
 test/over-above-source.ref.png                                  |binary
 test/over-above-source.rgb24.ref.png                            |binary
 test/over-above-source.test-fallback.argb32.ref.png             |binary
 test/over-above-source.test-fallback.rgb24.ref.png              |binary
 test/over-above-source.xlib.ref.png                             |binary
 test/over-above-source.xlib.rgb24.ref.png                       |binary
 test/over-around-source.pdf.argb32.ref.png                      |binary
 test/over-around-source.ps2.argb32.ref.png                      |binary
 test/over-around-source.ps3.argb32.ref.png                      |binary
 test/over-around-source.ref.png                                 |binary
 test/over-around-source.test-fallback.argb32.ref.png            |binary
 test/over-around-source.xlib.ref.png                            |binary
 test/over-around-source.xlib.rgb24.ref.png                      |binary
 test/over-below-source.pdf.argb32.ref.png                       |binary
 test/over-between-source.ps2.argb32.ref.png                     |binary
 test/over-between-source.ps3.argb32.ref.png                     |binary
 test/over-between-source.ref.png                                |binary
 test/over-between-source.test-fallback.argb32.ref.png           |binary
 test/over-between-source.xlib.ref.png                           |binary
 test/over-between-source.xlib.rgb24.ref.png                     |binary
 test/push-group.pdf.argb32.ref.png                              |binary
 test/push-group.pdf.rgb24.ref.png                               |binary
 test/push-group.ref.png                                         |binary
 test/push-group.rgb24.ref.png                                   |binary
 test/push-group.svg11.argb32.ref.png                            |binary
 test/push-group.svg12.argb32.ref.png                            |binary
 test/push-group.test-fallback.argb32.ref.png                    |binary
 test/push-group.test-fallback.rgb24.ref.png                     |binary
 test/push-group.xlib-fallback.rgb24.ref.png                     |binary
 test/push-group.xlib.ref.png                                    |binary
 test/push-group.xlib.rgb24.ref.png                              |binary
 test/radial-gradient.pdf.argb32.ref.png                         |binary
 test/radial-gradient.pdf.rgb24.ref.png                          |binary
 test/random-intersections.ref.png                               |binary
 test/random-intersections.test-fallback.argb32.ref.png          |binary
 test/random-intersections.test-fallback.rgb24.ref.png           |binary
 test/random-intersections.xlib.ref.png                          |binary
 test/rotate-image-surface-paint.pdf.argb32.ref.png              |binary
 test/rotate-image-surface-paint.pdf.rgb24.ref.png               |binary
 test/smask-fill.pdf.argb32.ref.png                              |binary
 test/smask-fill.pdf.rgb24.ref.png                               |binary
 test/smask-fill.ref.png                                         |binary
 test/smask-fill.svg11.argb32.ref.png                            |binary
 test/smask-fill.svg11.rgb24.ref.png                             |binary
 test/smask-fill.svg12.argb32.ref.png                            |binary
 test/smask-fill.svg12.rgb24.ref.png                             |binary
 test/smask-fill.test-fallback.argb32.ref.png                    |binary
 test/smask-fill.test-fallback.rgb24.ref.png                     |binary
 test/smask-fill.xlib-fallback.ref.png                           |binary
 test/smask-fill.xlib.ref.png                                    |binary
 test/smask-image-mask.pdf.argb32.ref.png                        |binary
 test/smask-image-mask.pdf.rgb24.ref.png                         |binary
 test/smask-mask.pdf.argb32.ref.png                              |binary
 test/smask-mask.pdf.rgb24.ref.png                               |binary
 test/smask-paint.pdf.argb32.ref.png                             |binary
 test/smask-paint.pdf.rgb24.ref.png                              |binary
 test/smask-stroke.pdf.argb32.ref.png                            |binary
 test/smask-stroke.pdf.rgb24.ref.png                             |binary
 test/smask-text.svg11.argb32.ref.png                            |binary
 test/smask-text.svg11.rgb24.ref.png                             |binary
 test/smask-text.svg12.argb32.ref.png                            |binary
 test/smask-text.svg12.rgb24.ref.png                             |binary
 test/smask.pdf.argb32.ref.png                                   |binary
 test/smask.pdf.rgb24.ref.png                                    |binary
 test/surface-pattern-scale-down.pdf.argb32.ref.png              |binary
 test/surface-pattern-scale-down.pdf.rgb24.ref.png               |binary
 test/surface-pattern-scale-up.pdf.argb32.ref.png                |binary
 test/surface-pattern-scale-up.pdf.rgb24.ref.png                 |binary
 test/surface-pattern.pdf.argb32.ref.png                         |binary
 test/surface-pattern.pdf.rgb24.ref.png                          |binary
 test/text-pattern.pdf.argb32.ref.png                            |binary
 test/text-pattern.svg11.argb32.ref.png                          |binary
 test/text-pattern.svg12.argb32.ref.png                          |binary
 test/text-rotate.svg11.argb32.ref.png                           |binary
 test/text-rotate.svg11.rgb24.ref.png                            |binary
 test/text-rotate.svg12.argb32.ref.png                           |binary
 test/text-rotate.svg12.rgb24.ref.png                            |binary
 test/text-transform.svg11.argb32.ref.png                        |binary
 test/text-transform.svg11.rgb24.ref.png                         |binary
 test/text-transform.svg12.argb32.ref.png                        |binary
 test/text-transform.svg12.rgb24.ref.png                         |binary
 test/trap-clip.pdf.argb32.ref.png                               |binary
 test/trap-clip.pdf.rgb24.ref.png                                |binary
 test/trap-clip.ps2.argb32.ref.png                               |binary
 test/trap-clip.ref.png                                          |binary
 test/trap-clip.rgb24.ref.png                                    |binary
 test/trap-clip.test-fallback.argb32.ref.png                     |binary
 test/trap-clip.test-fallback.rgb24.ref.png                      |binary
 test/trap-clip.test-paginated.argb32.ref.png                    |binary
 test/trap-clip.xlib.ref.png                                     |binary
 test/trap-clip.xlib.rgb24.ref.png                               |binary
 test/twin.svg11.argb32.ref.png                                  |binary
 test/twin.svg11.rgb24.ref.png                                   |binary
 test/twin.svg12.argb32.ref.png                                  |binary
 test/twin.svg12.rgb24.ref.png                                   |binary
 test/unbounded-operator.pdf.argb32.ref.png                      |binary
 test/unbounded-operator.ps2.argb32.ref.png                      |binary
 test/unbounded-operator.ps3.argb32.ref.png                      |binary
 test/unbounded-operator.rgb24.ref.png                           |binary
 test/unbounded-operator.test-fallback.rgb24.ref.png             |binary
 test/unbounded-operator.xlib.rgb24.ref.png                      |binary
 test/user-font-proxy.pdf.argb32.ref.png                         |binary
 test/user-font-proxy.pdf.rgb24.ref.png                          |binary
 test/user-font-proxy.ref.png                                    |binary
 test/user-font-proxy.svg11.argb32.ref.png                       |binary
 test/user-font-proxy.svg11.rgb24.ref.png                        |binary
 test/user-font-proxy.svg12.argb32.ref.png                       |binary
 test/user-font-proxy.svg12.rgb24.ref.png                        |binary
 test/user-font-proxy.test-fallback.argb32.ref.png               |binary
 test/user-font-proxy.test-fallback.rgb24.ref.png                |binary
 test/user-font-proxy.xlib.ref.png                               |binary
 test/user-font.ref.png                                          |binary
 test/user-font.svg11.argb32.ref.png                             |binary
 test/user-font.svg11.rgb24.ref.png                              |binary
 test/user-font.svg12.argb32.ref.png                             |binary
 test/user-font.svg12.rgb24.ref.png                              |binary
 test/user-font.test-fallback.argb32.ref.png                     |binary
 test/user-font.test-fallback.rgb24.ref.png                      |binary
 test/user-font.xlib.ref.png                                     |binary
 312 files changed, 3293 insertions(+), 39 deletions(-)

New commits:
commit 5e06085b483dcaaa7b1b29b13cd2813c7e51e02a
Author: M Joonas Pihlaja <jpihlaja at cc.helsinki.fi>
Date:   Fri Aug 1 23:28:15 2008 +0300

    [cairo-spans] Render clip mask surfaces with spans if we can.
    
    Generating surface masks for clipping can also benefit from span
    rendering sometimes.

diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 4303b60..cd423a4 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -534,6 +534,133 @@ _cairo_clip_intersect_mask (cairo_clip_t      *clip,
     return status;
 }
 
+static cairo_status_t
+_cairo_clip_intersect_mask_using_spans (cairo_clip_t       *clip,
+					cairo_path_fixed_t *path,
+					cairo_fill_rule_t   fill_rule,
+					double		    tolerance,
+					cairo_antialias_t   antialias,
+					cairo_surface_t    *target)
+{
+    cairo_span_renderer_t *renderer = NULL;
+    cairo_pattern_union_t pattern;
+    cairo_rectangle_int_t surface_rect;
+    cairo_surface_t *surface = NULL;
+    cairo_status_t status;
+    cairo_operator_t op;
+    cairo_composite_rectangles_t rects;
+
+    if (clip->all_clipped)
+	return CAIRO_STATUS_SUCCESS;
+
+    _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
+			       CAIRO_CONTENT_COLOR);
+
+    /* If we have a clip surface we're going to use IN to combine our
+     * new clip with the old clip.  The ADD is done to a transparent
+     * surface, as that's a fast way of doing it currently.  We should
+     * really be using SOURCE instead, but _cairo_surface_composite()
+     * checks that it's not called with SOURCE or DEST. */
+    op = clip->surface ? CAIRO_OPERATOR_IN : CAIRO_OPERATOR_ADD;
+
+    /* Test if the target can composite spans.  We're going to assume
+     * this is a good indicator of whether a similar surface is going
+     * to be able to composite spans too. */
+    if ( !_cairo_surface_check_span_renderer (op,
+					      &pattern.base,
+					      target,
+					      antialias,
+					      NULL))
+    {
+	status = CAIRO_INT_STATUS_UNSUPPORTED;
+	goto BAIL;
+    }
+
+    /* We'll create a new surface the size of the intersection of the
+     * old mask surface and the extents of the new clip path. */
+    {
+	cairo_rectangle_int_t target_rect;
+
+	_cairo_path_fixed_approximate_extents (path, &surface_rect);
+
+	if (clip->surface != NULL &&
+	    !_cairo_rectangle_intersect (&surface_rect, &clip->surface_rect))
+	    goto SUCCESS;
+
+	status = _cairo_surface_get_extents (target, &target_rect);
+	if (status != CAIRO_STATUS_SUCCESS &&
+	    !_cairo_rectangle_intersect (&surface_rect, &target_rect))
+	    goto SUCCESS;
+    }
+
+    /* Make the new mask surface and optionally initialise it from the
+     * previous clip if we have one. */
+    surface = _cairo_surface_create_similar_solid (target,
+						   CAIRO_CONTENT_ALPHA,
+						   surface_rect.width,
+						   surface_rect.height,
+						   CAIRO_COLOR_TRANSPARENT);
+    if (surface->status) {
+	_cairo_pattern_fini (&pattern.base);
+	return surface->status;
+    }
+
+    if (clip->surface) {
+	cairo_surface_pattern_t old_clip;
+	_cairo_pattern_init_for_surface (&old_clip, clip->surface);
+	status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
+					   &old_clip.base,
+					   NULL,
+					   surface,
+					   surface_rect.x - clip->surface_rect.x,
+					   surface_rect.y - clip->surface_rect.y,
+					   0, 0,
+					   0, 0,
+					   surface_rect.width,
+					   surface_rect.height);
+	_cairo_pattern_fini (&old_clip.base);
+	if (status)
+	    goto BAIL;
+    }
+
+    _cairo_composite_rectangles_init (&rects,
+				      surface_rect.x,
+				      surface_rect.y,
+				      surface_rect.width,
+				      surface_rect.height);
+    rects.dst.x = 0;
+    rects.dst.y = 0;
+
+    /* Render the new clipping path into the new mask surface. We've
+     * chosen op to either combine the new clip path with the existing
+     * clip mask (if there is one) or just render it. */
+    status =_cairo_path_fixed_fill_using_spans (op, &pattern.base,
+						path, surface,
+						fill_rule, tolerance,
+						antialias, &rects);
+    if (status)
+	goto BAIL;
+
+ SUCCESS:
+    if (clip->surface != NULL)
+	cairo_surface_destroy (clip->surface);
+    clip->surface = surface;
+    clip->surface_rect = surface_rect;
+    clip->serial = _cairo_surface_allocate_clip_serial (target);
+    surface = NULL;
+
+    if (surface_rect.width == 0 || surface_rect.height == 0)
+	_cairo_clip_set_all_clipped (clip, target);
+
+ BAIL:
+    if (renderer)
+	renderer->destroy(renderer);
+    if (surface)
+	cairo_surface_destroy (surface);
+    _cairo_pattern_fini (&pattern.base);
+    return status;
+}
+
 cairo_status_t
 _cairo_clip_clip (cairo_clip_t       *clip,
 		  cairo_path_fixed_t *path,
@@ -545,6 +672,7 @@ _cairo_clip_clip (cairo_clip_t       *clip,
     cairo_status_t status;
     cairo_rectangle_int_t rectangle;
     cairo_traps_t traps;
+    cairo_box_t ignored_box;
 
     if (clip->all_clipped)
 	return CAIRO_STATUS_SUCCESS;
@@ -564,6 +692,18 @@ _cairo_clip_clip (cairo_clip_t       *clip,
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	return status;
 
+    /* TODO: allow ANTIALIAS_NONE when we have a mono scan converter
+     * again. */
+    if (antialias != CAIRO_ANTIALIAS_NONE &&
+	!_cairo_path_fixed_is_box (path, &ignored_box) &&
+	!_cairo_path_fixed_is_region (path))
+    {
+	status = _cairo_clip_intersect_mask_using_spans (
+	    clip, path, fill_rule, tolerance, antialias, target);
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    return status;
+    }
+
     _cairo_traps_init (&traps);
 
     /* Limit the traps to the target surface
diff --git a/test/clip-fill-rule.pdf.argb32.ref.png b/test/clip-fill-rule.pdf.argb32.ref.png
new file mode 100644
index 0000000..0d9938e
Binary files /dev/null and b/test/clip-fill-rule.pdf.argb32.ref.png differ
diff --git a/test/clip-fill-rule.rgb24.ref.png b/test/clip-fill-rule.rgb24.ref.png
index a969e36..050bd66 100644
Binary files a/test/clip-fill-rule.rgb24.ref.png and b/test/clip-fill-rule.rgb24.ref.png differ
diff --git a/test/clip-fill-rule.test-paginated.rgb24.ref.png b/test/clip-fill-rule.test-paginated.rgb24.ref.png
new file mode 100644
index 0000000..d21472d
Binary files /dev/null and b/test/clip-fill-rule.test-paginated.rgb24.ref.png differ
diff --git a/test/clip-fill-rule.xlib.rgb24.ref.png b/test/clip-fill-rule.xlib.rgb24.ref.png
new file mode 100644
index 0000000..a969e36
Binary files /dev/null and b/test/clip-fill-rule.xlib.rgb24.ref.png differ
diff --git a/test/clip-nesting.pdf.argb32.ref.png b/test/clip-nesting.pdf.argb32.ref.png
new file mode 100644
index 0000000..78ae6e0
Binary files /dev/null and b/test/clip-nesting.pdf.argb32.ref.png differ
diff --git a/test/clip-nesting.rgb24.ref.png b/test/clip-nesting.rgb24.ref.png
index e2488f3..a014763 100644
Binary files a/test/clip-nesting.rgb24.ref.png and b/test/clip-nesting.rgb24.ref.png differ
diff --git a/test/clip-nesting.test-fallback.rgb24.ref.png b/test/clip-nesting.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..d087ab6
Binary files /dev/null and b/test/clip-nesting.test-fallback.rgb24.ref.png differ
diff --git a/test/clip-nesting.test-paginated.rgb24.ref.png b/test/clip-nesting.test-paginated.rgb24.ref.png
new file mode 100644
index 0000000..d087ab6
Binary files /dev/null and b/test/clip-nesting.test-paginated.rgb24.ref.png differ
diff --git a/test/clip-nesting.xlib.rgb24.ref.png b/test/clip-nesting.xlib.rgb24.ref.png
new file mode 100644
index 0000000..e2488f3
Binary files /dev/null and b/test/clip-nesting.xlib.rgb24.ref.png differ
diff --git a/test/clip-operator.pdf.argb32.ref.png b/test/clip-operator.pdf.argb32.ref.png
index 4bf79c4..e2fdc8d 100644
Binary files a/test/clip-operator.pdf.argb32.ref.png and b/test/clip-operator.pdf.argb32.ref.png differ
diff --git a/test/clip-operator.ps3.argb32.ref.png b/test/clip-operator.ps3.argb32.ref.png
index 638831c..cd207d9 100644
Binary files a/test/clip-operator.ps3.argb32.ref.png and b/test/clip-operator.ps3.argb32.ref.png differ
diff --git a/test/clip-operator.ref.png b/test/clip-operator.ref.png
index 22e080a..3a685f5 100644
Binary files a/test/clip-operator.ref.png and b/test/clip-operator.ref.png differ
diff --git a/test/clip-operator.test-paginated.argb32.ref.png b/test/clip-operator.test-paginated.argb32.ref.png
new file mode 100644
index 0000000..22e080a
Binary files /dev/null and b/test/clip-operator.test-paginated.argb32.ref.png differ
diff --git a/test/clip-twice.pdf.argb32.ref.png b/test/clip-twice.pdf.argb32.ref.png
index 589dfc9..2a7541f 100644
Binary files a/test/clip-twice.pdf.argb32.ref.png and b/test/clip-twice.pdf.argb32.ref.png differ
diff --git a/test/clip-twice.ref.png b/test/clip-twice.ref.png
index 8dc86f3..4aafc9a 100644
Binary files a/test/clip-twice.ref.png and b/test/clip-twice.ref.png differ
diff --git a/test/clip-twice.rgb24.ref.png b/test/clip-twice.rgb24.ref.png
index 3f1c013..25c44ef 100644
Binary files a/test/clip-twice.rgb24.ref.png and b/test/clip-twice.rgb24.ref.png differ
diff --git a/test/clip-twice.test-fallback.argb32.ref.png b/test/clip-twice.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..ba62180
Binary files /dev/null and b/test/clip-twice.test-fallback.argb32.ref.png differ
diff --git a/test/clip-twice.test-fallback.rgb24.ref.png b/test/clip-twice.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..9cbdc4d
Binary files /dev/null and b/test/clip-twice.test-fallback.rgb24.ref.png differ
diff --git a/test/clip-twice.test-paginated.argb32.ref.png b/test/clip-twice.test-paginated.argb32.ref.png
new file mode 100644
index 0000000..ffd59aa
Binary files /dev/null and b/test/clip-twice.test-paginated.argb32.ref.png differ
diff --git a/test/clip-twice.test-paginated.rgb24.ref.png b/test/clip-twice.test-paginated.rgb24.ref.png
new file mode 100644
index 0000000..e3d0ae4
Binary files /dev/null and b/test/clip-twice.test-paginated.rgb24.ref.png differ
diff --git a/test/clip-twice.xlib.ref.png b/test/clip-twice.xlib.ref.png
new file mode 100644
index 0000000..8dc86f3
Binary files /dev/null and b/test/clip-twice.xlib.ref.png differ
diff --git a/test/clip-twice.xlib.rgb24.ref.png b/test/clip-twice.xlib.rgb24.ref.png
new file mode 100644
index 0000000..3f1c013
Binary files /dev/null and b/test/clip-twice.xlib.rgb24.ref.png differ
diff --git a/test/device-offset-fractional.pdf.argb32.ref.png b/test/device-offset-fractional.pdf.argb32.ref.png
new file mode 100644
index 0000000..c076932
Binary files /dev/null and b/test/device-offset-fractional.pdf.argb32.ref.png differ
diff --git a/test/device-offset-fractional.pdf.rgb24.ref.png b/test/device-offset-fractional.pdf.rgb24.ref.png
new file mode 100644
index 0000000..c076932
Binary files /dev/null and b/test/device-offset-fractional.pdf.rgb24.ref.png differ
diff --git a/test/filter-nearest-offset.pdf.argb32.ref.png b/test/filter-nearest-offset.pdf.argb32.ref.png
new file mode 100644
index 0000000..3475cb6
Binary files /dev/null and b/test/filter-nearest-offset.pdf.argb32.ref.png differ
diff --git a/test/filter-nearest-offset.pdf.rgb24.ref.png b/test/filter-nearest-offset.pdf.rgb24.ref.png
new file mode 100644
index 0000000..3475cb6
Binary files /dev/null and b/test/filter-nearest-offset.pdf.rgb24.ref.png differ
diff --git a/test/filter-nearest-transformed.pdf.argb32.ref.png b/test/filter-nearest-transformed.pdf.argb32.ref.png
new file mode 100644
index 0000000..4016959
Binary files /dev/null and b/test/filter-nearest-transformed.pdf.argb32.ref.png differ
diff --git a/test/filter-nearest-transformed.pdf.rgb24.ref.png b/test/filter-nearest-transformed.pdf.rgb24.ref.png
new file mode 100644
index 0000000..4016959
Binary files /dev/null and b/test/filter-nearest-transformed.pdf.rgb24.ref.png differ
diff --git a/test/linear-gradient.pdf.argb32.ref.png b/test/linear-gradient.pdf.argb32.ref.png
index bddb681..f820c37 100644
Binary files a/test/linear-gradient.pdf.argb32.ref.png and b/test/linear-gradient.pdf.argb32.ref.png differ
diff --git a/test/linear-gradient.pdf.rgb24.ref.png b/test/linear-gradient.pdf.rgb24.ref.png
index bddb681..f820c37 100644
Binary files a/test/linear-gradient.pdf.rgb24.ref.png and b/test/linear-gradient.pdf.rgb24.ref.png differ
diff --git a/test/mask.pdf.argb32.ref.png b/test/mask.pdf.argb32.ref.png
index d1cc8ff..8bd8f14 100644
Binary files a/test/mask.pdf.argb32.ref.png and b/test/mask.pdf.argb32.ref.png differ
diff --git a/test/mask.ref.png b/test/mask.ref.png
index f5d30c5..2c2fa11 100644
Binary files a/test/mask.ref.png and b/test/mask.ref.png differ
diff --git a/test/mask.svg11.argb32.ref.png b/test/mask.svg11.argb32.ref.png
index e48e47b..3ce4d53 100644
Binary files a/test/mask.svg11.argb32.ref.png and b/test/mask.svg11.argb32.ref.png differ
diff --git a/test/mask.svg12.argb32.ref.png b/test/mask.svg12.argb32.ref.png
index e48e47b..3ce4d53 100644
Binary files a/test/mask.svg12.argb32.ref.png and b/test/mask.svg12.argb32.ref.png differ
diff --git a/test/meta-surface-pattern.pdf.argb32.ref.png b/test/meta-surface-pattern.pdf.argb32.ref.png
index a842b6f..2ee9b7d 100644
Binary files a/test/meta-surface-pattern.pdf.argb32.ref.png and b/test/meta-surface-pattern.pdf.argb32.ref.png differ
diff --git a/test/meta-surface-pattern.svg11.argb32.ref.png b/test/meta-surface-pattern.svg11.argb32.ref.png
index 3a6836d..9969574 100644
Binary files a/test/meta-surface-pattern.svg11.argb32.ref.png and b/test/meta-surface-pattern.svg11.argb32.ref.png differ
diff --git a/test/meta-surface-pattern.svg12.argb32.ref.png b/test/meta-surface-pattern.svg12.argb32.ref.png
index 3a6836d..9969574 100644
Binary files a/test/meta-surface-pattern.svg12.argb32.ref.png and b/test/meta-surface-pattern.svg12.argb32.ref.png differ
diff --git a/test/rotate-image-surface-paint.pdf.argb32.ref.png b/test/rotate-image-surface-paint.pdf.argb32.ref.png
index c12ae8f..93fab52 100644
Binary files a/test/rotate-image-surface-paint.pdf.argb32.ref.png and b/test/rotate-image-surface-paint.pdf.argb32.ref.png differ
diff --git a/test/rotate-image-surface-paint.pdf.rgb24.ref.png b/test/rotate-image-surface-paint.pdf.rgb24.ref.png
index 5cd7bf6..93fab52 100644
Binary files a/test/rotate-image-surface-paint.pdf.rgb24.ref.png and b/test/rotate-image-surface-paint.pdf.rgb24.ref.png differ
diff --git a/test/surface-pattern-scale-down.pdf.argb32.ref.png b/test/surface-pattern-scale-down.pdf.argb32.ref.png
index c29d804..dc4b3a3 100644
Binary files a/test/surface-pattern-scale-down.pdf.argb32.ref.png and b/test/surface-pattern-scale-down.pdf.argb32.ref.png differ
diff --git a/test/surface-pattern-scale-down.pdf.rgb24.ref.png b/test/surface-pattern-scale-down.pdf.rgb24.ref.png
index c29d804..dc4b3a3 100644
Binary files a/test/surface-pattern-scale-down.pdf.rgb24.ref.png and b/test/surface-pattern-scale-down.pdf.rgb24.ref.png differ
diff --git a/test/surface-pattern-scale-up.pdf.argb32.ref.png b/test/surface-pattern-scale-up.pdf.argb32.ref.png
index 6f3a53c..c0a2896 100644
Binary files a/test/surface-pattern-scale-up.pdf.argb32.ref.png and b/test/surface-pattern-scale-up.pdf.argb32.ref.png differ
diff --git a/test/surface-pattern-scale-up.pdf.rgb24.ref.png b/test/surface-pattern-scale-up.pdf.rgb24.ref.png
index 6f3a53c..c0a2896 100644
Binary files a/test/surface-pattern-scale-up.pdf.rgb24.ref.png and b/test/surface-pattern-scale-up.pdf.rgb24.ref.png differ
diff --git a/test/surface-pattern.pdf.argb32.ref.png b/test/surface-pattern.pdf.argb32.ref.png
new file mode 100644
index 0000000..70a4476
Binary files /dev/null and b/test/surface-pattern.pdf.argb32.ref.png differ
diff --git a/test/surface-pattern.pdf.rgb24.ref.png b/test/surface-pattern.pdf.rgb24.ref.png
new file mode 100644
index 0000000..70a4476
Binary files /dev/null and b/test/surface-pattern.pdf.rgb24.ref.png differ
diff --git a/test/trap-clip.pdf.rgb24.ref.png b/test/trap-clip.pdf.rgb24.ref.png
index 90b476b..0616367 100644
Binary files a/test/trap-clip.pdf.rgb24.ref.png and b/test/trap-clip.pdf.rgb24.ref.png differ
diff --git a/test/trap-clip.ref.png b/test/trap-clip.ref.png
index dee57e7..e8c26d3 100644
Binary files a/test/trap-clip.ref.png and b/test/trap-clip.ref.png differ
diff --git a/test/trap-clip.test-paginated.argb32.ref.png b/test/trap-clip.test-paginated.argb32.ref.png
new file mode 100644
index 0000000..dee57e7
Binary files /dev/null and b/test/trap-clip.test-paginated.argb32.ref.png differ
commit 18634c37026a2d6147443cb6d991576f62b07e6d
Author: M Joonas Pihlaja <jpihlaja at cc.helsinki.fi>
Date:   Thu Jul 24 20:47:14 2008 +0300

    [cairo-spans] Hook up filling paths with spans to cairo-surface-fallback.c.
    
    This speeds up the mask generation step in cairo_fill() for the image
    surface by up to 10x in especially favourable cases.
    
    image-rgba                              twin-800 7757.80 0.20% -> 749.41 0.29%: 10.36x speedup
    image-rgba spiral-diag-pixalign-nonzero-fill-512   15.16 0.44% ->   3.45 8.80%:  5.54x speedup
    
    More typical simple non-rectilinear geometries are sped up by 30-50%.
    This patch does not affect any stroking operations or any fill
    operations of pixel aligned rectilinear geometries; those are still
    rendered using trapezoids.

diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index 8e6e268..88975e9 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -670,6 +670,53 @@ out:
     return status;
 }
 
+typedef struct {
+    cairo_path_fixed_t		*path;
+    cairo_fill_rule_t		 fill_rule;
+    double			 tolerance;
+    cairo_antialias_t		 antialias;
+} cairo_composite_spans_fill_info_t;
+
+static cairo_status_t
+_composite_spans_fill_func (void                          *closure,
+			    cairo_operator_t               op,
+			    const cairo_pattern_t         *src,
+			    cairo_surface_t               *dst,
+			    int                            dst_x,
+			    int                            dst_y,
+			    const cairo_rectangle_int_t   *extents)
+{
+    cairo_composite_rectangles_t rects;
+    cairo_composite_spans_fill_info_t *info = closure;
+    cairo_pattern_union_t pattern;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+    _cairo_composite_rectangles_init (
+	&rects, extents->x, extents->y,
+	extents->width, extents->height);
+
+    /* The incoming dst_x/y are where we're pretending the origin of
+     * the dst surface is -- *not* the offset of a rectangle where
+     * we'd like to place the result. */
+    rects.dst.x -= dst_x;
+    rects.dst.y -= dst_y;
+
+    /* We're called without a source pattern from
+     * _create_composite_mask_pattern(). */
+    _cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
+			       CAIRO_CONTENT_COLOR);
+    if (src == NULL)
+	src = &pattern.base;
+
+    status = _cairo_path_fixed_fill_using_spans (
+	op, src, info->path, dst,
+	info->fill_rule, info->tolerance, info->antialias,
+	&rects);
+
+    _cairo_pattern_fini (&pattern.base);
+    return status;
+}
+
 cairo_status_t
 _cairo_surface_fallback_paint (cairo_surface_t		*surface,
 			       cairo_operator_t		 op,
@@ -886,8 +933,45 @@ _cairo_surface_fallback_fill (cairo_surface_t		*surface,
     if (extents.width == 0 || extents.height == 0)
 	return CAIRO_STATUS_SUCCESS;
 
-    _cairo_box_from_rectangle (&box, &extents);
+    /* Ask if the surface would like to render this combination of
+     * op/source/dst/antialias with spans or not, but don't actually
+     * make a renderer yet.  We'll try to hit the region optimisations
+     * in _clip_and_composite_trapezoids() if it looks like the path
+     * is a region. */
+    /* TODO: Until we have a mono scan converter we won't even try
+     * to use spans for CAIRO_ANTIALIAS_NONE. */
+    /* TODO: The region filling code should be lifted from
+     * _clip_and_composite_trapezoids() and given first priority
+     * explicitly before deciding between spans and trapezoids. */
+    if (antialias != CAIRO_ANTIALIAS_NONE &&
+	!_cairo_path_fixed_is_box (path, &box) &&
+	!_cairo_path_fixed_is_region (path) &&
+	_cairo_surface_check_span_renderer (
+	    op, source, surface, antialias, NULL))
+    {
+	cairo_composite_spans_fill_info_t info;
+	info.path = path;
+	info.fill_rule = fill_rule;
+	info.tolerance = tolerance;
+	info.antialias = antialias;
+
+	if (_cairo_operator_bounded_by_mask (op)) {
+	    cairo_rectangle_int_t path_extents;
+	    _cairo_path_fixed_approximate_extents (path, &path_extents);
+	    if (! _cairo_rectangle_intersect (&extents, &path_extents))
+		return CAIRO_STATUS_SUCCESS;
+	}
 
+	return _clip_and_composite (
+	    surface->clip, op, source,
+	    _composite_spans_fill_func,
+	    &info,
+	    surface,
+	    &extents);
+    }
+
+    /* Fall back to trapezoid fills. */
+    _cairo_box_from_rectangle (&box, &extents);
     _cairo_traps_init (&traps);
     _cairo_traps_limit (&traps, &box);
 
diff --git a/test/clip-fill-rule.test-fallback.rgb24.ref.png b/test/clip-fill-rule.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..d21472d
Binary files /dev/null and b/test/clip-fill-rule.test-fallback.rgb24.ref.png differ
diff --git a/test/clip-operator.pdf.argb32.ref.png b/test/clip-operator.pdf.argb32.ref.png
index b3ee143..4bf79c4 100644
Binary files a/test/clip-operator.pdf.argb32.ref.png and b/test/clip-operator.pdf.argb32.ref.png differ
diff --git a/test/clip-operator.pdf.rgb24.ref.png b/test/clip-operator.pdf.rgb24.ref.png
index b420f38..6590dd8 100644
Binary files a/test/clip-operator.pdf.rgb24.ref.png and b/test/clip-operator.pdf.rgb24.ref.png differ
diff --git a/test/clip-operator.ps2.rgb24.ref.png b/test/clip-operator.ps2.rgb24.ref.png
index 6ed9fc4..5245299 100644
Binary files a/test/clip-operator.ps2.rgb24.ref.png and b/test/clip-operator.ps2.rgb24.ref.png differ
diff --git a/test/clip-operator.ps3.argb32.ref.png b/test/clip-operator.ps3.argb32.ref.png
new file mode 100644
index 0000000..638831c
Binary files /dev/null and b/test/clip-operator.ps3.argb32.ref.png differ
diff --git a/test/clip-operator.ps3.rgb24.ref.png b/test/clip-operator.ps3.rgb24.ref.png
index 6ed9fc4..5245299 100644
Binary files a/test/clip-operator.ps3.rgb24.ref.png and b/test/clip-operator.ps3.rgb24.ref.png differ
diff --git a/test/clip-operator.ref.png b/test/clip-operator.ref.png
index 4ea1842..22e080a 100644
Binary files a/test/clip-operator.ref.png and b/test/clip-operator.ref.png differ
diff --git a/test/clip-operator.rgb24.ref.png b/test/clip-operator.rgb24.ref.png
index 7ab964c..0a4d4c0 100644
Binary files a/test/clip-operator.rgb24.ref.png and b/test/clip-operator.rgb24.ref.png differ
diff --git a/test/clip-operator.test-fallback.argb32.ref.png b/test/clip-operator.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..f53e492
Binary files /dev/null and b/test/clip-operator.test-fallback.argb32.ref.png differ
diff --git a/test/clip-operator.test-fallback.rgb24.ref.png b/test/clip-operator.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..7579ae6
Binary files /dev/null and b/test/clip-operator.test-fallback.rgb24.ref.png differ
diff --git a/test/clip-operator.xlib-fallback.rgb24.ref.png b/test/clip-operator.xlib-fallback.rgb24.ref.png
new file mode 100644
index 0000000..4a05f7b
Binary files /dev/null and b/test/clip-operator.xlib-fallback.rgb24.ref.png differ
diff --git a/test/clip-operator.xlib.ref.png b/test/clip-operator.xlib.ref.png
new file mode 100644
index 0000000..4ea1842
Binary files /dev/null and b/test/clip-operator.xlib.ref.png differ
diff --git a/test/clip-operator.xlib.rgb24.ref.png b/test/clip-operator.xlib.rgb24.ref.png
new file mode 100644
index 0000000..7ab964c
Binary files /dev/null and b/test/clip-operator.xlib.rgb24.ref.png differ
diff --git a/test/clip-twice.pdf.argb32.ref.png b/test/clip-twice.pdf.argb32.ref.png
new file mode 100644
index 0000000..589dfc9
Binary files /dev/null and b/test/clip-twice.pdf.argb32.ref.png differ
diff --git a/test/clipped-group.pdf.argb32.ref.png b/test/clipped-group.pdf.argb32.ref.png
new file mode 100644
index 0000000..b9975e1
Binary files /dev/null and b/test/clipped-group.pdf.argb32.ref.png differ
diff --git a/test/clipped-group.pdf.rgb24.ref.png b/test/clipped-group.pdf.rgb24.ref.png
new file mode 100644
index 0000000..b9975e1
Binary files /dev/null and b/test/clipped-group.pdf.rgb24.ref.png differ
diff --git a/test/degenerate-arc.ref.png b/test/degenerate-arc.ref.png
index 5112d7f..1d131b2 100644
Binary files a/test/degenerate-arc.ref.png and b/test/degenerate-arc.ref.png differ
diff --git a/test/degenerate-arc.test-fallback.argb32.ref.png b/test/degenerate-arc.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..73d41af
Binary files /dev/null and b/test/degenerate-arc.test-fallback.argb32.ref.png differ
diff --git a/test/degenerate-arc.test-fallback.rgb24.ref.png b/test/degenerate-arc.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..73d41af
Binary files /dev/null and b/test/degenerate-arc.test-fallback.rgb24.ref.png differ
diff --git a/test/degenerate-arc.xlib.ref.png b/test/degenerate-arc.xlib.ref.png
new file mode 100644
index 0000000..5112d7f
Binary files /dev/null and b/test/degenerate-arc.xlib.ref.png differ
diff --git a/test/fill-alpha-pattern.pdf.argb32.ref.png b/test/fill-alpha-pattern.pdf.argb32.ref.png
index d786c86..d7a7ebe 100644
Binary files a/test/fill-alpha-pattern.pdf.argb32.ref.png and b/test/fill-alpha-pattern.pdf.argb32.ref.png differ
diff --git a/test/fill-alpha-pattern.pdf.rgb24.ref.png b/test/fill-alpha-pattern.pdf.rgb24.ref.png
index 75e580f..ef9049e 100644
Binary files a/test/fill-alpha-pattern.pdf.rgb24.ref.png and b/test/fill-alpha-pattern.pdf.rgb24.ref.png differ
diff --git a/test/fill-alpha-pattern.ps3.argb32.ref.png b/test/fill-alpha-pattern.ps3.argb32.ref.png
new file mode 100644
index 0000000..b16731a
Binary files /dev/null and b/test/fill-alpha-pattern.ps3.argb32.ref.png differ
diff --git a/test/fill-alpha-pattern.ps3.rgb24.ref.png b/test/fill-alpha-pattern.ps3.rgb24.ref.png
new file mode 100644
index 0000000..d019354
Binary files /dev/null and b/test/fill-alpha-pattern.ps3.rgb24.ref.png differ
diff --git a/test/fill-alpha-pattern.ref.png b/test/fill-alpha-pattern.ref.png
index 0031c04..9ab39a7 100644
Binary files a/test/fill-alpha-pattern.ref.png and b/test/fill-alpha-pattern.ref.png differ
diff --git a/test/fill-alpha-pattern.test-fallback.argb32.ref.png b/test/fill-alpha-pattern.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..4dafb83
Binary files /dev/null and b/test/fill-alpha-pattern.test-fallback.argb32.ref.png differ
diff --git a/test/fill-alpha-pattern.test-fallback.rgb24.ref.png b/test/fill-alpha-pattern.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..4dafb83
Binary files /dev/null and b/test/fill-alpha-pattern.test-fallback.rgb24.ref.png differ
diff --git a/test/fill-alpha-pattern.xlib.ref.png b/test/fill-alpha-pattern.xlib.ref.png
new file mode 100644
index 0000000..0031c04
Binary files /dev/null and b/test/fill-alpha-pattern.xlib.ref.png differ
diff --git a/test/fill-alpha.ref.png b/test/fill-alpha.ref.png
index 61aaac2..b50a456 100644
Binary files a/test/fill-alpha.ref.png and b/test/fill-alpha.ref.png differ
diff --git a/test/fill-alpha.test-fallback.argb32.ref.png b/test/fill-alpha.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..85df919
Binary files /dev/null and b/test/fill-alpha.test-fallback.argb32.ref.png differ
diff --git a/test/fill-alpha.test-fallback.rgb24.ref.png b/test/fill-alpha.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..85df919
Binary files /dev/null and b/test/fill-alpha.test-fallback.rgb24.ref.png differ
diff --git a/test/fill-alpha.xlib.ref.png b/test/fill-alpha.xlib.ref.png
new file mode 100644
index 0000000..61aaac2
Binary files /dev/null and b/test/fill-alpha.xlib.ref.png differ
diff --git a/test/fill-degenerate-sort-order.ref.png b/test/fill-degenerate-sort-order.ref.png
index 8278d76..3a95c25 100644
Binary files a/test/fill-degenerate-sort-order.ref.png and b/test/fill-degenerate-sort-order.ref.png differ
diff --git a/test/fill-degenerate-sort-order.rgb24.ref.png b/test/fill-degenerate-sort-order.rgb24.ref.png
index 6c76eaf..377c708 100644
Binary files a/test/fill-degenerate-sort-order.rgb24.ref.png and b/test/fill-degenerate-sort-order.rgb24.ref.png differ
diff --git a/test/fill-degenerate-sort-order.test-fallback.argb32.ref.png b/test/fill-degenerate-sort-order.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..8cf567d
Binary files /dev/null and b/test/fill-degenerate-sort-order.test-fallback.argb32.ref.png differ
diff --git a/test/fill-degenerate-sort-order.test-fallback.rgb24.ref.png b/test/fill-degenerate-sort-order.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..da5aa50
Binary files /dev/null and b/test/fill-degenerate-sort-order.test-fallback.rgb24.ref.png differ
diff --git a/test/fill-degenerate-sort-order.xlib.ref.png b/test/fill-degenerate-sort-order.xlib.ref.png
new file mode 100644
index 0000000..8278d76
Binary files /dev/null and b/test/fill-degenerate-sort-order.xlib.ref.png differ
diff --git a/test/fill-degenerate-sort-order.xlib.rgb24.ref.png b/test/fill-degenerate-sort-order.xlib.rgb24.ref.png
new file mode 100644
index 0000000..6c76eaf
Binary files /dev/null and b/test/fill-degenerate-sort-order.xlib.rgb24.ref.png differ
diff --git a/test/fill-missed-stop.pdf.argb32.ref.png b/test/fill-missed-stop.pdf.argb32.ref.png
new file mode 100644
index 0000000..7d56e3e
Binary files /dev/null and b/test/fill-missed-stop.pdf.argb32.ref.png differ
diff --git a/test/fill-rule.ref.png b/test/fill-rule.ref.png
index e2e10d4..6e19b62 100644
Binary files a/test/fill-rule.ref.png and b/test/fill-rule.ref.png differ
diff --git a/test/fill-rule.rgb24.ref.png b/test/fill-rule.rgb24.ref.png
index 68d2b9b..bdfc12f 100644
Binary files a/test/fill-rule.rgb24.ref.png and b/test/fill-rule.rgb24.ref.png differ
diff --git a/test/fill-rule.test-fallback.argb32.ref.png b/test/fill-rule.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..e2e10d4
Binary files /dev/null and b/test/fill-rule.test-fallback.argb32.ref.png differ
diff --git a/test/fill-rule.test-fallback.rgb24.ref.png b/test/fill-rule.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..49fb39c
Binary files /dev/null and b/test/fill-rule.test-fallback.rgb24.ref.png differ
diff --git a/test/fill-rule.xlib.ref.png b/test/fill-rule.xlib.ref.png
new file mode 100644
index 0000000..e2e10d4
Binary files /dev/null and b/test/fill-rule.xlib.ref.png differ
diff --git a/test/fill-rule.xlib.rgb24.ref.png b/test/fill-rule.xlib.rgb24.ref.png
new file mode 100644
index 0000000..68d2b9b
Binary files /dev/null and b/test/fill-rule.xlib.rgb24.ref.png differ
diff --git a/test/finer-grained-fallbacks.ps2.argb32.ref.png b/test/finer-grained-fallbacks.ps2.argb32.ref.png
new file mode 100644
index 0000000..92cd951
Binary files /dev/null and b/test/finer-grained-fallbacks.ps2.argb32.ref.png differ
diff --git a/test/finer-grained-fallbacks.ps2.rgb24.ref.png b/test/finer-grained-fallbacks.ps2.rgb24.ref.png
index de48286..688c3e0 100644
Binary files a/test/finer-grained-fallbacks.ps2.rgb24.ref.png and b/test/finer-grained-fallbacks.ps2.rgb24.ref.png differ
diff --git a/test/finer-grained-fallbacks.ps3.argb32.ref.png b/test/finer-grained-fallbacks.ps3.argb32.ref.png
new file mode 100644
index 0000000..92cd951
Binary files /dev/null and b/test/finer-grained-fallbacks.ps3.argb32.ref.png differ
diff --git a/test/finer-grained-fallbacks.ps3.rgb24.ref.png b/test/finer-grained-fallbacks.ps3.rgb24.ref.png
index de48286..688c3e0 100644
Binary files a/test/finer-grained-fallbacks.ps3.rgb24.ref.png and b/test/finer-grained-fallbacks.ps3.rgb24.ref.png differ
diff --git a/test/finer-grained-fallbacks.ref.png b/test/finer-grained-fallbacks.ref.png
index c7eb113..5b1e532 100644
Binary files a/test/finer-grained-fallbacks.ref.png and b/test/finer-grained-fallbacks.ref.png differ
diff --git a/test/finer-grained-fallbacks.rgb24.ref.png b/test/finer-grained-fallbacks.rgb24.ref.png
index 3b8e9c3..d3997fe 100644
Binary files a/test/finer-grained-fallbacks.rgb24.ref.png and b/test/finer-grained-fallbacks.rgb24.ref.png differ
diff --git a/test/finer-grained-fallbacks.test-fallback.argb32.ref.png b/test/finer-grained-fallbacks.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..c7eb113
Binary files /dev/null and b/test/finer-grained-fallbacks.test-fallback.argb32.ref.png differ
diff --git a/test/finer-grained-fallbacks.test-fallback.rgb24.ref.png b/test/finer-grained-fallbacks.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..ff75c6d
Binary files /dev/null and b/test/finer-grained-fallbacks.test-fallback.rgb24.ref.png differ
diff --git a/test/finer-grained-fallbacks.xlib.ref.png b/test/finer-grained-fallbacks.xlib.ref.png
new file mode 100644
index 0000000..c7eb113
Binary files /dev/null and b/test/finer-grained-fallbacks.xlib.ref.png differ
diff --git a/test/finer-grained-fallbacks.xlib.rgb24.ref.png b/test/finer-grained-fallbacks.xlib.rgb24.ref.png
new file mode 100644
index 0000000..3b8e9c3
Binary files /dev/null and b/test/finer-grained-fallbacks.xlib.rgb24.ref.png differ
diff --git a/test/font-matrix-translation.svg11.argb32.ref.png b/test/font-matrix-translation.svg11.argb32.ref.png
new file mode 100644
index 0000000..441f6e3
Binary files /dev/null and b/test/font-matrix-translation.svg11.argb32.ref.png differ
diff --git a/test/font-matrix-translation.svg11.rgb24.ref.png b/test/font-matrix-translation.svg11.rgb24.ref.png
new file mode 100644
index 0000000..441f6e3
Binary files /dev/null and b/test/font-matrix-translation.svg11.rgb24.ref.png differ
diff --git a/test/font-matrix-translation.svg12.argb32.ref.png b/test/font-matrix-translation.svg12.argb32.ref.png
new file mode 100644
index 0000000..441f6e3
Binary files /dev/null and b/test/font-matrix-translation.svg12.argb32.ref.png differ
diff --git a/test/font-matrix-translation.svg12.rgb24.ref.png b/test/font-matrix-translation.svg12.rgb24.ref.png
new file mode 100644
index 0000000..441f6e3
Binary files /dev/null and b/test/font-matrix-translation.svg12.rgb24.ref.png differ
diff --git a/test/ft-show-glyphs-table.svg11.argb32.ref.png b/test/ft-show-glyphs-table.svg11.argb32.ref.png
new file mode 100644
index 0000000..0c6e1c0
Binary files /dev/null and b/test/ft-show-glyphs-table.svg11.argb32.ref.png differ
diff --git a/test/ft-show-glyphs-table.svg11.rgb24.ref.png b/test/ft-show-glyphs-table.svg11.rgb24.ref.png
new file mode 100644
index 0000000..0c6e1c0
Binary files /dev/null and b/test/ft-show-glyphs-table.svg11.rgb24.ref.png differ
diff --git a/test/ft-show-glyphs-table.svg12.argb32.ref.png b/test/ft-show-glyphs-table.svg12.argb32.ref.png
new file mode 100644
index 0000000..0c6e1c0
Binary files /dev/null and b/test/ft-show-glyphs-table.svg12.argb32.ref.png differ
diff --git a/test/ft-show-glyphs-table.svg12.rgb24.ref.png b/test/ft-show-glyphs-table.svg12.rgb24.ref.png
new file mode 100644
index 0000000..0c6e1c0
Binary files /dev/null and b/test/ft-show-glyphs-table.svg12.rgb24.ref.png differ
diff --git a/test/ft-text-vertical-layout-type1.pdf.argb32.ref.png b/test/ft-text-vertical-layout-type1.pdf.argb32.ref.png
new file mode 100644
index 0000000..242c3be
Binary files /dev/null and b/test/ft-text-vertical-layout-type1.pdf.argb32.ref.png differ
diff --git a/test/ft-text-vertical-layout-type1.pdf.rgb24.ref.png b/test/ft-text-vertical-layout-type1.pdf.rgb24.ref.png
new file mode 100644
index 0000000..242c3be
Binary files /dev/null and b/test/ft-text-vertical-layout-type1.pdf.rgb24.ref.png differ
diff --git a/test/ft-text-vertical-layout-type1.ref.png b/test/ft-text-vertical-layout-type1.ref.png
index 2b74aa6..1accc0b 100644
Binary files a/test/ft-text-vertical-layout-type1.ref.png and b/test/ft-text-vertical-layout-type1.ref.png differ
diff --git a/test/ft-text-vertical-layout-type1.svg11.argb32.ref.png b/test/ft-text-vertical-layout-type1.svg11.argb32.ref.png
new file mode 100644
index 0000000..2de3f5b
Binary files /dev/null and b/test/ft-text-vertical-layout-type1.svg11.argb32.ref.png differ
diff --git a/test/ft-text-vertical-layout-type1.svg11.rgb24.ref.png b/test/ft-text-vertical-layout-type1.svg11.rgb24.ref.png
new file mode 100644
index 0000000..2de3f5b
Binary files /dev/null and b/test/ft-text-vertical-layout-type1.svg11.rgb24.ref.png differ
diff --git a/test/ft-text-vertical-layout-type1.svg12.argb32.ref.png b/test/ft-text-vertical-layout-type1.svg12.argb32.ref.png
new file mode 100644
index 0000000..2de3f5b
Binary files /dev/null and b/test/ft-text-vertical-layout-type1.svg12.argb32.ref.png differ
diff --git a/test/ft-text-vertical-layout-type1.svg12.rgb24.ref.png b/test/ft-text-vertical-layout-type1.svg12.rgb24.ref.png
new file mode 100644
index 0000000..2de3f5b
Binary files /dev/null and b/test/ft-text-vertical-layout-type1.svg12.rgb24.ref.png differ
diff --git a/test/ft-text-vertical-layout-type1.test-fallback.argb32.ref.png b/test/ft-text-vertical-layout-type1.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..9eba6bb
Binary files /dev/null and b/test/ft-text-vertical-layout-type1.test-fallback.argb32.ref.png differ
diff --git a/test/ft-text-vertical-layout-type1.test-fallback.rgb24.ref.png b/test/ft-text-vertical-layout-type1.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..9eba6bb
Binary files /dev/null and b/test/ft-text-vertical-layout-type1.test-fallback.rgb24.ref.png differ
diff --git a/test/ft-text-vertical-layout-type1.xlib.ref.png b/test/ft-text-vertical-layout-type1.xlib.ref.png
new file mode 100644
index 0000000..2b74aa6
Binary files /dev/null and b/test/ft-text-vertical-layout-type1.xlib.ref.png differ
diff --git a/test/ft-text-vertical-layout-type3.pdf.argb32.ref.png b/test/ft-text-vertical-layout-type3.pdf.argb32.ref.png
new file mode 100644
index 0000000..f232b9a
Binary files /dev/null and b/test/ft-text-vertical-layout-type3.pdf.argb32.ref.png differ
diff --git a/test/ft-text-vertical-layout-type3.pdf.rgb24.ref.png b/test/ft-text-vertical-layout-type3.pdf.rgb24.ref.png
new file mode 100644
index 0000000..f232b9a
Binary files /dev/null and b/test/ft-text-vertical-layout-type3.pdf.rgb24.ref.png differ
diff --git a/test/ft-text-vertical-layout-type3.ref.png b/test/ft-text-vertical-layout-type3.ref.png
index 8ec2ebe..6b59c56 100644
Binary files a/test/ft-text-vertical-layout-type3.ref.png and b/test/ft-text-vertical-layout-type3.ref.png differ
diff --git a/test/ft-text-vertical-layout-type3.svg11.argb32.ref.png b/test/ft-text-vertical-layout-type3.svg11.argb32.ref.png
new file mode 100644
index 0000000..cfe9268
Binary files /dev/null and b/test/ft-text-vertical-layout-type3.svg11.argb32.ref.png differ
diff --git a/test/ft-text-vertical-layout-type3.svg11.rgb24.ref.png b/test/ft-text-vertical-layout-type3.svg11.rgb24.ref.png
new file mode 100644
index 0000000..cfe9268
Binary files /dev/null and b/test/ft-text-vertical-layout-type3.svg11.rgb24.ref.png differ
diff --git a/test/ft-text-vertical-layout-type3.svg12.argb32.ref.png b/test/ft-text-vertical-layout-type3.svg12.argb32.ref.png
new file mode 100644
index 0000000..cfe9268
Binary files /dev/null and b/test/ft-text-vertical-layout-type3.svg12.argb32.ref.png differ
diff --git a/test/ft-text-vertical-layout-type3.svg12.rgb24.ref.png b/test/ft-text-vertical-layout-type3.svg12.rgb24.ref.png
new file mode 100644
index 0000000..cfe9268
Binary files /dev/null and b/test/ft-text-vertical-layout-type3.svg12.rgb24.ref.png differ
diff --git a/test/ft-text-vertical-layout-type3.test-fallback.argb32.ref.png b/test/ft-text-vertical-layout-type3.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..e57c083
Binary files /dev/null and b/test/ft-text-vertical-layout-type3.test-fallback.argb32.ref.png differ
diff --git a/test/ft-text-vertical-layout-type3.test-fallback.rgb24.ref.png b/test/ft-text-vertical-layout-type3.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..e57c083
Binary files /dev/null and b/test/ft-text-vertical-layout-type3.test-fallback.rgb24.ref.png differ
diff --git a/test/ft-text-vertical-layout-type3.xlib.ref.png b/test/ft-text-vertical-layout-type3.xlib.ref.png
new file mode 100644
index 0000000..8ec2ebe
Binary files /dev/null and b/test/ft-text-vertical-layout-type3.xlib.ref.png differ
diff --git a/test/huge-pattern.pdf.argb32.ref.png b/test/huge-pattern.pdf.argb32.ref.png
new file mode 100644
index 0000000..005d4a6
Binary files /dev/null and b/test/huge-pattern.pdf.argb32.ref.png differ
diff --git a/test/linear-gradient.pdf.argb32.ref.png b/test/linear-gradient.pdf.argb32.ref.png
new file mode 100644
index 0000000..bddb681
Binary files /dev/null and b/test/linear-gradient.pdf.argb32.ref.png differ
diff --git a/test/linear-gradient.pdf.rgb24.ref.png b/test/linear-gradient.pdf.rgb24.ref.png
new file mode 100644
index 0000000..bddb681
Binary files /dev/null and b/test/linear-gradient.pdf.rgb24.ref.png differ
diff --git a/test/linear-gradient.ref.png b/test/linear-gradient.ref.png
index cb8f908..ee238e6 100644
Binary files a/test/linear-gradient.ref.png and b/test/linear-gradient.ref.png differ
diff --git a/test/linear-gradient.svg11.argb32.ref.png b/test/linear-gradient.svg11.argb32.ref.png
new file mode 100644
index 0000000..ea0e723
Binary files /dev/null and b/test/linear-gradient.svg11.argb32.ref.png differ
diff --git a/test/linear-gradient.svg11.rgb24.ref.png b/test/linear-gradient.svg11.rgb24.ref.png
new file mode 100644
index 0000000..ea0e723
Binary files /dev/null and b/test/linear-gradient.svg11.rgb24.ref.png differ
diff --git a/test/linear-gradient.svg12.argb32.ref.png b/test/linear-gradient.svg12.argb32.ref.png
new file mode 100644
index 0000000..ea0e723
Binary files /dev/null and b/test/linear-gradient.svg12.argb32.ref.png differ
diff --git a/test/linear-gradient.svg12.rgb24.ref.png b/test/linear-gradient.svg12.rgb24.ref.png
new file mode 100644
index 0000000..ea0e723
Binary files /dev/null and b/test/linear-gradient.svg12.rgb24.ref.png differ
diff --git a/test/linear-gradient.test-fallback.argb32.ref.png b/test/linear-gradient.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..8202880
Binary files /dev/null and b/test/linear-gradient.test-fallback.argb32.ref.png differ
diff --git a/test/linear-gradient.test-fallback.rgb24.ref.png b/test/linear-gradient.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..8202880
Binary files /dev/null and b/test/linear-gradient.test-fallback.rgb24.ref.png differ
diff --git a/test/linear-gradient.xlib.ref.png b/test/linear-gradient.xlib.ref.png
new file mode 100644
index 0000000..cb8f908
Binary files /dev/null and b/test/linear-gradient.xlib.ref.png differ
diff --git a/test/mask-alpha.ref.png b/test/mask-alpha.ref.png
index 715a959..d100da4 100644
Binary files a/test/mask-alpha.ref.png and b/test/mask-alpha.ref.png differ
diff --git a/test/mask-alpha.svg11.argb32.ref.png b/test/mask-alpha.svg11.argb32.ref.png
index 3e56aa3..fa9e82d 100644
Binary files a/test/mask-alpha.svg11.argb32.ref.png and b/test/mask-alpha.svg11.argb32.ref.png differ
diff --git a/test/mask-alpha.svg11.rgb24.ref.png b/test/mask-alpha.svg11.rgb24.ref.png
new file mode 100644
index 0000000..167eab4
Binary files /dev/null and b/test/mask-alpha.svg11.rgb24.ref.png differ
diff --git a/test/mask-alpha.svg12.argb32.ref.png b/test/mask-alpha.svg12.argb32.ref.png
index 3e56aa3..fa9e82d 100644
Binary files a/test/mask-alpha.svg12.argb32.ref.png and b/test/mask-alpha.svg12.argb32.ref.png differ
diff --git a/test/mask-alpha.svg12.rgb24.ref.png b/test/mask-alpha.svg12.rgb24.ref.png
new file mode 100644
index 0000000..167eab4
Binary files /dev/null and b/test/mask-alpha.svg12.rgb24.ref.png differ
diff --git a/test/mask-alpha.test-fallback.argb32.ref.png b/test/mask-alpha.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..a0b9017
Binary files /dev/null and b/test/mask-alpha.test-fallback.argb32.ref.png differ
diff --git a/test/mask-alpha.xlib.ref.png b/test/mask-alpha.xlib.ref.png
new file mode 100644
index 0000000..715a959
Binary files /dev/null and b/test/mask-alpha.xlib.ref.png differ
diff --git a/test/mask-alpha.xlib.rgb24.ref.png b/test/mask-alpha.xlib.rgb24.ref.png
new file mode 100644
index 0000000..aa2010f
Binary files /dev/null and b/test/mask-alpha.xlib.rgb24.ref.png differ
diff --git a/test/mask.pdf.argb32.ref.png b/test/mask.pdf.argb32.ref.png
index 4570bff..d1cc8ff 100644
Binary files a/test/mask.pdf.argb32.ref.png and b/test/mask.pdf.argb32.ref.png differ
diff --git a/test/mask.pdf.rgb24.ref.png b/test/mask.pdf.rgb24.ref.png
index 1231965..a3d3845 100644
Binary files a/test/mask.pdf.rgb24.ref.png and b/test/mask.pdf.rgb24.ref.png differ
diff --git a/test/mask.ref.png b/test/mask.ref.png
index 549c130..f5d30c5 100644
Binary files a/test/mask.ref.png and b/test/mask.ref.png differ
diff --git a/test/mask.rgb24.ref.png b/test/mask.rgb24.ref.png
index 7032367..3440050 100644
Binary files a/test/mask.rgb24.ref.png and b/test/mask.rgb24.ref.png differ
diff --git a/test/mask.svg11.argb32.ref.png b/test/mask.svg11.argb32.ref.png
index c582859..e48e47b 100644
Binary files a/test/mask.svg11.argb32.ref.png and b/test/mask.svg11.argb32.ref.png differ
diff --git a/test/mask.svg11.rgb24.ref.png b/test/mask.svg11.rgb24.ref.png
index 7995723..94e3800 100644
Binary files a/test/mask.svg11.rgb24.ref.png and b/test/mask.svg11.rgb24.ref.png differ
diff --git a/test/mask.svg12.argb32.ref.png b/test/mask.svg12.argb32.ref.png
index c582859..e48e47b 100644
Binary files a/test/mask.svg12.argb32.ref.png and b/test/mask.svg12.argb32.ref.png differ
diff --git a/test/mask.svg12.rgb24.ref.png b/test/mask.svg12.rgb24.ref.png
index 7995723..94e3800 100644
Binary files a/test/mask.svg12.rgb24.ref.png and b/test/mask.svg12.rgb24.ref.png differ
diff --git a/test/mask.test-fallback.argb32.ref.png b/test/mask.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..bba0f9f
Binary files /dev/null and b/test/mask.test-fallback.argb32.ref.png differ
diff --git a/test/mask.test-fallback.rgb24.ref.png b/test/mask.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..49a5b36
Binary files /dev/null and b/test/mask.test-fallback.rgb24.ref.png differ
diff --git a/test/mask.xlib-fallback.rgb24.ref.png b/test/mask.xlib-fallback.rgb24.ref.png
new file mode 100644
index 0000000..3440050
Binary files /dev/null and b/test/mask.xlib-fallback.rgb24.ref.png differ
diff --git a/test/mask.xlib.ref.png b/test/mask.xlib.ref.png
new file mode 100644
index 0000000..549c130
Binary files /dev/null and b/test/mask.xlib.ref.png differ
diff --git a/test/mask.xlib.rgb24.ref.png b/test/mask.xlib.rgb24.ref.png
new file mode 100644
index 0000000..7032367
Binary files /dev/null and b/test/mask.xlib.rgb24.ref.png differ
diff --git a/test/meta-surface-pattern.pdf.argb32.ref.png b/test/meta-surface-pattern.pdf.argb32.ref.png
new file mode 100644
index 0000000..a842b6f
Binary files /dev/null and b/test/meta-surface-pattern.pdf.argb32.ref.png differ
diff --git a/test/meta-surface-pattern.pdf.rgb24.ref.png b/test/meta-surface-pattern.pdf.rgb24.ref.png
index 680f0f5..6555a26 100644
Binary files a/test/meta-surface-pattern.pdf.rgb24.ref.png and b/test/meta-surface-pattern.pdf.rgb24.ref.png differ
diff --git a/test/meta-surface-pattern.svg11.argb32.ref.png b/test/meta-surface-pattern.svg11.argb32.ref.png
index 6250f26..3a6836d 100644
Binary files a/test/meta-surface-pattern.svg11.argb32.ref.png and b/test/meta-surface-pattern.svg11.argb32.ref.png differ
diff --git a/test/meta-surface-pattern.svg11.rgb24.ref.png b/test/meta-surface-pattern.svg11.rgb24.ref.png
index feda67d..dea9b9b 100644
Binary files a/test/meta-surface-pattern.svg11.rgb24.ref.png and b/test/meta-surface-pattern.svg11.rgb24.ref.png differ
diff --git a/test/meta-surface-pattern.svg12.argb32.ref.png b/test/meta-surface-pattern.svg12.argb32.ref.png
index 6250f26..3a6836d 100644
Binary files a/test/meta-surface-pattern.svg12.argb32.ref.png and b/test/meta-surface-pattern.svg12.argb32.ref.png differ
diff --git a/test/meta-surface-pattern.svg12.rgb24.ref.png b/test/meta-surface-pattern.svg12.rgb24.ref.png
index feda67d..dea9b9b 100644
Binary files a/test/meta-surface-pattern.svg12.rgb24.ref.png and b/test/meta-surface-pattern.svg12.rgb24.ref.png differ
diff --git a/test/operator-clear.pdf.argb32.ref.png b/test/operator-clear.pdf.argb32.ref.png
index 06fc51e..258c61c 100644
Binary files a/test/operator-clear.pdf.argb32.ref.png and b/test/operator-clear.pdf.argb32.ref.png differ
diff --git a/test/operator-clear.ps2.argb32.ref.png b/test/operator-clear.ps2.argb32.ref.png
new file mode 100644
index 0000000..92b4111
Binary files /dev/null and b/test/operator-clear.ps2.argb32.ref.png differ
diff --git a/test/operator-clear.ps3.argb32.ref.png b/test/operator-clear.ps3.argb32.ref.png
new file mode 100644
index 0000000..92b4111
Binary files /dev/null and b/test/operator-clear.ps3.argb32.ref.png differ
diff --git a/test/operator-source.pdf.argb32.ref.png b/test/operator-source.pdf.argb32.ref.png
index f110ff2..f42d5af 100644
Binary files a/test/operator-source.pdf.argb32.ref.png and b/test/operator-source.pdf.argb32.ref.png differ
diff --git a/test/operator-source.pdf.rgb24.ref.png b/test/operator-source.pdf.rgb24.ref.png
index c6b7170..8269bc1 100644
Binary files a/test/operator-source.pdf.rgb24.ref.png and b/test/operator-source.pdf.rgb24.ref.png differ
diff --git a/test/operator-source.ref.png b/test/operator-source.ref.png
index 8e2f5e6..006bf95 100644
Binary files a/test/operator-source.ref.png and b/test/operator-source.ref.png differ
diff --git a/test/operator-source.rgb24.ref.png b/test/operator-source.rgb24.ref.png
index a762d60..013d8a4 100644
Binary files a/test/operator-source.rgb24.ref.png and b/test/operator-source.rgb24.ref.png differ
diff --git a/test/operator-source.test-fallback.argb32.ref.png b/test/operator-source.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..8aac39d
Binary files /dev/null and b/test/operator-source.test-fallback.argb32.ref.png differ
diff --git a/test/operator-source.test-fallback.rgb24.ref.png b/test/operator-source.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..ad37a60
Binary files /dev/null and b/test/operator-source.test-fallback.rgb24.ref.png differ
diff --git a/test/operator-source.xlib-fallback.rgb24.ref.png b/test/operator-source.xlib-fallback.rgb24.ref.png
new file mode 100644
index 0000000..fe0d3c6
Binary files /dev/null and b/test/operator-source.xlib-fallback.rgb24.ref.png differ
diff --git a/test/operator-source.xlib.ref.png b/test/operator-source.xlib.ref.png
new file mode 100644
index 0000000..8e2f5e6
Binary files /dev/null and b/test/operator-source.xlib.ref.png differ
diff --git a/test/operator-source.xlib.rgb24.ref.png b/test/operator-source.xlib.rgb24.ref.png
new file mode 100644
index 0000000..a762d60
Binary files /dev/null and b/test/operator-source.xlib.rgb24.ref.png differ
diff --git a/test/over-above-source.ps2.argb32.ref.png b/test/over-above-source.ps2.argb32.ref.png
index 886faad..7c90d08 100644
Binary files a/test/over-above-source.ps2.argb32.ref.png and b/test/over-above-source.ps2.argb32.ref.png differ
diff --git a/test/over-above-source.ps3.argb32.ref.png b/test/over-above-source.ps3.argb32.ref.png
index 886faad..7c90d08 100644
Binary files a/test/over-above-source.ps3.argb32.ref.png and b/test/over-above-source.ps3.argb32.ref.png differ
diff --git a/test/over-above-source.ref.png b/test/over-above-source.ref.png
index f3a49f6..c45fcbd 100644
Binary files a/test/over-above-source.ref.png and b/test/over-above-source.ref.png differ
diff --git a/test/over-above-source.rgb24.ref.png b/test/over-above-source.rgb24.ref.png
index 68c7d98..84fc880 100644
Binary files a/test/over-above-source.rgb24.ref.png and b/test/over-above-source.rgb24.ref.png differ
diff --git a/test/over-above-source.test-fallback.argb32.ref.png b/test/over-above-source.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..8a0183a
Binary files /dev/null and b/test/over-above-source.test-fallback.argb32.ref.png differ
diff --git a/test/over-above-source.test-fallback.rgb24.ref.png b/test/over-above-source.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..85c1997
Binary files /dev/null and b/test/over-above-source.test-fallback.rgb24.ref.png differ
diff --git a/test/over-above-source.xlib.ref.png b/test/over-above-source.xlib.ref.png
new file mode 100644
index 0000000..f3a49f6
Binary files /dev/null and b/test/over-above-source.xlib.ref.png differ
diff --git a/test/over-above-source.xlib.rgb24.ref.png b/test/over-above-source.xlib.rgb24.ref.png
new file mode 100644
index 0000000..68c7d98
Binary files /dev/null and b/test/over-above-source.xlib.rgb24.ref.png differ
diff --git a/test/over-around-source.pdf.argb32.ref.png b/test/over-around-source.pdf.argb32.ref.png
new file mode 100644
index 0000000..02af76a
Binary files /dev/null and b/test/over-around-source.pdf.argb32.ref.png differ
diff --git a/test/over-around-source.ps2.argb32.ref.png b/test/over-around-source.ps2.argb32.ref.png
index ea6de69..647420a 100644
Binary files a/test/over-around-source.ps2.argb32.ref.png and b/test/over-around-source.ps2.argb32.ref.png differ
diff --git a/test/over-around-source.ps3.argb32.ref.png b/test/over-around-source.ps3.argb32.ref.png
index ea6de69..647420a 100644
Binary files a/test/over-around-source.ps3.argb32.ref.png and b/test/over-around-source.ps3.argb32.ref.png differ
diff --git a/test/over-around-source.ref.png b/test/over-around-source.ref.png
index ccae951..abaeb4e 100644
Binary files a/test/over-around-source.ref.png and b/test/over-around-source.ref.png differ
diff --git a/test/over-around-source.test-fallback.argb32.ref.png b/test/over-around-source.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..fca7505
Binary files /dev/null and b/test/over-around-source.test-fallback.argb32.ref.png differ
diff --git a/test/over-around-source.xlib.ref.png b/test/over-around-source.xlib.ref.png
new file mode 100644
index 0000000..ccae951
Binary files /dev/null and b/test/over-around-source.xlib.ref.png differ
diff --git a/test/over-around-source.xlib.rgb24.ref.png b/test/over-around-source.xlib.rgb24.ref.png
new file mode 100644
index 0000000..943a28e
Binary files /dev/null and b/test/over-around-source.xlib.rgb24.ref.png differ
diff --git a/test/over-below-source.pdf.argb32.ref.png b/test/over-below-source.pdf.argb32.ref.png
new file mode 100644
index 0000000..b9c4fe2
Binary files /dev/null and b/test/over-below-source.pdf.argb32.ref.png differ
diff --git a/test/over-between-source.ps2.argb32.ref.png b/test/over-between-source.ps2.argb32.ref.png
index 43e9424..dd95940 100644
Binary files a/test/over-between-source.ps2.argb32.ref.png and b/test/over-between-source.ps2.argb32.ref.png differ
diff --git a/test/over-between-source.ps3.argb32.ref.png b/test/over-between-source.ps3.argb32.ref.png
index 43e9424..dd95940 100644
Binary files a/test/over-between-source.ps3.argb32.ref.png and b/test/over-between-source.ps3.argb32.ref.png differ
diff --git a/test/over-between-source.ref.png b/test/over-between-source.ref.png
index 79ea75e..0c3986f 100644
Binary files a/test/over-between-source.ref.png and b/test/over-between-source.ref.png differ
diff --git a/test/over-between-source.test-fallback.argb32.ref.png b/test/over-between-source.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..a8fe66a
Binary files /dev/null and b/test/over-between-source.test-fallback.argb32.ref.png differ
diff --git a/test/over-between-source.xlib.ref.png b/test/over-between-source.xlib.ref.png
new file mode 100644
index 0000000..79ea75e
Binary files /dev/null and b/test/over-between-source.xlib.ref.png differ
diff --git a/test/over-between-source.xlib.rgb24.ref.png b/test/over-between-source.xlib.rgb24.ref.png
new file mode 100644
index 0000000..602f2d2
Binary files /dev/null and b/test/over-between-source.xlib.rgb24.ref.png differ
diff --git a/test/push-group.pdf.argb32.ref.png b/test/push-group.pdf.argb32.ref.png
new file mode 100644
index 0000000..9cb59c9
Binary files /dev/null and b/test/push-group.pdf.argb32.ref.png differ
diff --git a/test/push-group.pdf.rgb24.ref.png b/test/push-group.pdf.rgb24.ref.png
index 7e84ec8..34d7f74 100644
Binary files a/test/push-group.pdf.rgb24.ref.png and b/test/push-group.pdf.rgb24.ref.png differ
diff --git a/test/push-group.ref.png b/test/push-group.ref.png
index 84bc184..e4ae291 100644
Binary files a/test/push-group.ref.png and b/test/push-group.ref.png differ
diff --git a/test/push-group.rgb24.ref.png b/test/push-group.rgb24.ref.png
index cababd9..3a95182 100644
Binary files a/test/push-group.rgb24.ref.png and b/test/push-group.rgb24.ref.png differ
diff --git a/test/push-group.svg11.argb32.ref.png b/test/push-group.svg11.argb32.ref.png
index 34f06bf..d695879 100644
Binary files a/test/push-group.svg11.argb32.ref.png and b/test/push-group.svg11.argb32.ref.png differ
diff --git a/test/push-group.svg12.argb32.ref.png b/test/push-group.svg12.argb32.ref.png
index 34f06bf..d695879 100644
Binary files a/test/push-group.svg12.argb32.ref.png and b/test/push-group.svg12.argb32.ref.png differ
diff --git a/test/push-group.test-fallback.argb32.ref.png b/test/push-group.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..7c5905a
Binary files /dev/null and b/test/push-group.test-fallback.argb32.ref.png differ
diff --git a/test/push-group.test-fallback.rgb24.ref.png b/test/push-group.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..4586d5c
Binary files /dev/null and b/test/push-group.test-fallback.rgb24.ref.png differ
diff --git a/test/push-group.xlib-fallback.rgb24.ref.png b/test/push-group.xlib-fallback.rgb24.ref.png
new file mode 100644
index 0000000..3a95182
Binary files /dev/null and b/test/push-group.xlib-fallback.rgb24.ref.png differ
diff --git a/test/push-group.xlib.ref.png b/test/push-group.xlib.ref.png
new file mode 100644
index 0000000..84bc184
Binary files /dev/null and b/test/push-group.xlib.ref.png differ
diff --git a/test/push-group.xlib.rgb24.ref.png b/test/push-group.xlib.rgb24.ref.png
new file mode 100644
index 0000000..cababd9
Binary files /dev/null and b/test/push-group.xlib.rgb24.ref.png differ
diff --git a/test/radial-gradient.pdf.argb32.ref.png b/test/radial-gradient.pdf.argb32.ref.png
new file mode 100644
index 0000000..6cee5d1
Binary files /dev/null and b/test/radial-gradient.pdf.argb32.ref.png differ
diff --git a/test/radial-gradient.pdf.rgb24.ref.png b/test/radial-gradient.pdf.rgb24.ref.png
new file mode 100644
index 0000000..6cee5d1
Binary files /dev/null and b/test/radial-gradient.pdf.rgb24.ref.png differ
diff --git a/test/random-intersections.ref.png b/test/random-intersections.ref.png
index 3188ede..ace75a2 100644
Binary files a/test/random-intersections.ref.png and b/test/random-intersections.ref.png differ
diff --git a/test/random-intersections.test-fallback.argb32.ref.png b/test/random-intersections.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..a35364d
Binary files /dev/null and b/test/random-intersections.test-fallback.argb32.ref.png differ
diff --git a/test/random-intersections.test-fallback.rgb24.ref.png b/test/random-intersections.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..a35364d
Binary files /dev/null and b/test/random-intersections.test-fallback.rgb24.ref.png differ
diff --git a/test/random-intersections.xlib.ref.png b/test/random-intersections.xlib.ref.png
new file mode 100644
index 0000000..3188ede
Binary files /dev/null and b/test/random-intersections.xlib.ref.png differ
diff --git a/test/smask-fill.pdf.argb32.ref.png b/test/smask-fill.pdf.argb32.ref.png
new file mode 100644
index 0000000..51d34d4
Binary files /dev/null and b/test/smask-fill.pdf.argb32.ref.png differ
diff --git a/test/smask-fill.pdf.rgb24.ref.png b/test/smask-fill.pdf.rgb24.ref.png
new file mode 100644
index 0000000..51d34d4
Binary files /dev/null and b/test/smask-fill.pdf.rgb24.ref.png differ
diff --git a/test/smask-fill.ref.png b/test/smask-fill.ref.png
index c778a79..28ab733 100644
Binary files a/test/smask-fill.ref.png and b/test/smask-fill.ref.png differ
diff --git a/test/smask-fill.svg11.argb32.ref.png b/test/smask-fill.svg11.argb32.ref.png
new file mode 100644
index 0000000..57ae76e
Binary files /dev/null and b/test/smask-fill.svg11.argb32.ref.png differ
diff --git a/test/smask-fill.svg11.rgb24.ref.png b/test/smask-fill.svg11.rgb24.ref.png
new file mode 100644
index 0000000..57ae76e
Binary files /dev/null and b/test/smask-fill.svg11.rgb24.ref.png differ
diff --git a/test/smask-fill.svg12.argb32.ref.png b/test/smask-fill.svg12.argb32.ref.png
new file mode 100644
index 0000000..57ae76e
Binary files /dev/null and b/test/smask-fill.svg12.argb32.ref.png differ
diff --git a/test/smask-fill.svg12.rgb24.ref.png b/test/smask-fill.svg12.rgb24.ref.png
new file mode 100644
index 0000000..57ae76e
Binary files /dev/null and b/test/smask-fill.svg12.rgb24.ref.png differ
diff --git a/test/smask-fill.test-fallback.argb32.ref.png b/test/smask-fill.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..3d375bb
Binary files /dev/null and b/test/smask-fill.test-fallback.argb32.ref.png differ
diff --git a/test/smask-fill.test-fallback.rgb24.ref.png b/test/smask-fill.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..3d375bb
Binary files /dev/null and b/test/smask-fill.test-fallback.rgb24.ref.png differ
diff --git a/test/smask-fill.xlib-fallback.ref.png b/test/smask-fill.xlib-fallback.ref.png
new file mode 100644
index 0000000..28ab733
Binary files /dev/null and b/test/smask-fill.xlib-fallback.ref.png differ
diff --git a/test/smask-fill.xlib.ref.png b/test/smask-fill.xlib.ref.png
new file mode 100644
index 0000000..c778a79
Binary files /dev/null and b/test/smask-fill.xlib.ref.png differ
diff --git a/test/smask-image-mask.pdf.argb32.ref.png b/test/smask-image-mask.pdf.argb32.ref.png
new file mode 100644
index 0000000..19a20f4
Binary files /dev/null and b/test/smask-image-mask.pdf.argb32.ref.png differ
diff --git a/test/smask-image-mask.pdf.rgb24.ref.png b/test/smask-image-mask.pdf.rgb24.ref.png
new file mode 100644
index 0000000..19a20f4
Binary files /dev/null and b/test/smask-image-mask.pdf.rgb24.ref.png differ
diff --git a/test/smask-mask.pdf.argb32.ref.png b/test/smask-mask.pdf.argb32.ref.png
new file mode 100644
index 0000000..0dc2135
Binary files /dev/null and b/test/smask-mask.pdf.argb32.ref.png differ
diff --git a/test/smask-mask.pdf.rgb24.ref.png b/test/smask-mask.pdf.rgb24.ref.png
new file mode 100644
index 0000000..0dc2135
Binary files /dev/null and b/test/smask-mask.pdf.rgb24.ref.png differ
diff --git a/test/smask-paint.pdf.argb32.ref.png b/test/smask-paint.pdf.argb32.ref.png
new file mode 100644
index 0000000..c6b1731
Binary files /dev/null and b/test/smask-paint.pdf.argb32.ref.png differ
diff --git a/test/smask-paint.pdf.rgb24.ref.png b/test/smask-paint.pdf.rgb24.ref.png
new file mode 100644
index 0000000..c6b1731
Binary files /dev/null and b/test/smask-paint.pdf.rgb24.ref.png differ
diff --git a/test/smask-stroke.pdf.argb32.ref.png b/test/smask-stroke.pdf.argb32.ref.png
new file mode 100644
index 0000000..41321f2
Binary files /dev/null and b/test/smask-stroke.pdf.argb32.ref.png differ
diff --git a/test/smask-stroke.pdf.rgb24.ref.png b/test/smask-stroke.pdf.rgb24.ref.png
new file mode 100644
index 0000000..41321f2
Binary files /dev/null and b/test/smask-stroke.pdf.rgb24.ref.png differ
diff --git a/test/smask-text.svg11.argb32.ref.png b/test/smask-text.svg11.argb32.ref.png
new file mode 100644
index 0000000..5034526
Binary files /dev/null and b/test/smask-text.svg11.argb32.ref.png differ
diff --git a/test/smask-text.svg11.rgb24.ref.png b/test/smask-text.svg11.rgb24.ref.png
new file mode 100644
index 0000000..5034526
Binary files /dev/null and b/test/smask-text.svg11.rgb24.ref.png differ
diff --git a/test/smask-text.svg12.argb32.ref.png b/test/smask-text.svg12.argb32.ref.png
new file mode 100644
index 0000000..5034526
Binary files /dev/null and b/test/smask-text.svg12.argb32.ref.png differ
diff --git a/test/smask-text.svg12.rgb24.ref.png b/test/smask-text.svg12.rgb24.ref.png
new file mode 100644
index 0000000..5034526
Binary files /dev/null and b/test/smask-text.svg12.rgb24.ref.png differ
diff --git a/test/smask.pdf.argb32.ref.png b/test/smask.pdf.argb32.ref.png
new file mode 100644
index 0000000..c6b1731
Binary files /dev/null and b/test/smask.pdf.argb32.ref.png differ
diff --git a/test/smask.pdf.rgb24.ref.png b/test/smask.pdf.rgb24.ref.png
new file mode 100644
index 0000000..c6b1731
Binary files /dev/null and b/test/smask.pdf.rgb24.ref.png differ
diff --git a/test/text-pattern.pdf.argb32.ref.png b/test/text-pattern.pdf.argb32.ref.png
index 2a70deb..dfaed39 100644
Binary files a/test/text-pattern.pdf.argb32.ref.png and b/test/text-pattern.pdf.argb32.ref.png differ
diff --git a/test/text-pattern.svg11.argb32.ref.png b/test/text-pattern.svg11.argb32.ref.png
index 97d7534..47ee89c 100644
Binary files a/test/text-pattern.svg11.argb32.ref.png and b/test/text-pattern.svg11.argb32.ref.png differ
diff --git a/test/text-pattern.svg12.argb32.ref.png b/test/text-pattern.svg12.argb32.ref.png
index 97d7534..47ee89c 100644
Binary files a/test/text-pattern.svg12.argb32.ref.png and b/test/text-pattern.svg12.argb32.ref.png differ
diff --git a/test/text-rotate.svg11.argb32.ref.png b/test/text-rotate.svg11.argb32.ref.png
new file mode 100644
index 0000000..4864046
Binary files /dev/null and b/test/text-rotate.svg11.argb32.ref.png differ
diff --git a/test/text-rotate.svg11.rgb24.ref.png b/test/text-rotate.svg11.rgb24.ref.png
new file mode 100644
index 0000000..4864046
Binary files /dev/null and b/test/text-rotate.svg11.rgb24.ref.png differ
diff --git a/test/text-rotate.svg12.argb32.ref.png b/test/text-rotate.svg12.argb32.ref.png
new file mode 100644
index 0000000..4864046
Binary files /dev/null and b/test/text-rotate.svg12.argb32.ref.png differ
diff --git a/test/text-rotate.svg12.rgb24.ref.png b/test/text-rotate.svg12.rgb24.ref.png
new file mode 100644
index 0000000..4864046
Binary files /dev/null and b/test/text-rotate.svg12.rgb24.ref.png differ
diff --git a/test/text-transform.svg11.argb32.ref.png b/test/text-transform.svg11.argb32.ref.png
new file mode 100644
index 0000000..0c4e57c
Binary files /dev/null and b/test/text-transform.svg11.argb32.ref.png differ
diff --git a/test/text-transform.svg11.rgb24.ref.png b/test/text-transform.svg11.rgb24.ref.png
new file mode 100644
index 0000000..0c4e57c
Binary files /dev/null and b/test/text-transform.svg11.rgb24.ref.png differ
diff --git a/test/text-transform.svg12.argb32.ref.png b/test/text-transform.svg12.argb32.ref.png
new file mode 100644
index 0000000..0c4e57c
Binary files /dev/null and b/test/text-transform.svg12.argb32.ref.png differ
diff --git a/test/text-transform.svg12.rgb24.ref.png b/test/text-transform.svg12.rgb24.ref.png
new file mode 100644
index 0000000..0c4e57c
Binary files /dev/null and b/test/text-transform.svg12.rgb24.ref.png differ
diff --git a/test/trap-clip.pdf.argb32.ref.png b/test/trap-clip.pdf.argb32.ref.png
index c3ee997..1501016 100644
Binary files a/test/trap-clip.pdf.argb32.ref.png and b/test/trap-clip.pdf.argb32.ref.png differ
diff --git a/test/trap-clip.pdf.rgb24.ref.png b/test/trap-clip.pdf.rgb24.ref.png
index f787011..90b476b 100644
Binary files a/test/trap-clip.pdf.rgb24.ref.png and b/test/trap-clip.pdf.rgb24.ref.png differ
diff --git a/test/trap-clip.ps2.argb32.ref.png b/test/trap-clip.ps2.argb32.ref.png
index 37121cd..957b938 100644
Binary files a/test/trap-clip.ps2.argb32.ref.png and b/test/trap-clip.ps2.argb32.ref.png differ
diff --git a/test/trap-clip.ref.png b/test/trap-clip.ref.png
index 2cbbdb7..dee57e7 100644
Binary files a/test/trap-clip.ref.png and b/test/trap-clip.ref.png differ
diff --git a/test/trap-clip.rgb24.ref.png b/test/trap-clip.rgb24.ref.png
index 15068aa..e61992f 100644
Binary files a/test/trap-clip.rgb24.ref.png and b/test/trap-clip.rgb24.ref.png differ
diff --git a/test/trap-clip.test-fallback.argb32.ref.png b/test/trap-clip.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..319d835
Binary files /dev/null and b/test/trap-clip.test-fallback.argb32.ref.png differ
diff --git a/test/trap-clip.test-fallback.rgb24.ref.png b/test/trap-clip.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..7ac5789
Binary files /dev/null and b/test/trap-clip.test-fallback.rgb24.ref.png differ
diff --git a/test/trap-clip.xlib.ref.png b/test/trap-clip.xlib.ref.png
new file mode 100644
index 0000000..2cbbdb7
Binary files /dev/null and b/test/trap-clip.xlib.ref.png differ
diff --git a/test/trap-clip.xlib.rgb24.ref.png b/test/trap-clip.xlib.rgb24.ref.png
new file mode 100644
index 0000000..15068aa
Binary files /dev/null and b/test/trap-clip.xlib.rgb24.ref.png differ
diff --git a/test/twin.svg11.argb32.ref.png b/test/twin.svg11.argb32.ref.png
new file mode 100644
index 0000000..0818c67
Binary files /dev/null and b/test/twin.svg11.argb32.ref.png differ
diff --git a/test/twin.svg11.rgb24.ref.png b/test/twin.svg11.rgb24.ref.png
new file mode 100644
index 0000000..0818c67
Binary files /dev/null and b/test/twin.svg11.rgb24.ref.png differ
diff --git a/test/twin.svg12.argb32.ref.png b/test/twin.svg12.argb32.ref.png
new file mode 100644
index 0000000..0818c67
Binary files /dev/null and b/test/twin.svg12.argb32.ref.png differ
diff --git a/test/twin.svg12.rgb24.ref.png b/test/twin.svg12.rgb24.ref.png
new file mode 100644
index 0000000..0818c67
Binary files /dev/null and b/test/twin.svg12.rgb24.ref.png differ
diff --git a/test/unbounded-operator.pdf.argb32.ref.png b/test/unbounded-operator.pdf.argb32.ref.png
new file mode 100644
index 0000000..4aa476d
Binary files /dev/null and b/test/unbounded-operator.pdf.argb32.ref.png differ
diff --git a/test/unbounded-operator.ps2.argb32.ref.png b/test/unbounded-operator.ps2.argb32.ref.png
new file mode 100644
index 0000000..4aa476d
Binary files /dev/null and b/test/unbounded-operator.ps2.argb32.ref.png differ
diff --git a/test/unbounded-operator.ps3.argb32.ref.png b/test/unbounded-operator.ps3.argb32.ref.png
new file mode 100644
index 0000000..4aa476d
Binary files /dev/null and b/test/unbounded-operator.ps3.argb32.ref.png differ
diff --git a/test/unbounded-operator.rgb24.ref.png b/test/unbounded-operator.rgb24.ref.png
index b2f1a84..ad3225d 100644
Binary files a/test/unbounded-operator.rgb24.ref.png and b/test/unbounded-operator.rgb24.ref.png differ
diff --git a/test/unbounded-operator.test-fallback.rgb24.ref.png b/test/unbounded-operator.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..07c7ecf
Binary files /dev/null and b/test/unbounded-operator.test-fallback.rgb24.ref.png differ
diff --git a/test/unbounded-operator.xlib.rgb24.ref.png b/test/unbounded-operator.xlib.rgb24.ref.png
new file mode 100644
index 0000000..b2f1a84
Binary files /dev/null and b/test/unbounded-operator.xlib.rgb24.ref.png differ
diff --git a/test/user-font-proxy.pdf.argb32.ref.png b/test/user-font-proxy.pdf.argb32.ref.png
new file mode 100644
index 0000000..cffa9ed
Binary files /dev/null and b/test/user-font-proxy.pdf.argb32.ref.png differ
diff --git a/test/user-font-proxy.pdf.rgb24.ref.png b/test/user-font-proxy.pdf.rgb24.ref.png
new file mode 100644
index 0000000..cffa9ed
Binary files /dev/null and b/test/user-font-proxy.pdf.rgb24.ref.png differ
diff --git a/test/user-font-proxy.ref.png b/test/user-font-proxy.ref.png
index ebd9719..cffa9ed 100644
Binary files a/test/user-font-proxy.ref.png and b/test/user-font-proxy.ref.png differ
diff --git a/test/user-font-proxy.svg11.argb32.ref.png b/test/user-font-proxy.svg11.argb32.ref.png
new file mode 100644
index 0000000..d2a7812
Binary files /dev/null and b/test/user-font-proxy.svg11.argb32.ref.png differ
diff --git a/test/user-font-proxy.svg11.rgb24.ref.png b/test/user-font-proxy.svg11.rgb24.ref.png
new file mode 100644
index 0000000..d2a7812
Binary files /dev/null and b/test/user-font-proxy.svg11.rgb24.ref.png differ
diff --git a/test/user-font-proxy.svg12.argb32.ref.png b/test/user-font-proxy.svg12.argb32.ref.png
new file mode 100644
index 0000000..d2a7812
Binary files /dev/null and b/test/user-font-proxy.svg12.argb32.ref.png differ
diff --git a/test/user-font-proxy.svg12.rgb24.ref.png b/test/user-font-proxy.svg12.rgb24.ref.png
new file mode 100644
index 0000000..d2a7812
Binary files /dev/null and b/test/user-font-proxy.svg12.rgb24.ref.png differ
diff --git a/test/user-font-proxy.test-fallback.argb32.ref.png b/test/user-font-proxy.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..9cccf31
Binary files /dev/null and b/test/user-font-proxy.test-fallback.argb32.ref.png differ
diff --git a/test/user-font-proxy.test-fallback.rgb24.ref.png b/test/user-font-proxy.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..9cccf31
Binary files /dev/null and b/test/user-font-proxy.test-fallback.rgb24.ref.png differ
diff --git a/test/user-font-proxy.xlib.ref.png b/test/user-font-proxy.xlib.ref.png
new file mode 100644
index 0000000..ebd9719
Binary files /dev/null and b/test/user-font-proxy.xlib.ref.png differ
diff --git a/test/user-font.ref.png b/test/user-font.ref.png
index abc3117..753fc7b 100644
Binary files a/test/user-font.ref.png and b/test/user-font.ref.png differ
diff --git a/test/user-font.svg11.argb32.ref.png b/test/user-font.svg11.argb32.ref.png
new file mode 100644
index 0000000..3dc77ae
Binary files /dev/null and b/test/user-font.svg11.argb32.ref.png differ
diff --git a/test/user-font.svg11.rgb24.ref.png b/test/user-font.svg11.rgb24.ref.png
new file mode 100644
index 0000000..3dc77ae
Binary files /dev/null and b/test/user-font.svg11.rgb24.ref.png differ
diff --git a/test/user-font.svg12.argb32.ref.png b/test/user-font.svg12.argb32.ref.png
new file mode 100644
index 0000000..3dc77ae
Binary files /dev/null and b/test/user-font.svg12.argb32.ref.png differ
diff --git a/test/user-font.svg12.rgb24.ref.png b/test/user-font.svg12.rgb24.ref.png
new file mode 100644
index 0000000..3dc77ae
Binary files /dev/null and b/test/user-font.svg12.rgb24.ref.png differ
diff --git a/test/user-font.test-fallback.argb32.ref.png b/test/user-font.test-fallback.argb32.ref.png
new file mode 100644
index 0000000..3080c69
Binary files /dev/null and b/test/user-font.test-fallback.argb32.ref.png differ
diff --git a/test/user-font.test-fallback.rgb24.ref.png b/test/user-font.test-fallback.rgb24.ref.png
new file mode 100644
index 0000000..3080c69
Binary files /dev/null and b/test/user-font.test-fallback.rgb24.ref.png differ
diff --git a/test/user-font.xlib.ref.png b/test/user-font.xlib.ref.png
new file mode 100644
index 0000000..abc3117
Binary files /dev/null and b/test/user-font.xlib.ref.png differ
commit 85b81a3e59401e2fc68209634f7622694e7d30e1
Author: M Joonas Pihlaja <jpihlaja at cc.helsinki.fi>
Date:   Fri Jul 11 13:10:20 2008 +0300

    [cairo-spans] Implement a span renderer for cairo_image_surface_t.
    
    This implementation first produces an A8 alpha mask and then
    pixman_image_composites the result to the destination with the source.
    Clipping is handled by pixman when it is region clipping or by
    cairo-surface-fallback when it is something more complex.

diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index ef5e238..f484466 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -1078,6 +1078,15 @@ _cairo_image_surface_fill_rectangles (void		      *abstract_surface,
     return status;
 }
 
+static cairo_format_t
+_cairo_mask_format_from_antialias (cairo_antialias_t antialias)
+{
+    if (antialias == CAIRO_ANTIALIAS_NONE)
+	return CAIRO_FORMAT_A1;
+    return CAIRO_FORMAT_A8;
+}
+
+
 static cairo_int_status_t
 _cairo_image_surface_composite_trapezoids (cairo_operator_t	op,
 					   const cairo_pattern_t *pattern,
@@ -1095,13 +1104,10 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t	op,
     cairo_surface_attributes_t	attributes;
     cairo_image_surface_t	*dst = abstract_dst;
     cairo_image_surface_t	*src;
-    cairo_int_status_t		status;
-    pixman_image_t		*mask;
-    pixman_format_code_t	 format;
-    uint32_t			*mask_data;
+    cairo_int_status_t		 status;
+    cairo_image_surface_t	*mask = NULL;
     pixman_trapezoid_t		 stack_traps[CAIRO_STACK_ARRAY_LENGTH (pixman_trapezoid_t)];
     pixman_trapezoid_t		*pixman_traps = stack_traps;
-    int				 mask_stride;
     int				 i;
 
     if (height == 0 || width == 0)
@@ -1165,40 +1171,19 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t	op,
     if (unlikely (status))
 	goto CLEANUP_SOURCE;
 
-    switch (antialias) {
-    case CAIRO_ANTIALIAS_NONE:
-	format = PIXMAN_a1;
-	mask_stride = ((width + 31) / 8) & ~0x03;
-	break;
-    case CAIRO_ANTIALIAS_GRAY:
-    case CAIRO_ANTIALIAS_SUBPIXEL:
-    case CAIRO_ANTIALIAS_DEFAULT:
-    default:
-	format = PIXMAN_a8;
-	mask_stride = (width + 3) & ~3;
-	break;
-    }
-
-    /* The image must be initially transparent */
-    mask_data = calloc (mask_stride, height);
-    if (unlikely (mask_data == NULL)) {
-	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    mask = (cairo_image_surface_t *)
+	cairo_image_surface_create (
+	    _cairo_mask_format_from_antialias (antialias),
+	    width, height);
+    if (cairo_surface_status (&mask->base) != CAIRO_STATUS_SUCCESS)
 	goto CLEANUP_SOURCE;
-    }
 
-    mask = pixman_image_create_bits (format, width, height,
-				     mask_data, mask_stride);
-    if (unlikely (mask == NULL)) {
-	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	goto CLEANUP_IMAGE_DATA;
-    }
-
-    pixman_add_trapezoids (mask, - dst_x, - dst_y,
+    pixman_add_trapezoids (mask->pixman_image, - dst_x, - dst_y,
 			   num_traps, pixman_traps);
 
     pixman_image_composite (_pixman_operator (op),
 			    src->pixman_image,
-			    mask,
+			    mask->pixman_image,
 			    dst->pixman_image,
 			    src_x + attributes.x_offset,
 			    src_y + attributes.y_offset,
@@ -1208,15 +1193,13 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t	op,
 
     if (! _cairo_operator_bounded_by_mask (op))
 	status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
-								 &attributes, src->width, src->height,
+								 &attributes,
+								 src->width, src->height,
 								 width, height,
 								 src_x, src_y,
 								 0, 0,
 								 dst_x, dst_y, width, height);
-    pixman_image_unref (mask);
-
- CLEANUP_IMAGE_DATA:
-    free (mask_data);
+    cairo_surface_destroy (&mask->base);
 
  CLEANUP_SOURCE:
     _cairo_pattern_release_surface (pattern, &src->base, &attributes);
@@ -1228,6 +1211,216 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t	op,
     return status;
 }
 
+typedef struct _cairo_image_surface_span_renderer {
+    cairo_span_renderer_t base;
+
+    cairo_operator_t op;
+    const cairo_pattern_t *pattern;
+    cairo_antialias_t antialias;
+
+    cairo_image_surface_t *src;
+    cairo_surface_attributes_t src_attributes;
+    cairo_image_surface_t *mask;
+    cairo_image_surface_t *dst;
+
+    cairo_composite_rectangles_t composite_rectangles;
+} cairo_image_surface_span_renderer_t;
+
+static cairo_status_t
+_cairo_image_surface_span_renderer_render_row (
+    void				*abstract_renderer,
+    int					 y,
+    const cairo_half_open_span_t	*spans,
+    unsigned				 num_spans)
+{
+    cairo_image_surface_span_renderer_t *renderer = abstract_renderer;
+    int xmin = renderer->composite_rectangles.mask.x;
+    int xmax = xmin + renderer->composite_rectangles.width;
+    uint8_t *row;
+    int prev_x = xmin;
+    int prev_alpha = 0;
+    unsigned i;
+
+    /* Make sure we're within y-range. */
+    y -= renderer->composite_rectangles.mask.y;
+    if (y < 0 || y >= renderer->composite_rectangles.height)
+	return CAIRO_STATUS_SUCCESS;
+
+    row = (uint8_t*)(renderer->mask->data) + y*(size_t)renderer->mask->stride - xmin;
+
+    /* Find the first span within x-range. */
+    for (i=0; i < num_spans && spans[i].x < xmin; i++) {}
+    if (i>0)
+	prev_alpha = spans[i-1].coverage;
+
+    /* Set the intermediate spans. */
+    for (; i < num_spans; i++) {
+	int x = spans[i].x;
+
+	if (x >= xmax)
+	    break;
+
+	if (prev_alpha != 0) {
+	    /* We implement setting rendering the most common single
+	     * pixel wide span case to avoid the overhead of a memset
+	     * call.  Open coding setting longer spans didn't show a
+	     * noticeable improvement over memset. */
+	    if (x == prev_x + 1) {
+		row[prev_x] = prev_alpha;
+	    }
+	    else {
+		memset(row + prev_x, prev_alpha, x - prev_x);
+	    }
+	}
+
+	prev_x = x;
+	prev_alpha = spans[i].coverage;
+    }
+
+    if (prev_alpha != 0 && prev_x < xmax) {
+	memset(row + prev_x, prev_alpha, xmax - prev_x);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_image_surface_span_renderer_destroy (void *abstract_renderer)
+{
+    cairo_image_surface_span_renderer_t *renderer = abstract_renderer;
+    if (!renderer) return;
+
+    if (renderer->src != NULL) {
+	_cairo_pattern_release_surface (renderer->pattern,
+					&renderer->src->base,
+					&renderer->src_attributes);
+    }
+
+    if (renderer->mask != NULL)
+	cairo_surface_destroy (&renderer->mask->base);
+
+    free (renderer);
+}
+
+static cairo_status_t
+_cairo_image_surface_span_renderer_finish (void *abstract_renderer)
+{
+    cairo_image_surface_span_renderer_t *renderer = abstract_renderer;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+    if (renderer->src == NULL || renderer->mask == NULL)
+	return CAIRO_STATUS_SUCCESS;
+
+    status = cairo_surface_status (&renderer->mask->base);
+    if (status == CAIRO_STATUS_SUCCESS) {
+	cairo_composite_rectangles_t *rects = &renderer->composite_rectangles;
+	cairo_image_surface_t *src = renderer->src;
+	cairo_image_surface_t *dst = renderer->dst;
+	cairo_surface_attributes_t *src_attributes = &renderer->src_attributes;
+	int width = rects->width;
+	int height = rects->height;
+
+	pixman_image_composite (_pixman_operator (renderer->op),
+				src->pixman_image,
+				renderer->mask->pixman_image,
+				dst->pixman_image,
+				rects->src.x + src_attributes->x_offset,
+				rects->src.y + src_attributes->y_offset,
+				0, 0,		/* mask.x, mask.y */
+				rects->dst.x, rects->dst.y,
+				width, height);
+
+	if (! _cairo_operator_bounded_by_mask (renderer->op))
+	    status = _cairo_surface_composite_shape_fixup_unbounded (
+		&dst->base,
+		src_attributes,
+		src->width, src->height,
+		rects->width, rects->height,
+		rects->src.x, rects->src.y,
+		0, 0,		/* mask.x, mask.y */
+		rects->dst.x, rects->dst.y,
+		rects->width, rects->height);
+    }
+    if (status != CAIRO_STATUS_SUCCESS)
+	return _cairo_span_renderer_set_error (abstract_renderer,
+					       status);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_bool_t
+_cairo_image_surface_check_span_renderer (cairo_operator_t	  op,
+					  const cairo_pattern_t  *pattern,
+					  void			 *abstract_dst,
+					  cairo_antialias_t	  antialias,
+					  const cairo_composite_rectangles_t *rects)
+{
+    (void) op;
+    (void) pattern;
+    (void) abstract_dst;
+    (void) antialias;
+    (void) rects;
+    return TRUE;
+}
+
+static cairo_span_renderer_t *
+_cairo_image_surface_create_span_renderer (cairo_operator_t	 op,
+					   const cairo_pattern_t  *pattern,
+					   void			*abstract_dst,
+					   cairo_antialias_t	 antialias,
+					   const cairo_composite_rectangles_t *rects)
+{
+    cairo_image_surface_t *dst = abstract_dst;
+    cairo_image_surface_span_renderer_t *renderer
+	= calloc(1, sizeof(*renderer));
+    cairo_status_t status;
+    int width = rects->width;
+    int height = rects->height;
+
+    if (renderer == NULL)
+	return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+    renderer->base.destroy = _cairo_image_surface_span_renderer_destroy;
+    renderer->base.finish = _cairo_image_surface_span_renderer_finish;
+    renderer->base.render_row =
+	_cairo_image_surface_span_renderer_render_row;
+    renderer->op = op;
+    renderer->pattern = pattern;
+    renderer->antialias = antialias;
+    renderer->dst = dst;
+
+    renderer->composite_rectangles = *rects;
+
+    status = _cairo_pattern_acquire_surface (
+	renderer->pattern, &renderer->dst->base,
+	rects->src.x, rects->src.y,
+	width, height,
+	(cairo_surface_t **) &renderer->src,
+	&renderer->src_attributes);
+    if (status)
+	goto unwind;
+
+    status = _cairo_image_surface_set_attributes (
+	renderer->src, &renderer->src_attributes,
+	rects->dst.x + width/2, rects->dst.y + height/2);
+    if (status)
+	goto unwind;
+
+    /* TODO: support rendering to A1 surfaces (or: go add span
+     * compositing to pixman.) */
+    renderer->mask = (cairo_image_surface_t *)
+	cairo_image_surface_create (CAIRO_FORMAT_A8,
+				    width, height);
+
+    status = cairo_surface_status (&renderer->mask->base);
+
+ unwind:
+    if (status != CAIRO_STATUS_SUCCESS) {
+	_cairo_image_surface_span_renderer_destroy (renderer);
+	return _cairo_span_renderer_create_in_error (status);
+    }
+    return &renderer->base;
+}
+
 cairo_int_status_t
 _cairo_image_surface_set_clip_region (void *abstract_surface,
 				      cairo_region_t *region)
@@ -1303,8 +1496,8 @@ const cairo_surface_backend_t _cairo_image_surface_backend = {
     _cairo_image_surface_composite,
     _cairo_image_surface_fill_rectangles,
     _cairo_image_surface_composite_trapezoids,
-    NULL, /* create_span_renderer */
-    NULL, /* check_span_renderer */
+    _cairo_image_surface_create_span_renderer,
+    _cairo_image_surface_check_span_renderer,
     NULL, /* copy_page */
     NULL, /* show_page */
     _cairo_image_surface_set_clip_region,
commit 7994fc06ad66e31fcbc16f6e8cd9ad226022ec8c
Author: M Joonas Pihlaja <jpihlaja at cc.helsinki.fi>
Date:   Thu Aug 28 22:16:07 2008 +0300

    [cairo-spans] New cairo_tor_scan_converter_t.
    
    Imports a new polygon scan converter implementation from the
    repository at
    
    http://cgit.freedesktop.org/~joonas/glitter-paths/
    
    Glitter paths is a stand alone polygon rasteriser derived from David
    Turner's reimplementation of Tor Anderssons's 15x17 supersampling
    rasteriser from the Apparition graphics library.  The main new feature
    in this implementation is cheaply choosing per-scan line between doing
    fully analytical coverage computation for an entire row at a time
    vs. using a supersampling approach.

diff --git a/src/Makefile.sources b/src/Makefile.sources
index 9811650..5f387f4 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -138,6 +138,7 @@ cairo_sources = \
 	cairo-stroke-style.c \
 	cairo-surface.c \
 	cairo-surface-fallback.c \
+	cairo-tor-scan-converter.c \
 	cairo-system.c \
 	cairo-traps.c \
 	cairo-unicode.c \
diff --git a/src/cairo-spans-private.h b/src/cairo-spans-private.h
index e86d3d4..c285f94 100644
--- a/src/cairo-spans-private.h
+++ b/src/cairo-spans-private.h
@@ -96,6 +96,16 @@ struct _cairo_scan_converter {
     cairo_status_t status;
 };
 
+/* Scan converter constructors. */
+
+cairo_private cairo_scan_converter_t *
+_cairo_tor_scan_converter_create(
+    int			xmin,
+    int			ymin,
+    int			xmax,
+    int			ymax,
+    cairo_fill_rule_t	fill_rule);
+
 /* cairo-spans.c: */
 
 cairo_private cairo_scan_converter_t *
diff --git a/src/cairo-spans.c b/src/cairo-spans.c
index 4411abb..e441143 100644
--- a/src/cairo-spans.c
+++ b/src/cairo-spans.c
@@ -128,11 +128,19 @@ _create_scan_converter (cairo_fill_rule_t			 fill_rule,
 			cairo_antialias_t			 antialias,
 			const cairo_composite_rectangles_t	*rects)
 {
-    /* Until we get a scan converter implementation we're going to
-     * fail. */
-    ASSERT_NOT_REACHED;
-    return _cairo_scan_converter_create_in_error (
-	CAIRO_INT_STATUS_UNSUPPORTED);
+    if (antialias == CAIRO_ANTIALIAS_NONE) {
+	ASSERT_NOT_REACHED;
+	return _cairo_scan_converter_create_in_error (
+	    CAIRO_INT_STATUS_UNSUPPORTED);
+    }
+    else {
+	return _cairo_tor_scan_converter_create (
+	    rects->mask.x,
+	    rects->mask.y,
+	    rects->mask.x + rects->width,
+	    rects->mask.y + rects->height,
+	    fill_rule);
+    }
 }
 
 cairo_status_t
diff --git a/src/cairo-tor-scan-converter.c b/src/cairo-tor-scan-converter.c
new file mode 100644
index 0000000..20104a7
--- /dev/null
+++ b/src/cairo-tor-scan-converter.c
@@ -0,0 +1,2003 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* glitter-paths - polygon scan converter
+ *
+ * Copyright (c) 2008  M Joonas Pihlaja
+ * Copyright (c) 2007  David Turner
+ *
+ * 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.
+ */
+/* This is the Glitter paths scan converter incorporated into cairo.
+ * The source is from commit 734c53237a867a773640bd5b64816249fa1730f8
+ * of
+ *
+ *   http://gitweb.freedesktop.org/?p=users/joonas/glitter-paths
+ */
+/* Glitter-paths is a stand alone polygon rasteriser derived from
+ * David Turner's reimplementation of Tor Anderssons's 15x17
+ * supersampling rasteriser from the Apparition graphics library.  The
+ * main new feature here is cheaply choosing per-scan line between
+ * doing fully analytical coverage computation for an entire row at a
+ * time vs. using a supersampling approach.
+ *
+ * David Turner's code can be found at
+ *
+ *   http://david.freetype.org/rasterizer-shootout/raster-comparison-20070813.tar.bz2
+ *
+ * In particular this file incorporates large parts of ftgrays_tor10.h
+ * from raster-comparison-20070813.tar.bz2
+ */
+/* Overview
+ *
+ * A scan converter's basic purpose to take polygon edges and convert
+ * them into an RLE compressed A8 mask.  This one works in two phases:
+ * gathering edges and generating spans.
+ *
+ * 1) As the user feeds the scan converter edges they are vertically
+ * clipped and bucketted into a _polygon_ data structure.  The edges
+ * are also snapped from the user's coordinates to the subpixel grid
+ * coordinates used during scan conversion.
+ *
+ *     user
+ *      |
+ *      | edges
+ *      V
+ *    polygon buckets
+ *
+ * 2) Generating spans works by performing a vertical sweep of pixel
+ * rows from top to bottom and maintaining an _active_list_ of edges
+ * that intersect the row.  From the active list the fill rule
+ * determines which edges are the left and right edges of the start of
+ * each span, and their contribution is then accumulated into a pixel
+ * coverage list (_cell_list_) as coverage deltas.  Once the coverage
+ * deltas of all edges are known we can form spans of constant pixel
+ * coverage by summing the deltas during a traversal of the cell list.
+ * At the end of a pixel row the cell list is sent to a coverage
+ * blitter for rendering to some target surface.
+ *
+ * The pixel coverages are computed by either supersampling the row
+ * and box filtering a mono rasterisation, or by computing the exact
+ * coverages of edges in the active list.  The supersampling method is
+ * used whenever some edge starts or stops within the row or there are
+ * edge intersections in the row.
+ *
+ *   polygon bucket for       \
+ *   current pixel row        |
+ *      |                     |
+ *      | activate new edges  |  Repeat GRID_Y times if we
+ *      V                     \  are supersampling this row,
+ *   active list              /  or just once if we're computing
+ *      |                     |  analytical coverage.
+ *      | coverage deltas     |
+ *      V                     |
+ *   pixel coverage list     /
+ *      |
+ *      V
+ *   coverage blitter
+ */
+#include "cairoint.h"
+#include "cairo-spans-private.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+/*-------------------------------------------------------------------------
+ * cairo specific config
+ */
+#define I static
+
+/* Prefer cairo's status type. */
+#define GLITTER_HAVE_STATUS_T 1
+#define GLITTER_STATUS_SUCCESS CAIRO_STATUS_SUCCESS
+#define GLITTER_STATUS_NO_MEMORY CAIRO_STATUS_NO_MEMORY
+typedef cairo_status_t glitter_status_t;
+
+/* The input coordinate scale and the rasterisation grid scales. */
+#define GLITTER_INPUT_BITS CAIRO_FIXED_FRAC_BITS
+#define GRID_X_BITS CAIRO_FIXED_FRAC_BITS
+#define GRID_Y 15
+
+/* Set glitter up to use a cairo span renderer to do the coverage
+ * blitting. */
+struct pool;
+struct cell_list;
+
+static glitter_status_t
+blit_with_span_renderer(
+    struct cell_list		*coverages,
+    cairo_span_renderer_t	*span_renderer,
+    struct pool			*span_pool,
+    int				 y,
+    int				 xmin,
+    int				 xmax);
+
+#define GLITTER_BLIT_COVERAGES_ARGS \
+	cairo_span_renderer_t *span_renderer, \
+	struct pool *span_pool
+
+#define GLITTER_BLIT_COVERAGES(cells, y, xmin, xmax) do {		\
+    cairo_status_t status = blit_with_span_renderer (cells,		\
+						     span_renderer,	\
+						     span_pool,		\
+						     y, xmin, xmax);	\
+    if (unlikely (status))						\
+	return status;							\
+} while (0)
+
+/*-------------------------------------------------------------------------
+ * glitter-paths.h
+ */
+
+/* "Input scaled" numbers are fixed precision reals with multiplier
+ * 2**GLITTER_INPUT_BITS.  Input coordinates are given to glitter as
+ * pixel scaled numbers.  These get converted to the internal grid
+ * scaled numbers as soon as possible. Internal overflow is possible
+ * if GRID_X/Y inside glitter-paths.c is larger than
+ * 1<<GLITTER_INPUT_BITS. */
+#ifndef GLITTER_INPUT_BITS
+#  define GLITTER_INPUT_BITS 8
+#endif
+#define GLITTER_INPUT_SCALE (1<<GLITTER_INPUT_BITS)
+typedef int glitter_input_scaled_t;
+
+#if !GLITTER_HAVE_STATUS_T
+typedef enum {
+    GLITTER_STATUS_SUCCESS = 0,
+    GLITTER_STATUS_NO_MEMORY
+} glitter_status_t;
+#endif
+
+#ifndef I
+# define I /*static*/
+#endif
+
+/* Opaque type for scan converting. */
+typedef struct glitter_scan_converter glitter_scan_converter_t;
+
+/* Reset a scan converter to accept polygon edges and set the clip box
+ * in pixels.  Allocates O(ymax-ymin) bytes of memory.	The clip box
+ * is set to integer pixel coordinates xmin <= x < xmax, ymin <= y <
+ * ymax. */
+I glitter_status_t
+glitter_scan_converter_reset(
+    glitter_scan_converter_t *converter,
+    int xmin, int ymin,
+    int xmax, int ymax);
+
+/* Add a new polygon edge from pixel (x1,y1) to (x2,y2) to the scan
+ * converter.  The coordinates represent pixel positions scaled by
+ * 2**GLITTER_PIXEL_BITS.  If this function fails then the scan
+ * converter should be reset or destroyed.  Dir must be +1 or -1,
+ * with the latter reversing the orientation of the edge. */
+I glitter_status_t
+glitter_scan_converter_add_edge(
+    glitter_scan_converter_t *converter,
+    glitter_input_scaled_t x1, glitter_input_scaled_t y1,
+    glitter_input_scaled_t x2, glitter_input_scaled_t y2,
+    int dir);
+
+/* Render the polygon in the scan converter to the given A8 format
+ * image raster.  Only the pixels accessible as pixels[y*stride+x] for
+ * x,y inside the clip box are written to, where xmin <= x < xmax,
+ * ymin <= y < ymax.  The image is assumed to be clear on input.
+ *
+ * If nonzero_fill is true then the interior of the polygon is
+ * computed with the non-zero fill rule.  Otherwise the even-odd fill
+ * rule is used.
+ *
+ * The scan converter must be reset or destroyed after this call. */
+#ifndef GLITTER_BLIT_COVERAGES_ARGS
+# define GLITTER_BLIT_COVERAGES_ARGS unsigned char *raster_pixels, long raster_stride
+#endif
+I glitter_status_t
+glitter_scan_converter_render(
+    glitter_scan_converter_t *converter,
+    int nonzero_fill,
+    GLITTER_BLIT_COVERAGES_ARGS);
+
+/*-------------------------------------------------------------------------
+ * glitter-paths.c: Implementation internal types
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+/* All polygon coordinates are snapped onto a subsample grid. "Grid
+ * scaled" numbers are fixed precision reals with multiplier GRID_X or
+ * GRID_Y. */
+typedef int grid_scaled_t;
+typedef int grid_scaled_x_t;
+typedef int grid_scaled_y_t;
+
+/* Default x/y scale factors.
+ *  You can either define GRID_X/Y_BITS to get a power-of-two scale
+ *  or define GRID_X/Y separately. */
+#if !defined(GRID_X) && !defined(GRID_X_BITS)
+#  define GRID_X_BITS 8
+#endif
+#if !defined(GRID_Y) && !defined(GRID_Y_BITS)
+#  define GRID_Y 15
+#endif
+
+/* Use GRID_X/Y_BITS to define GRID_X/Y if they're available. */
+#ifdef GRID_X_BITS
+#  define GRID_X (1 << GRID_X_BITS)
+#endif
+#ifdef GRID_Y_BITS
+#  define GRID_Y (1 << GRID_Y_BITS)
+#endif
+
+/* The GRID_X_TO_INT_FRAC macro splits a grid scaled coordinate into
+ * integer and fractional parts. The integer part is floored. */
+#if defined(GRID_X_TO_INT_FRAC)
+  /* do nothing */
+#elif defined(GRID_X_BITS)
+#  define GRID_X_TO_INT_FRAC(x, i, f) \
+	_GRID_TO_INT_FRAC_shift(x, i, f, GRID_X_BITS)
+#else
+#  define GRID_X_TO_INT_FRAC(x, i, f) \
+	_GRID_TO_INT_FRAC_general(x, i, f, GRID_X)
+#endif
+
+#define _GRID_TO_INT_FRAC_general(t, i, f, m) do {	\
+    (i) = (t) / (m);					\
+    (f) = (t) % (m);					\
+    if ((f) < 0) {					\
+	--(i);						\
+	(f) += (m);					\
+    }							\
+} while (0)
+
+#define _GRID_TO_INT_FRAC_shift(t, i, f, b) do {	\
+    (f) = (t) & ((1 << (b)) - 1);			\
+    (i) = (t) >> (b);					\
+} while (0)
+
+/* A grid area is a real in [0,1] scaled by 2*GRID_X*GRID_Y.  We want
+ * to be able to represent exactly areas of subpixel trapezoids whose
+ * vertices are given in grid scaled coordinates.  The scale factor
+ * comes from needing to accurately represent the area 0.5*dx*dy of a
+ * triangle with base dx and height dy in grid scaled numbers. */
+typedef int grid_area_t;
+#define GRID_XY (2*GRID_X*GRID_Y) /* Unit area on the grid. */
+
+/* GRID_AREA_TO_ALPHA(area): map [0,GRID_XY] to [0,255]. */
+#if GRID_XY == 510
+#  define GRID_AREA_TO_ALPHA(c)	  (((c)+1) >> 1)
+#elif GRID_XY == 255
+#  define  GRID_AREA_TO_ALPHA(c)  (c)
+#elif GRID_XY == 64
+#  define  GRID_AREA_TO_ALPHA(c)  (((c) << 2) | -(((c) & 0x40) >> 6))
+#elif GRID_XY == 128
+#  define  GRID_AREA_TO_ALPHA(c)  ((((c) << 1) | -((c) >> 7)) & 255)
+#elif GRID_XY == 256
+#  define  GRID_AREA_TO_ALPHA(c)  (((c) | -((c) >> 8)) & 255)
+#elif GRID_XY == 15
+#  define  GRID_AREA_TO_ALPHA(c)  (((c) << 4) + (c))
+#elif GRID_XY == 2*256*15
+#  define  GRID_AREA_TO_ALPHA(c)  (((c) + ((c)<<4)) >> 9)
+#else
+#  define  GRID_AREA_TO_ALPHA(c)  ((c)*255 / GRID_XY) /* tweak me for rounding */
+#endif
+
+#define UNROLL3(x) x x x
+
+struct quorem {
+    int quo;
+    int rem;
+};
+
+/* Header for a chunk of memory in a memory pool. */
+struct _pool_chunk {
+    /* # bytes used in this chunk. */
+    size_t size;
+
+    /* # bytes total in this chunk */
+    size_t capacity;
+
+    /* Pointer to the previous chunk or %NULL if this is the sentinel
+     * chunk in the pool header. */
+    struct _pool_chunk *prev_chunk;
+
+    /* Actual data starts here.	 Well aligned for pointers. */
+    unsigned char data[0];
+};
+
+/* A memory pool.  This is supposed to be embedded on the stack or
+ * within some other structure.	 It may optionally be followed by an
+ * embedded array from which requests are fulfilled until
+ * malloc needs to be called to allocate a first real chunk. */
+struct pool {
+    /* Chunk we're allocating from. */
+    struct _pool_chunk *current;
+
+    /* Free list of previously allocated chunks.  All have >= default
+     * capacity. */
+    struct _pool_chunk *first_free;
+
+    /* The default capacity of a chunk. */
+    size_t default_capacity;
+
+    /* Header for the sentinel chunk.  Directly following the pool
+     * struct should be some space for embedded elements from which
+     * the sentinel chunk allocates from. */
+    struct _pool_chunk sentinel[1];
+};
+
+/* A polygon edge. */
+struct edge {
+    /* Next in y-bucket or active list. */
+    struct edge *next;
+
+    /* Current x coordinate while the edge is on the active
+     * list. Initialised to the x coordinate of the top of the
+     * edge. The quotient is in grid_scaled_x_t units and the
+     * remainder is mod dy in grid_scaled_y_t units.*/
+    struct quorem x;
+
+    /* Advance of the current x when moving down a subsample line. */
+    struct quorem dxdy;
+
+    /* Advance of the current x when moving down a full pixel
+     * row. Only initialised when the height of the edge is large
+     * enough that there's a chance the edge could be stepped by a
+     * full row's worth of subsample rows at a time. */
+    struct quorem dxdy_full;
+
+    /* The clipped y of the top of the edge. */
+    grid_scaled_y_t ytop;
+
+    /* y2-y1 after orienting the edge downwards.  */
+    grid_scaled_y_t dy;
+
+    /* Number of subsample rows remaining to scan convert of this
+     * edge. */
+    grid_scaled_y_t height_left;
+
+    /* Original sign of the edge: +1 for downwards, -1 for upwards
+     * edges.  */
+    int dir;
+};
+
+/* Number of subsample rows per y-bucket. Must be GRID_Y. */
+#define EDGE_Y_BUCKET_HEIGHT GRID_Y
+
+#define EDGE_Y_BUCKET_INDEX(y, ymin) (((y) - (ymin))/EDGE_Y_BUCKET_HEIGHT)
+
+/* A collection of sorted and vertically clipped edges of the polygon.
+ * Edges are moved from the polygon to an active list while scan
+ * converting. */
+struct polygon {
+    /* The vertical clip extents. */
+    grid_scaled_y_t ymin, ymax;
+
+    /* Array of edges all starting in the same bucket.	An edge is put
+     * into bucket EDGE_BUCKET_INDEX(edge->ytop, polygon->ymin) when
+     * it is added to the polygon. */
+    struct edge **y_buckets;
+
+    struct {
+	struct pool base[1];
+	struct edge embedded[32];
+    } edge_pool;
+};
+
+/* A cell records the effect on pixel coverage of polygon edges
+ * passing through a pixel.  It contains two accumulators of pixel
+ * coverage.
+ *
+ * Consider the effects of a polygon edge on the coverage of a pixel
+ * it intersects and that of the following one.  The coverage of the
+ * following pixel is the height of the edge multiplied by the width
+ * of the pixel, and the coverage of the pixel itself is the area of
+ * the trapezoid formed by the edge and the right side of the pixel.
+ *
+ * +-----------------------+-----------------------+
+ * |                       |                       |
+ * |                       |                       |
+ * |_______________________|_______________________|
+ * |   \...................|.......................|\
+ * |    \..................|.......................| |
+ * |     \.................|.......................| |
+ * |      \....covered.....|.......................| |
+ * |       \....area.......|.......................| } covered height
+ * |        \..............|.......................| |
+ * |uncovered\.............|.......................| |
+ * |  area    \............|.......................| |
+ * |___________\...........|.......................|/
+ * |                       |                       |
+ * |                       |                       |
+ * |                       |                       |
+ * +-----------------------+-----------------------+
+ *
+ * Since the coverage of the following pixel will always be a multiple
+ * of the width of the pixel, we can store the height of the covered
+ * area instead.  The coverage of the pixel itself is the total
+ * coverage minus the area of the uncovered area to the left of the
+ * edge.  As it's faster to compute the uncovered area we only store
+ * that and subtract it from the total coverage later when forming
+ * spans to blit.
+ *
+ * The heights and areas are signed, with left edges of the polygon
+ * having positive sign and right edges having negative sign.  When
+ * two edges intersect they swap their left/rightness so their
+ * contribution above and below the intersection point must be
+ * computed separately. */
+struct cell {
+    struct cell		*next;
+    int			 x;
+    grid_area_t		 uncovered_area;
+    grid_scaled_y_t	 covered_height;
+};
+
+/* A cell list represents the scan line sparsely as cells ordered by
+ * ascending x.  It is geared towards scanning the cells in order
+ * using an internal cursor. */
+struct cell_list {
+    /* Points to the left-most cell in the scan line. */
+    struct cell *head;
+
+    /* Cursor state for iterating through the cell list.  Points to
+     * a pointer to the current cell: either &cell_list->head or the next
+     * field of the previous cell. */
+    struct cell **cursor;
+
+    /* Cells in the cell list are owned by the cell list and are
+     * allocated from this pool.  */
+    struct {
+	struct pool base[1];
+	struct cell embedded[32];
+    } cell_pool;
+};
+
+struct cell_pair {
+    struct cell *cell1;
+    struct cell *cell2;
+};
+
+/* The active list contains edges in the current scan line ordered by
+ * the x-coordinate of the intercept of the edge and the scan line. */
+struct active_list {
+    /* Leftmost edge on the current scan line. */
+    struct edge *head;
+
+    /* A lower bound on the height of the active edges is used to
+     * estimate how soon some active edge ends.	 We can't advance the
+     * scan conversion by a full pixel row if an edge ends somewhere
+     * within it. */
+    grid_scaled_y_t min_height;
+};
+
+struct glitter_scan_converter {
+    struct polygon	polygon[1];
+    struct active_list	active[1];
+    struct cell_list	coverages[1];
+
+    /* Clip box. */
+    grid_scaled_x_t xmin, xmax;
+    grid_scaled_y_t ymin, ymax;
+};
+
+/* Compute the floored division a/b. Assumes / and % perform symmetric
+ * division. */
+inline static struct quorem
+floored_divrem(int a, int b)
+{
+    struct quorem qr;
+    qr.quo = a/b;
+    qr.rem = a%b;
+    if ((a^b)<0 && qr.rem) {
+	qr.quo -= 1;
+	qr.rem += b;
+    }
+    return qr;
+}
+
+/* Compute the floored division (x*a)/b. Assumes / and % perform symmetric
+ * division. */
+static struct quorem
+floored_muldivrem(int x, int a, int b)
+{
+    struct quorem qr;
+    long long xa = (long long)x*a;
+    qr.quo = xa/b;
+    qr.rem = xa%b;
+    if ((xa>=0) != (b>=0) && qr.rem) {
+	qr.quo -= 1;
+	qr.rem += b;
+    }
+    return qr;
+}
+
+static void
+_pool_chunk_init(
+    struct _pool_chunk *p,
+    struct _pool_chunk *prev_chunk,
+    size_t capacity)
+{
+    p->prev_chunk = prev_chunk;
+    p->size = 0;
+    p->capacity = capacity;
+}
+
+static struct _pool_chunk *
+_pool_chunk_create(
+    struct _pool_chunk *prev_chunk,
+    size_t size)
+{
+    struct _pool_chunk *p;
+    size_t size_with_head = size + sizeof(struct _pool_chunk);
+    if (size_with_head < size)
+	return NULL;
+    p = malloc(size_with_head);
+    if (p)
+	_pool_chunk_init(p, prev_chunk, size);
+    return p;
+}
+
+static void
+pool_init(
+    struct pool *pool,
+    size_t default_capacity,
+    size_t embedded_capacity)
+{
+    pool->current = pool->sentinel;
+    pool->first_free = NULL;
+    pool->default_capacity = default_capacity;
+    _pool_chunk_init(pool->sentinel, NULL, embedded_capacity);
+}
+
+static void
+pool_fini(struct pool *pool)
+{
+    struct _pool_chunk *p = pool->current;
+    do {
+	while (NULL != p) {
+	    struct _pool_chunk *prev = p->prev_chunk;
+	    if (p != pool->sentinel)
+		free(p);
+	    p = prev;
+	}
+	p = pool->first_free;
+	pool->first_free = NULL;
+    } while (NULL != p);
+    pool_init(pool, 0, 0);
+}
+
+/* Satisfy an allocation by first allocating a new large enough chunk
+ * and adding it to the head of the pool's chunk list. This function
+ * is called as a fallback if pool_alloc() couldn't do a quick
+ * allocation from the current chunk in the pool. */
+static void *
+_pool_alloc_from_new_chunk(
+    struct pool *pool,
+    size_t size)
+{
+    struct _pool_chunk *chunk;
+    void *obj;
+    size_t capacity;
+
+    /* If the allocation is smaller than the default chunk size then
+     * try getting a chunk off the free list.  Force alloc of a new
+     * chunk for large requests. */
+    capacity = size;
+    chunk = NULL;
+    if (size < pool->default_capacity) {
+	capacity = pool->default_capacity;
+	chunk = pool->first_free;
+	if (chunk) {
+	    pool->first_free = chunk->prev_chunk;
+	    _pool_chunk_init(chunk, pool->current, chunk->capacity);
+	}
+    }
+
+    if (NULL == chunk) {
+	chunk = _pool_chunk_create(
+	    pool->current,
+	    capacity);
+	if (NULL == chunk)
+	    return NULL;
+    }
+    pool->current = chunk;
+
+    obj = &chunk->data[chunk->size];
+    chunk->size += size;
+    return obj;
+}
+
+/* Allocate size bytes from the pool.  The first allocated address
+ * returned from a pool is aligned to sizeof(void*).  Subsequent
+ * addresses will maintain alignment as long as multiples of void* are
+ * allocated.  Returns the address of a new memory area or %NULL on
+ * allocation failures.	 The pool retains ownership of the returned
+ * memory. */
+inline static void *
+pool_alloc(
+    struct pool *pool,
+    size_t size)
+{
+    struct _pool_chunk *chunk = pool->current;
+
+    if (size <= chunk->capacity - chunk->size) {
+	void *obj = &chunk->data[chunk->size];
+	chunk->size += size;
+	return obj;
+    }
+    else {
+	return _pool_alloc_from_new_chunk(pool, size);
+    }
+}
+
+/* Relinquish all pool_alloced memory back to the pool. */
+static void
+pool_reset(struct pool *pool)
+{
+    /* Transfer all used chunks to the chunk free list. */
+    struct _pool_chunk *chunk = pool->current;
+    if (chunk != pool->sentinel) {
+	while (chunk->prev_chunk != pool->sentinel) {
+	    chunk = chunk->prev_chunk;
+	}
+	chunk->prev_chunk = pool->first_free;
+	pool->first_free = pool->current;
+    }
+    /* Reset the sentinel as the current chunk. */
+    pool->current = pool->sentinel;
+    pool->sentinel->size = 0;
+}
+
+/* Rewinds the cell list's cursor to the beginning.  After rewinding
+ * we're good to cell_list_find() the cell any x coordinate. */
+inline static void
+cell_list_rewind(struct cell_list *cells)
+{
+    cells->cursor = &cells->head;
+}
+
+/* Rewind the cell list if its cursor has been advanced past x. */
+inline static void
+cell_list_maybe_rewind(struct cell_list *cells, int x)
+{
+    struct cell *tail = *cells->cursor;
+    if (tail && tail->x > x) {
+	cell_list_rewind(cells);
+    }
+}
+
+static void
+cell_list_init(struct cell_list *cells)
+{
+    pool_init(cells->cell_pool.base,
+	      256*sizeof(struct cell),
+	      sizeof(cells->cell_pool.embedded));
+    cells->head = NULL;
+    cell_list_rewind(cells);
+}
+
+static void
+cell_list_fini(struct cell_list *cells)
+{
+    pool_fini(cells->cell_pool.base);
+    cell_list_init(cells);
+}
+
+/* Empty the cell list.  This is called at the start of every pixel
+ * row. */
+inline static void
+cell_list_reset(struct cell_list *cells)
+{
+    cell_list_rewind(cells);
+    cells->head = NULL;
+    pool_reset(cells->cell_pool.base);
+}
+
+/* Find a cell at the given x-coordinate.  Returns %NULL if a new cell
+ * needed to be allocated but couldn't be.  Cells must be found with
+ * non-decreasing x-coordinate until the cell list is rewound using
+ * cell_list_rewind(). Ownership of the returned cell is retained by
+ * the cell list. */
+inline static struct cell *
+cell_list_find(struct cell_list *cells, int x)
+{
+    struct cell **cursor = cells->cursor;
+    struct cell *tail;
+
+    while (1) {
+	UNROLL3({
+	    tail = *cursor;
+	    if (NULL == tail || tail->x >= x) {
+		break;
+	    }
+	    cursor = &tail->next;
+	});
+    }
+    cells->cursor = cursor;
+    if (tail && tail->x == x) {
+	return tail;
+    } else {
+	struct cell *cell = pool_alloc(
+	    cells->cell_pool.base,
+	    sizeof(struct cell));
+	if (NULL == cell)
+	    return NULL;
+	*cursor = cell;
+	cell->next = tail;
+	cell->x = x;
+	cell->uncovered_area = 0;
+	cell->covered_height = 0;
+	return cell;
+    }
+}
+
+/* Find two cells at x1 and x2.	 This is exactly equivalent
+ * to
+ *
+ *   pair.cell1 = cell_list_find(cells, x1);
+ *   pair.cell2 = cell_list_find(cells, x2);
+ *
+ * except with less function call overhead. */
+inline static struct cell_pair
+cell_list_find2(struct cell_list *cells, int x1, int x2)
+{
+    struct cell_pair pair;
+    struct cell **cursor = cells->cursor;
+    struct cell *cell1;
+    struct cell *cell2;
+    struct cell *newcell;
+
+    /* Find first cell at x1. */
+    while (1) {
+	UNROLL3({
+	    cell1 = *cursor;
+	    if (NULL == cell1 || cell1->x > x1)
+		break;
+	    if (cell1->x == x1)
+		goto found_first;
+	    cursor = &cell1->next;
+	});
+    }
+
+    /* New first cell at x1. */
+    newcell = pool_alloc(
+	cells->cell_pool.base,
+	sizeof(struct cell));
+    if (NULL != newcell) {
+	*cursor = newcell;
+	newcell->next = cell1;
+	newcell->x = x1;
+	newcell->uncovered_area = 0;
+	newcell->covered_height = 0;
+    }
+    cell1 = newcell;
+ found_first:
+
+    /* Find second cell at x2. */
+    while (1) {
+	UNROLL3({
+	    cell2 = *cursor;
+	    if (NULL == cell2 || cell2->x > x2)
+		break;
+	    if (cell2->x == x2)
+		goto found_second;
+	    cursor = &cell2->next;
+	});
+    }
+
+    /* New second cell at x2. */
+    newcell = pool_alloc(
+	cells->cell_pool.base,
+	sizeof(struct cell));
+    if (NULL != newcell) {
+	*cursor = newcell;
+	newcell->next = cell2;
+	newcell->x = x2;
+	newcell->uncovered_area = 0;
+	newcell->covered_height = 0;
+    }
+    cell2 = newcell;
+ found_second:
+
+    cells->cursor = cursor;
+    pair.cell1 = cell1;
+    pair.cell2 = cell2;
+    return pair;
+}
+
+/* Add an unbounded subpixel span covering subpixels >= x to the
+ * coverage cells. */
+static glitter_status_t
+cell_list_add_unbounded_subspan(
+    struct cell_list *cells,
+    grid_scaled_x_t x)
+{
+    struct cell *cell;
+    int ix, fx;
+
+    GRID_X_TO_INT_FRAC(x, ix, fx);
+
+    cell = cell_list_find(cells, ix);
+    if (cell) {
+	cell->uncovered_area += 2*fx;
+	cell->covered_height++;
+	return GLITTER_STATUS_SUCCESS;
+    }
+    return GLITTER_STATUS_NO_MEMORY;
+}
+
+/* Add a subpixel span covering [x1, x2) to the coverage cells. */
+inline static glitter_status_t
+cell_list_add_subspan(
+    struct cell_list *cells,
+    grid_scaled_x_t x1,
+    grid_scaled_x_t x2)
+{
+    int ix1, fx1;
+    int ix2, fx2;
+
+    GRID_X_TO_INT_FRAC(x1, ix1, fx1);
+    GRID_X_TO_INT_FRAC(x2, ix2, fx2);
+
+    if (ix1 != ix2) {
+	struct cell_pair p;
+	p = cell_list_find2(cells, ix1, ix2);
+	if (p.cell1 && p.cell2) {
+	    p.cell1->uncovered_area += 2*fx1;
+	    ++p.cell1->covered_height;
+	    p.cell2->uncovered_area -= 2*fx2;
+	    --p.cell2->covered_height;
+	    return GLITTER_STATUS_SUCCESS;
+	}
+    }
+    else {
+	struct cell *cell = cell_list_find(cells, ix1);
+	if (cell) {
+	    cell->uncovered_area += 2*(fx1-fx2);
+	    return GLITTER_STATUS_SUCCESS;
+	}
+    }
+    return GLITTER_STATUS_NO_MEMORY;
+}
+
+/* Adds the analytical coverage of an edge crossing the current pixel
+ * row to the coverage cells and advances the edge's x position to the
+ * following row.
+ *
+ * This function is only called when we know that during this pixel row:
+ *
+ * 1) The relative order of all edges on the active list doesn't
+ * change.  In particular, no edges intersect within this row to pixel
+ * precision.
+ *
+ * 2) No new edges start in this row.
+ *
+ * 3) No existing edges end mid-row.
+ *
+ * This function depends on being called with all edges from the
+ * active list in the order they appear on the list (i.e. with
+ * non-decreasing x-coordinate.)  */
+static glitter_status_t
+cell_list_render_edge(
+    struct cell_list *cells,
+    struct edge *edge,
+    int sign)
+{
+    struct quorem x1 = edge->x;
+    struct quorem x2 = x1;
+    grid_scaled_y_t y1, y2, dy;
+    grid_scaled_x_t dx;
+    int ix1, ix2;
+    grid_scaled_x_t fx1, fx2;
+
+    x2.quo += edge->dxdy_full.quo;
+    x2.rem += edge->dxdy_full.rem;
+    if (x2.rem >= 0) {
+	++x2.quo;
+	x2.rem -= edge->dy;
+    }
+    edge->x = x2;
+
+    GRID_X_TO_INT_FRAC(x1.quo, ix1, fx1);
+    GRID_X_TO_INT_FRAC(x2.quo, ix2, fx2);
+
+    /* Edge is entirely within a column? */
+    if (ix1 == ix2) {
+	/* We always know that ix1 is >= the cell list cursor in this
+	 * case due to the no-intersections precondition.  */
+	struct cell *cell = cell_list_find(cells, ix1);
+	if (NULL == cell)
+	    return GLITTER_STATUS_NO_MEMORY;
+	cell->covered_height += sign*GRID_Y;
+	cell->uncovered_area += sign*(fx1 + fx2)*GRID_Y;
+	return GLITTER_STATUS_SUCCESS;
+    }
+
+    /* Orient the edge left-to-right. */
+    dx = x2.quo - x1.quo;
+    if (dx >= 0) {
+	y1 = 0;
+	y2 = GRID_Y;
+    } else {
+	int tmp;
+	tmp = ix1; ix1 = ix2; ix2 = tmp;
+	tmp = fx1; fx1 = fx2; fx2 = tmp;
+	dx = -dx;
+	sign = -sign;
+	y1 = GRID_Y;
+	y2 = 0;
+    }
+    dy = y2 - y1;
+
+    /* Add coverage for all pixels [ix1,ix2] on this row crossed
+     * by the edge. */
+    {
+	struct cell_pair pair;
+	struct quorem y = floored_divrem((GRID_X - fx1)*dy, dx);
+
+	/* When rendering a previous edge on the active list we may
+	 * advance the cell list cursor past the leftmost pixel of the
+	 * current edge even though the two edges don't intersect.
+	 * e.g. consider two edges going down and rightwards:
+	 *
+	 *  --\_+---\_+-----+-----+----
+	 *      \_    \_    |     |
+	 *      | \_  | \_  |     |
+	 *      |   \_|   \_|     |
+	 *      |     \_    \_    |
+	 *  ----+-----+-\---+-\---+----
+	 *
+	 * The left edge touches cells past the starting cell of the
+	 * right edge.  Fortunately such cases are rare.
+	 *
+	 * The rewinding is never necessary if the current edge stays
+	 * within a single column because we've checked before calling
+	 * this function that the active list order won't change. */
+	cell_list_maybe_rewind(cells, ix1);
+
+	pair = cell_list_find2(cells, ix1, ix1+1);
+	if (!pair.cell1 || !pair.cell2)
+	    return GLITTER_STATUS_NO_MEMORY;
+
+	pair.cell1->uncovered_area += sign*y.quo*(GRID_X + fx1);
+	pair.cell1->covered_height += sign*y.quo;
+	y.quo += y1;
+
+	if (ix1+1 < ix2) {
+	    struct quorem dydx_full = floored_divrem(GRID_X*dy, dx);
+	    struct cell *cell = pair.cell2;
+
+	    ++ix1;
+	    do {
+		grid_scaled_y_t y_skip = dydx_full.quo;
+		y.rem += dydx_full.rem;
+		if (y.rem >= dx) {
+		    ++y_skip;
+		    y.rem -= dx;
+		}
+
+		y.quo += y_skip;
+
+		y_skip *= sign;
+		cell->uncovered_area += y_skip*GRID_X;
+		cell->covered_height += y_skip;
+
+		++ix1;
+		cell = cell_list_find(cells, ix1);
+		if (NULL == cell)
+		    return GLITTER_STATUS_NO_MEMORY;
+	    } while (ix1 != ix2);
+
+	    pair.cell2 = cell;
+	}
+	pair.cell2->uncovered_area += sign*(y2 - y.quo)*fx2;
+	pair.cell2->covered_height += sign*(y2 - y.quo);
+    }
+
+    return GLITTER_STATUS_SUCCESS;
+}
+
+static void
+polygon_init(struct polygon *polygon)
+{
+    polygon->ymin = polygon->ymax = 0;
+    polygon->y_buckets = NULL;
+    pool_init(polygon->edge_pool.base,
+	      (8192 - sizeof(struct _pool_chunk))/sizeof(struct edge),
+	      sizeof(polygon->edge_pool.embedded));
+}
+
+static void
+polygon_fini(struct polygon *polygon)
+{
+    free(polygon->y_buckets);
+    pool_fini(polygon->edge_pool.base);
+    polygon_init(polygon);
+}
+
+static void *
+realloc_and_clear(void *p, size_t a, size_t b)
+{
+    size_t total = a*b;
+    if (b && total / b != a)
+	return NULL;
+    p = realloc(p, total);
+    if (p)
+	memset(p, 0, total);
+    return p;
+}
+
+/* Empties the polygon of all edges. The polygon is then prepared to
+ * receive new edges and clip them to the vertical range
+ * [ymin,ymax). */
+static glitter_status_t
+polygon_reset(
+    struct polygon *polygon,
+    grid_scaled_y_t ymin,
+    grid_scaled_y_t ymax)
+{
+    void *p;
+    unsigned h = ymax - ymin;
+    unsigned num_buckets = EDGE_Y_BUCKET_INDEX(ymax + EDGE_Y_BUCKET_HEIGHT-1,
+					       ymin);
+
+    pool_reset(polygon->edge_pool.base);
+
+    if (h > 0x7FFFFFFFU - EDGE_Y_BUCKET_HEIGHT)
+	goto bail_no_mem; /* even if you could, you wouldn't want to. */
+
+    if (num_buckets > 0) {
+	p = realloc_and_clear(
+	    polygon->y_buckets,
+	    num_buckets,
+	    sizeof(struct edge*));
+	if (NULL == p)
+	    goto bail_no_mem;
+    }
+    else {
+	free(polygon->y_buckets);
+	p = NULL;
+    }
+    polygon->y_buckets = p;
+
+    polygon->ymin = ymin;
+    polygon->ymax = ymax;
+    return GLITTER_STATUS_SUCCESS;
+
+ bail_no_mem:
+    free(polygon->y_buckets);
+    polygon->y_buckets = NULL;
+    polygon->ymin = 0;
+    polygon->ymax = 0;
+    return GLITTER_STATUS_NO_MEMORY;
+}
+
+static void
+_polygon_insert_edge_into_its_y_bucket(
+    struct polygon *polygon,
+    struct edge *e)
+{
+    unsigned ix = EDGE_Y_BUCKET_INDEX(e->ytop, polygon->ymin);
+    struct edge **ptail = &polygon->y_buckets[ix];
+    e->next = *ptail;
+    *ptail = e;
+}
+
+inline static glitter_status_t
+polygon_add_edge(
+    struct polygon *polygon,
+    int x0, int y0,
+    int x1, int y1,
+    int dir)
+{
+    struct edge *e;
+    grid_scaled_x_t dx;
+    grid_scaled_y_t dy;
+    grid_scaled_y_t ytop, ybot;
+    grid_scaled_y_t ymin = polygon->ymin;
+    grid_scaled_y_t ymax = polygon->ymax;
+
+    if (y0 == y1)
+	return GLITTER_STATUS_SUCCESS;
+
+    if (y0 > y1) {
+	int tmp;
+	tmp = x0; x0 = x1; x1 = tmp;
+	tmp = y0; y0 = y1; y1 = tmp;
+	dir = -dir;
+    }
+
+    if (y0 >= ymax || y1 <= ymin)
+	return GLITTER_STATUS_SUCCESS;
+
+    e = pool_alloc(polygon->edge_pool.base,
+		   sizeof(struct edge));
+    if (NULL == e)
+	return GLITTER_STATUS_NO_MEMORY;
+
+    dx = x1 - x0;
+    dy = y1 - y0;
+    e->dy = dy;
+    e->dxdy = floored_divrem(dx, dy);
+
+    if (ymin <= y0) {
+	ytop = y0;
+	e->x.quo = x0;
+	e->x.rem = 0;
+    }
+    else {
+	ytop = ymin;
+	e->x = floored_muldivrem(ymin - y0, dx, dy);
+	e->x.quo += x0;
+    }
+
+    e->dir = dir;
+    e->ytop = ytop;
+    ybot = y1 < ymax ? y1 : ymax;
+    e->height_left = ybot - ytop;
+
+    if (e->height_left >= GRID_Y) {
+	e->dxdy_full = floored_muldivrem(GRID_Y, dx, dy);
+    }
+    else {
+	e->dxdy_full.quo = 0;
+	e->dxdy_full.rem = 0;
+    }
+
+    _polygon_insert_edge_into_its_y_bucket(polygon, e);
+
+    e->x.rem -= dy;		/* Bias the remainder for faster
+				 * edge advancement. */
+    return GLITTER_STATUS_SUCCESS;
+}
+
+static void
+active_list_reset(
+    struct active_list *active)
+{
+    active->head = NULL;
+    active->min_height = 0;
+}
+
+static void
+active_list_init(struct active_list *active)
+{
+    active_list_reset(active);
+}
+
+static void
+active_list_fini(
+    struct active_list *active)
+{
+    active_list_reset(active);
+}
+
+/* Merge the edges in an unsorted list of edges into a sorted
+ * list. The sort order is edges ascending by edge->x.quo.  Returns
+ * the new head of the sorted list. */
+static struct edge *
+merge_unsorted_edges(struct edge *sorted_head, struct edge *unsorted_head)
+{
+    struct edge *head = unsorted_head;
+    struct edge **cursor = &sorted_head;
+    int x;
+
+    while (NULL != head) {
+	struct edge *prev = *cursor;
+	struct edge *next = head->next;
+	x = head->x.quo;
+
+	if (NULL == prev || x < prev->x.quo) {
+	    cursor = &sorted_head;
+	}
+
+	while (1) {
+	    UNROLL3({
+		prev = *cursor;
+		if (NULL == prev || prev->x.quo >= x)
+		    break;
+		cursor = &prev->next;
+	    });
+	}
+
+	head->next = *cursor;
+	*cursor = head;
+
+	head = next;
+    }
+    return sorted_head;
+}
+
+/* Test if the edges on the active list can be safely advanced by a
+ * full row without intersections or any edges ending. */
+inline static int
+active_list_can_step_full_row(
+    struct active_list *active)
+{
+    /* Recomputes the minimum height of all edges on the active
+     * list if we have been dropping edges. */
+    if (active->min_height <= 0) {
+	struct edge *e = active->head;
+	int min_height = INT_MAX;
+
+	while (NULL != e) {
+	    if (e->height_left < min_height)
+		min_height = e->height_left;
+	    e = e->next;
+	}
+
+	active->min_height = min_height;
+    }
+
+    /* Check for intersections only if no edges end during the next
+     * row. */
+    if (active->min_height >= GRID_Y) {
+	grid_scaled_x_t prev_x = INT_MIN;
+	struct edge *e = active->head;
+	while (NULL != e) {
+	    struct quorem x = e->x;
+
+	    x.quo += e->dxdy_full.quo;
+	    x.rem += e->dxdy_full.rem;
+	    if (x.rem >= 0)
+		++x.quo;
+
+	    if (x.quo <= prev_x)
+		return 0;
+	    prev_x = x.quo;
+	    e = e->next;
+	}
+	return 1;
+    }
+    return 0;
+}
+
+/* Merges edges on the given subpixel row from the polygon to the
+ * active_list. */
+inline static void
+active_list_merge_edges_from_polygon(
+    struct active_list *active,
+    grid_scaled_y_t y,
+    struct polygon *polygon)
+{
+    /* Split off the edges on the current subrow and merge them into
+     * the active list. */
+    unsigned ix = EDGE_Y_BUCKET_INDEX(y, polygon->ymin);
+    int min_height = active->min_height;
+    struct edge *subrow_edges = NULL;
+    struct edge **ptail = &polygon->y_buckets[ix];
+
+    while (1) {
+	struct edge *tail = *ptail;
+	if (NULL == tail) break;
+
+	if (y == tail->ytop) {
+	    *ptail = tail->next;
+	    tail->next = subrow_edges;
+	    subrow_edges = tail;
+	    if (tail->height_left < min_height)
+		min_height = tail->height_left;
+	}
+	else {
+	    ptail = &tail->next;
+	}
+    }
+    active->head = merge_unsorted_edges(active->head, subrow_edges);
+    active->min_height = min_height;
+}
+
+/* Advance the edges on the active list by one subsample row by
+ * updating their x positions.  Drop edges from the list that end. */
+inline static void
+active_list_substep_edges(
+    struct active_list *active)
+{
+    struct edge **cursor = &active->head;
+    grid_scaled_x_t prev_x = INT_MIN;
+    struct edge *unsorted = NULL;
+
+    while (1) {
+	struct edge *edge;
+
+	UNROLL3({
+	    edge = *cursor;
+	    if (NULL == edge)
+		break;
+
+	    if (0 != --edge->height_left) {
+		edge->x.quo += edge->dxdy.quo;
+		edge->x.rem += edge->dxdy.rem;
+		if (edge->x.rem >= 0) {
+		    ++edge->x.quo;
+		    edge->x.rem -= edge->dy;
+		}
+
+		if (edge->x.quo < prev_x) {
+		    *cursor = edge->next;
+		    edge->next = unsorted;
+		    unsorted = edge;
+		} else {
+		    prev_x = edge->x.quo;
+		    cursor = &edge->next;
+		}
+
+	    } else {
+		*cursor = edge->next;
+	    }
+	});
+    }
+
+    if (unsorted)
+	active->head = merge_unsorted_edges(active->head, unsorted);
+}
+
+inline static glitter_status_t
+apply_nonzero_fill_rule_for_subrow(
+    struct active_list *active,
+    struct cell_list *coverages)
+{
+    struct edge *edge = active->head;
+    int winding = 0;
+    int xstart;
+    int xend;
+    int status;
+
+    cell_list_rewind(coverages);
+
+    while (NULL != edge) {
+	xstart = edge->x.quo;
+	winding = edge->dir;
+	while (1) {
+	    edge = edge->next;
+	    if (NULL == edge) {
+		return cell_list_add_unbounded_subspan(
+		    coverages, xstart);
+	    }
+	    winding += edge->dir;
+	    if (0 == winding)
+		break;
+	}
+
+	xend = edge->x.quo;
+	status = cell_list_add_subspan(coverages, xstart, xend);
+	if (status)
+	    return status;
+
+	edge = edge->next;
+    }
+
+    return GLITTER_STATUS_SUCCESS;
+}
+
+static glitter_status_t
+apply_evenodd_fill_rule_for_subrow(
+    struct active_list *active,
+    struct cell_list *coverages)
+{
+    struct edge *edge = active->head;
+    int xstart;
+    int xend;
+    int status;
+
+    cell_list_rewind(coverages);
+
+    while (NULL != edge) {
+	xstart = edge->x.quo;
+
+	edge = edge->next;
+	if (NULL == edge) {
+	    return cell_list_add_unbounded_subspan(
+		coverages, xstart);
+	}
+
+	xend = edge->x.quo;
+	status = cell_list_add_subspan(coverages, xstart, xend);
+	if (status)
+	    return status;
+
+	edge = edge->next;
+    }
+
+    return GLITTER_STATUS_SUCCESS;
+}
+
+static glitter_status_t
+apply_nonzero_fill_rule_and_step_edges(
+    struct active_list *active,
+    struct cell_list *coverages)
+{
+    struct edge **cursor = &active->head;
+    struct edge *left_edge;
+    int status;
+
+    left_edge = *cursor;
+    while (NULL != left_edge) {
+	struct edge *right_edge;
+	int winding = left_edge->dir;
+
+	left_edge->height_left -= GRID_Y;
+	if (left_edge->height_left) {
+	    cursor = &left_edge->next;
+	}
+	else {
+	    *cursor = left_edge->next;
+	}
+
+	while (1) {
+	    right_edge = *cursor;
+
+	    if (NULL == right_edge) {
+		return cell_list_render_edge(
+		    coverages, left_edge, +1);
+	    }
+
+	    right_edge->height_left -= GRID_Y;
+	    if (right_edge->height_left) {
+		cursor = &right_edge->next;
+	    }
+	    else {
+		*cursor = right_edge->next;
+	    }
+
+	    winding += right_edge->dir;
+	    if (0 == winding)
+		break;
+
+	    right_edge->x.quo += right_edge->dxdy_full.quo;
+	    right_edge->x.rem += right_edge->dxdy_full.rem;
+	    if (right_edge->x.rem >= 0) {
+		++right_edge->x.quo;
+		right_edge->x.rem -= right_edge->dy;
+	    }
+	}
+
+	status = cell_list_render_edge(
+	    coverages, left_edge, +1);
+	if (status)
+	    return status;
+	status = cell_list_render_edge(
+	    coverages, right_edge, -1);
+	if (status)
+	    return status;
+
+	left_edge = *cursor;
+    }
+
+    return GLITTER_STATUS_SUCCESS;
+}
+
+static glitter_status_t
+apply_evenodd_fill_rule_and_step_edges(
+    struct active_list *active,
+    struct cell_list *coverages)
+{
+    struct edge **cursor = &active->head;
+    struct edge *left_edge;
+    int status;
+
+    left_edge = *cursor;
+    while (NULL != left_edge) {
+	struct edge *right_edge;
+
+	left_edge->height_left -= GRID_Y;
+	if (left_edge->height_left) {
+	    cursor = &left_edge->next;
+	}
+	else {
+	    *cursor = left_edge->next;
+	}
+
+	right_edge = *cursor;
+
+	if (NULL == right_edge) {
+	    return cell_list_render_edge(
+		coverages, left_edge, +1);
+	}
+
+	right_edge->height_left -= GRID_Y;
+	if (right_edge->height_left) {
+	    cursor = &right_edge->next;
+	}
+	else {
+	    *cursor = right_edge->next;
+	}
+
+	status = cell_list_render_edge(
+	    coverages, left_edge, +1);
+	if (status)
+	    return status;
+	status = cell_list_render_edge(
+	    coverages, right_edge, -1);
+	if (status)
+	    return status;
+
+	left_edge = *cursor;
+    }
+
+    return GLITTER_STATUS_SUCCESS;
+}
+
+/* If the user hasn't configured a coverage blitter, use a default one
+ * that blits spans directly to an A8 raster. */
+#ifndef GLITTER_BLIT_COVERAGES
+
+inline static void
+blit_span(
+    unsigned char *row_pixels,
+    int x, unsigned len,
+    grid_area_t coverage)
+{
+    int alpha = GRID_AREA_TO_ALPHA(coverage);
+    if (1 == len) {
+	row_pixels[x] = alpha;
+    }
+    else {
+	memset(row_pixels + x, alpha, len);
+    }
+}
+
+#define GLITTER_BLIT_COVERAGES(coverages, y, xmin, xmax) \
+	blit_cells(coverages, raster_pixels + (y)*raster_stride, xmin, xmax)
+
+static void
+blit_cells(
+    struct cell_list *cells,
+    unsigned char *row_pixels,
+    int xmin, int xmax)
+{
+    struct cell *cell = cells->head;
+    int prev_x = xmin;
+    int coverage = 0;
+    if (NULL == cell)
+	return;
+
+    while (NULL != cell && cell->x < xmin) {
+	coverage += cell->covered_height;
+	cell = cell->next;
+    }
+    coverage *= GRID_X*2;
+
+    for (; NULL != cell; cell = cell->next) {
+	int x = cell->x;
+	int area;
+	if (x >= xmax)
+	    break;
+	if (x > prev_x && 0 != coverage) {
+	    blit_span(row_pixels, prev_x, x - prev_x, coverage);
+	}
+
+	coverage += cell->covered_height * GRID_X*2;
+	area = coverage - cell->uncovered_area;
+	if (area) {
+	    blit_span(row_pixels, x, 1, area);
+	}
+	prev_x = x+1;
+    }
+
+    if (0 != coverage && prev_x < xmax) {
+	blit_span(row_pixels, prev_x, xmax - prev_x, coverage);
+    }
+}
+#endif /* GLITTER_BLIT_COVERAGES */
+
+static void
+_glitter_scan_converter_init(glitter_scan_converter_t *converter)
+{
+    polygon_init(converter->polygon);
+    active_list_init(converter->active);
+    cell_list_init(converter->coverages);
+    converter->xmin=0;
+    converter->ymin=0;
+    converter->xmax=0;
+    converter->ymax=0;
+}
+
+static void
+_glitter_scan_converter_fini(glitter_scan_converter_t *converter)
+{
+    polygon_fini(converter->polygon);
+    active_list_fini(converter->active);
+    cell_list_fini(converter->coverages);
+    converter->xmin=0;
+    converter->ymin=0;
+    converter->xmax=0;
+    converter->ymax=0;
+}
+
+static grid_scaled_t
+int_to_grid_scaled(int i, int scale)
+{
+    /* Clamp to max/min representable scaled number. */
+    if (i >= 0) {
+	if (i >= INT_MAX/scale)
+	    i = INT_MAX/scale;
+    }
+    else {
+	if (i <= INT_MIN/scale)
+	    i = INT_MIN/scale;
+    }
+    return i*scale;
+}
+
+#define int_to_grid_scaled_x(x) int_to_grid_scaled((x), GRID_X)
+#define int_to_grid_scaled_y(x) int_to_grid_scaled((x), GRID_Y)
+
+I glitter_status_t
+glitter_scan_converter_reset(
+    glitter_scan_converter_t *converter,
+    int xmin, int ymin,
+    int xmax, int ymax)
+{
+    glitter_status_t status;
+
+    converter->xmin = 0; converter->xmax = 0;
+    converter->ymin = 0; converter->ymax = 0;
+
+    xmin = int_to_grid_scaled_x(xmin);
+    ymin = int_to_grid_scaled_y(ymin);
+    xmax = int_to_grid_scaled_x(xmax);
+    ymax = int_to_grid_scaled_y(ymax);
+
+    active_list_reset(converter->active);
+    cell_list_reset(converter->coverages);
+    status = polygon_reset(converter->polygon, ymin, ymax);
+    if (status)
+	return status;
+
+    converter->xmin = xmin;
+    converter->xmax = xmax;
+    converter->ymin = ymin;
+    converter->ymax = ymax;
+    return GLITTER_STATUS_SUCCESS;
+}
+
+/* INPUT_TO_GRID_X/Y (in_coord, out_grid_scaled, grid_scale)
+ *   These macros convert an input coordinate in the client's
+ *   device space to the rasterisation grid.
+ */
+/* Gah.. this bit of ugly defines INPUT_TO_GRID_X/Y so as to use
+ * shifts if possible, and something saneish if not.
+ */
+#if !defined(INPUT_TO_GRID_Y) && defined(GRID_Y_BITS) && GRID_Y_BITS <= GLITTER_INPUT_BITS
+#  define INPUT_TO_GRID_Y(in, out) (out) = (in) >> (GLITTER_INPUT_BITS - GRID_Y_BITS)
+#else
+#  define INPUT_TO_GRID_Y(in, out) INPUT_TO_GRID_general(in, out, GRID_Y)
+#endif
+
+#if !defined(INPUT_TO_GRID_X) && defined(GRID_X_BITS) && GRID_X_BITS <= GLITTER_INPUT_BITS
+#  define INPUT_TO_GRID_X(in, out) (out) = (in) >> (GLITTER_INPUT_BITS - GRID_X_BITS)
+#else
+#  define INPUT_TO_GRID_X(in, out) INPUT_TO_GRID_general(in, out, GRID_X)
+#endif
+
+#define INPUT_TO_GRID_general(in, out, grid_scale) do {		\
+	long long tmp__ = (long long)(grid_scale) * (in);	\
+	tmp__ >>= GLITTER_INPUT_BITS;				\
+	(out) = tmp__;						\
+} while (0)
+
+I glitter_status_t
+glitter_scan_converter_add_edge(
+    glitter_scan_converter_t *converter,
+    glitter_input_scaled_t x1, glitter_input_scaled_t y1,
+    glitter_input_scaled_t x2, glitter_input_scaled_t y2,
+    int dir)
+{
+    /* XXX: possible overflows if GRID_X/Y > 2**GLITTER_INPUT_BITS */
+    grid_scaled_y_t sx1, sy1;
+    grid_scaled_y_t sx2, sy2;
+
+    INPUT_TO_GRID_Y(y1, sy1);
+    INPUT_TO_GRID_Y(y2, sy2);
+    if (sy1 == sy2)
+	return GLITTER_STATUS_SUCCESS;
+
+    INPUT_TO_GRID_X(x1, sx1);
+    INPUT_TO_GRID_X(x2, sx2);
+
+    return polygon_add_edge(
+	converter->polygon, sx1, sy1, sx2, sy2, dir);
+}
+
+#ifndef GLITTER_BLIT_COVERAGES_BEGIN
+# define GLITTER_BLIT_COVERAGES_BEGIN
+#endif
+
+#ifndef GLITTER_BLIT_COVERAGES_END
+# define GLITTER_BLIT_COVERAGES_END
+#endif
+
+#ifndef GLITTER_BLIT_COVERAGES_EMPTY
+# define GLITTER_BLIT_COVERAGES_EMPTY(y, xmin, xmax)
+#endif
+
+I glitter_status_t
+glitter_scan_converter_render(
+    glitter_scan_converter_t *converter,
+    int nonzero_fill,
+    GLITTER_BLIT_COVERAGES_ARGS)
+{
+    int i;
+    int ymax_i = converter->ymax / GRID_Y;
+    int ymin_i = converter->ymin / GRID_Y;
+    int xmin_i, xmax_i;
+    int h = ymax_i - ymin_i;
+    struct polygon *polygon = converter->polygon;
+    struct cell_list *coverages = converter->coverages;
+    struct active_list *active = converter->active;
+
+    xmin_i = converter->xmin / GRID_X;
+    xmax_i = converter->xmax / GRID_X;
+    if (xmin_i >= xmax_i)
+	return GLITTER_STATUS_SUCCESS;
+
+    /* Let the coverage blitter initialise itself. */
+    GLITTER_BLIT_COVERAGES_BEGIN;
+
+    /* Render each pixel row. */
+    for (i=0; i<h; i++) {
+	int do_full_step = 0;
+	glitter_status_t status = 0;
+
+	/* Determine if we can ignore this row or use the full pixel
+	 * stepper. */
+	if (GRID_Y == EDGE_Y_BUCKET_HEIGHT
+	    && !polygon->y_buckets[i])
+	{
+	    if (!active->head) {
+		GLITTER_BLIT_COVERAGES_EMPTY(i+ymin_i, xmin_i, xmax_i);
+		continue;
+	    }
+	    do_full_step = active_list_can_step_full_row(active);
+	}
+
+	cell_list_reset(coverages);
+
+	if (do_full_step) {
+	    /* Step by a full pixel row's worth. */
+	    if (nonzero_fill) {
+		status = apply_nonzero_fill_rule_and_step_edges(
+		    active, coverages);
+	    }
+	    else {
+		status = apply_evenodd_fill_rule_and_step_edges(
+		    active, coverages);
+	    }
+	}
+	else {
+	    /* Subsample this row. */
+	    grid_scaled_y_t suby;
+	    for (suby = 0; suby < GRID_Y; suby++) {
+		grid_scaled_y_t y = (i+ymin_i)*GRID_Y + suby;
+
+		active_list_merge_edges_from_polygon(
+		    active, y, polygon);
+
+		if (nonzero_fill)
+		    status |= apply_nonzero_fill_rule_for_subrow(
+			active, coverages);
+		else
+		    status |= apply_evenodd_fill_rule_for_subrow(
+			active, coverages);
+
+		active_list_substep_edges(active);
+	    }
+	}
+
+	if (status)
+	    return status;
+
+	GLITTER_BLIT_COVERAGES(coverages, i+ymin_i, xmin_i, xmax_i);
+
+	if (!active->head) {
+	    active->min_height = INT_MAX;
+	}
+	else {
+	    active->min_height -= GRID_Y;
+	}
+    }
+
+    /* Clean up the coverage blitter. */
+    GLITTER_BLIT_COVERAGES_END;
+
+    return GLITTER_STATUS_SUCCESS;
+}
+
+/*-------------------------------------------------------------------------
+ * cairo specific implementation: the coverage blitter and
+ * scan converter subclass. */
+
+static glitter_status_t
+blit_with_span_renderer(
+    struct cell_list *cells,
+    cairo_span_renderer_t *renderer,
+    struct pool *span_pool,
+    int y,
+    int xmin,
+    int xmax)
+{
+    struct cell *cell = cells->head;
+    int prev_x = xmin;
+    int cover = 0;
+    cairo_half_open_span_t *spans;
+    unsigned num_spans;
+    if (cell == NULL)
+	return CAIRO_STATUS_SUCCESS;
+
+    /* Skip cells to the left of the clip region. */
+    while (cell != NULL && cell->x < xmin) {
+	cover += cell->covered_height;
+	cell = cell->next;
+    }
+    cover *= GRID_X*2;
+
+    /* Count number of cells remaining. */
+    {
+	struct cell *next = cell;
+	num_spans = 0;
+	while (next) {
+	    next = next->next;
+	    ++num_spans;
+	}
+	num_spans = 2*num_spans + 1;
+    }
+
+    /* Allocate enough spans for the row. */
+    pool_reset (span_pool);
+    spans = pool_alloc (span_pool, sizeof(spans[0])*num_spans);
+    if (spans == NULL)
+	return GLITTER_STATUS_NO_MEMORY;
+
+    num_spans = 0;
+
+    /* Form the spans from the coverages and areas. */
+    for (; cell != NULL; cell = cell->next) {
+	int x = cell->x;
+	int area;
+	if (x >= xmax)
+	    break;
+
+	if (x > prev_x) {
+	    spans[num_spans].x = prev_x;
+	    spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover);
+	    ++num_spans;
+	}
+
+	cover += cell->covered_height*GRID_X*2;
+	area = cover - cell->uncovered_area;
+
+	spans[num_spans].x = x;
+	spans[num_spans].coverage = GRID_AREA_TO_ALPHA (area);
+	++num_spans;
+
+	prev_x = x+1;
+    }
+
+    if (prev_x < xmax) {
+	spans[num_spans].x = prev_x;
+	spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover);
+	++num_spans;
+    }
+
+    /* Dump them into the renderer. */
+    return renderer->render_row (renderer, y, spans, num_spans);
+}
+
+struct _cairo_tor_scan_converter {
+    cairo_scan_converter_t base;
+    glitter_scan_converter_t converter[1];
+    cairo_fill_rule_t fill_rule;
+
+    struct {
+	struct pool base[1];
+	cairo_half_open_span_t embedded[32];
+    } span_pool;
+};
+
+typedef struct _cairo_tor_scan_converter cairo_tor_scan_converter_t;
+
+static void
+_cairo_tor_scan_converter_destroy(void *abstract_converter)
+{
+    cairo_tor_scan_converter_t *self = abstract_converter;
+    if (self == NULL) {
+	return;
+    }
+    _glitter_scan_converter_fini (self->converter);
+    pool_fini (self->span_pool.base);
+    free(self);
+}
+
+static cairo_status_t
+_cairo_tor_scan_converter_add_edge(
+    void		*abstract_converter,
+    cairo_fixed_t	 x1,
+    cairo_fixed_t	 y1,
+    cairo_fixed_t	 x2,
+    cairo_fixed_t	 y2)
+{
+    cairo_tor_scan_converter_t *self = abstract_converter;
+    cairo_status_t status;
+    status = glitter_scan_converter_add_edge (
+	self->converter,
+	x1, y1, x2, y2, +1);
+    if (status) {
+	return _cairo_scan_converter_set_error (self,
+						_cairo_error (status));
+    }
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_tor_scan_converter_generate(
+    void			*abstract_converter,
+    cairo_span_renderer_t	*renderer)
+{
+    cairo_tor_scan_converter_t *self = abstract_converter;
+    cairo_status_t status = glitter_scan_converter_render (
+	self->converter,
+	self->fill_rule == CAIRO_FILL_RULE_WINDING,
+	renderer,
+	self->span_pool.base);
+    if (status) {
+	return _cairo_scan_converter_set_error (self,
+						_cairo_error (status));
+    }
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_scan_converter_t *
+_cairo_tor_scan_converter_create(
+    int			xmin,
+    int			ymin,
+    int			xmax,
+    int			ymax,
+    cairo_fill_rule_t	fill_rule)
+{
+    cairo_status_t status;
+    cairo_tor_scan_converter_t *self =
+	calloc (1, sizeof(struct _cairo_tor_scan_converter));
+    if (self == NULL)
+	goto bail_nomem;
+
+    self->base.destroy = &_cairo_tor_scan_converter_destroy;
+    self->base.add_edge = &_cairo_tor_scan_converter_add_edge;
+    self->base.generate = &_cairo_tor_scan_converter_generate;
+
+    pool_init (self->span_pool.base,
+	      250 * sizeof(self->span_pool.embedded[0]),
+	      sizeof(self->span_pool.embedded));
+
+    _glitter_scan_converter_init (self->converter);
+    status = glitter_scan_converter_reset (
+	self->converter, xmin, ymin, xmax, ymax);
+    if (status != CAIRO_STATUS_SUCCESS)
+	goto bail;
+
+    self->fill_rule = fill_rule;
+
+    return &self->base;
+
+ bail:
+    self->base.destroy(&self->base);
+ bail_nomem:
+    return _cairo_scan_converter_create_in_error (CAIRO_STATUS_NO_MEMORY);
+}
commit 2078e5b20fdff76ada6e13b29b2775b7dcd35439
Author: M Joonas Pihlaja <jpihlaja at cc.helsinki.fi>
Date:   Thu Jul 31 01:58:08 2008 +0300

    [cairo-spans] New _cairo_path_fixed_fill_using_spans().
    
    Adds a helper function for backends to use for filling a path using
    spans.

diff --git a/src/cairo-spans-private.h b/src/cairo-spans-private.h
index ba10d5b..e86d3d4 100644
--- a/src/cairo-spans-private.h
+++ b/src/cairo-spans-private.h
@@ -121,4 +121,14 @@ cairo_private cairo_status_t
 _cairo_span_renderer_set_error (void *abstract_renderer,
 				cairo_status_t error);
 
+cairo_private cairo_status_t
+_cairo_path_fixed_fill_using_spans (
+    cairo_operator_t		 op,
+    const cairo_pattern_t	*pattern,
+    cairo_path_fixed_t		*path,
+    cairo_surface_t		*dst,
+    cairo_fill_rule_t		 fill_rule,
+    double			 tolerance,
+    cairo_antialias_t		 antialias,
+    const cairo_composite_rectangles_t *rects);
 #endif /* CAIRO_SPANS_PRIVATE_H */
diff --git a/src/cairo-spans.c b/src/cairo-spans.c
index 9cf351b..4411abb 100644
--- a/src/cairo-spans.c
+++ b/src/cairo-spans.c
@@ -26,6 +26,151 @@
  */
 #include "cairoint.h"
 
+typedef struct {
+    cairo_scan_converter_t *converter;
+    cairo_point_t current_point;
+    cairo_point_t first_point;
+} scan_converter_filler_t;
+
+static void
+scan_converter_filler_init (
+    scan_converter_filler_t		*filler,
+    cairo_scan_converter_t		*converter)
+{
+    filler->converter = converter;
+    filler->current_point.x = 0;
+    filler->current_point.y = 0;
+    filler->first_point = filler->current_point;
+}
+
+static cairo_status_t
+scan_converter_filler_move_to (
+    void *closure,
+    cairo_point_t *p)
+{
+    scan_converter_filler_t *filler = closure;
+    filler->current_point.x = p->x;
+    filler->current_point.y = p->y;
+    filler->first_point = filler->current_point;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+scan_converter_filler_line_to (
+    void *closure,
+    cairo_point_t *p)
+{
+    scan_converter_filler_t *filler = closure;
+    cairo_status_t status;
+    cairo_point_t to;
+
+    to.x = p->x;
+    to.y = p->y;
+
+    status = filler->converter->add_edge (
+	filler->converter,
+	filler->current_point.x, filler->current_point.y,
+	to.x, to.y);
+
+    filler->current_point = to;
+
+    return status;
+}
+
+static cairo_status_t
+scan_converter_filler_close_path (
+    void *closure)
+{
+    scan_converter_filler_t *filler = closure;
+    cairo_status_t status;
+
+    if (filler->first_point.x == filler->current_point.x &&
+	filler->first_point.y == filler->current_point.y)
+    {
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    status = filler->converter->add_edge (
+	filler->converter,
+	filler->current_point.x, filler->current_point.y,
+	filler->first_point.x, filler->first_point.y);
+
+    filler->current_point = filler->first_point;
+
+    return status;
+}
+
+static cairo_status_t
+_cairo_path_fixed_fill_to_scan_converter (
+    cairo_path_fixed_t			*path,
+    double				 tolerance,
+    cairo_scan_converter_t		*converter)
+{
+    scan_converter_filler_t filler;
+    cairo_status_t status;
+
+    scan_converter_filler_init (&filler, converter);
+
+    status = _cairo_path_fixed_interpret_flat (
+	path, CAIRO_DIRECTION_FORWARD,
+	scan_converter_filler_move_to,
+	scan_converter_filler_line_to,
+	scan_converter_filler_close_path,
+	&filler, tolerance);
+    if (status)
+	return status;
+
+    return scan_converter_filler_close_path (&filler);
+}
+
+static cairo_scan_converter_t *
+_create_scan_converter (cairo_fill_rule_t			 fill_rule,
+			cairo_antialias_t			 antialias,
+			const cairo_composite_rectangles_t	*rects)
+{
+    /* Until we get a scan converter implementation we're going to
+     * fail. */
+    ASSERT_NOT_REACHED;
+    return _cairo_scan_converter_create_in_error (
+	CAIRO_INT_STATUS_UNSUPPORTED);
+}
+
+cairo_status_t
+_cairo_path_fixed_fill_using_spans (
+    cairo_operator_t		 op,
+    const cairo_pattern_t	*pattern,
+    cairo_path_fixed_t		*path,
+    cairo_surface_t		*dst,
+    cairo_fill_rule_t		 fill_rule,
+    double			 tolerance,
+    cairo_antialias_t		 antialias,
+    const cairo_composite_rectangles_t *rects)
+{
+    cairo_status_t status;
+    cairo_span_renderer_t *renderer = _cairo_surface_create_span_renderer (
+	op, pattern, dst, antialias, rects);
+    cairo_scan_converter_t *converter = _create_scan_converter (
+	fill_rule, antialias, rects);
+
+    status = _cairo_path_fixed_fill_to_scan_converter (
+	path, tolerance, converter);
+    if (status)
+	goto BAIL;
+
+    status = converter->generate (converter, renderer);
+    if (status)
+	goto BAIL;
+
+    status = renderer->finish (renderer);
+    if (status)
+	goto BAIL;
+
+ BAIL:
+    renderer->destroy (renderer);
+    converter->destroy (converter);
+    return status;
+}
+
 static void
 _cairo_nil_destroy (void *abstract)
 {
commit 4a9b274eebe674bbc5c66dc3e33256723cdf9829
Author: M Joonas Pihlaja <jpihlaja at cc.helsinki.fi>
Date:   Fri Jul 11 00:59:47 2008 +0300

    [cairo-spans] Add a check/create_span_renderer backend methods.
    
    A surface will have the chance to use span rendering at cairo_fill()
    time by creating a renderer for a specific combination of
    pattern/dst/op before the path is scan converted.  The protocol is to
    first call check_span_renderer() to see if the surface wants to render
    with spans and then later call create_span_renderer() to create the
    renderer for real once the extents of the path are known.
    
    No backends have an implementation yet.

diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index a19ff10..50005c2 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -746,6 +746,8 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
     NULL, /* composite */
     NULL, /* fill_rectangles */
     NULL, /* composite_trapezoids */
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     NULL, /* copy_page */
     NULL, /* show_page */
     NULL, /* set_clip_region */
@@ -961,6 +963,8 @@ static const cairo_surface_backend_t cairo_null_surface_backend = {
     NULL, /* composite */
     NULL, /* fill_rectangles */
     NULL, /* composite_trapezoids */
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     NULL, /* copy_page */
     NULL, /* show_page */
     (_set_clip_region_func) _return_success, /* set_clip_region */
diff --git a/src/cairo-beos-surface.cpp b/src/cairo-beos-surface.cpp
index ec4aff0..e527272 100644
--- a/src/cairo-beos-surface.cpp
+++ b/src/cairo-beos-surface.cpp
@@ -895,6 +895,8 @@ static const struct _cairo_surface_backend cairo_beos_surface_backend = {
     _cairo_beos_surface_composite, /* composite */
     _cairo_beos_surface_fill_rectangles,
     NULL, /* composite_trapezoids */
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     NULL, /* copy_page */
     NULL, /* show_page */
     _cairo_beos_surface_set_clip_region,
diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c
index cab7104..71c4675 100644
--- a/src/cairo-directfb-surface.c
+++ b/src/cairo-directfb-surface.c
@@ -1815,6 +1815,8 @@ _cairo_directfb_surface_backend = {
 #else
         NULL,/*composite_trapezoids*/
 #endif
+        NULL, /* create_span_renderer */
+        NULL, /* check_span_renderer */
         NULL, /* copy_page */
         NULL, /* show_page */
         _cairo_directfb_surface_set_clip_region,/* set_clip_region */
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index 589e14f..f049f40 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -2293,6 +2293,8 @@ static const cairo_surface_backend_t cairo_glitz_surface_backend = {
     _cairo_glitz_surface_composite,
     _cairo_glitz_surface_fill_rectangles,
     _cairo_glitz_surface_composite_trapezoids,
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     NULL, /* copy_page */
     NULL, /* show_page */
     _cairo_glitz_surface_set_clip_region,
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 2bf4543..ef5e238 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -1303,6 +1303,8 @@ const cairo_surface_backend_t _cairo_image_surface_backend = {
     _cairo_image_surface_composite,
     _cairo_image_surface_fill_rectangles,
     _cairo_image_surface_composite_trapezoids,
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     NULL, /* copy_page */
     NULL, /* show_page */
     _cairo_image_surface_set_clip_region,
diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c
index e69df21..0f6e632 100644
--- a/src/cairo-meta-surface.c
+++ b/src/cairo-meta-surface.c
@@ -647,6 +647,8 @@ static const cairo_surface_backend_t cairo_meta_surface_backend = {
     NULL, /* composite */
     NULL, /* fill_rectangles */
     NULL, /* composite_trapezoids */
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     NULL, /* copy_page */
     NULL, /* show_page */
     NULL, /* set_clip_region */
diff --git a/src/cairo-os2-surface.c b/src/cairo-os2-surface.c
index e4cef05..02840e3 100644
--- a/src/cairo-os2-surface.c
+++ b/src/cairo-os2-surface.c
@@ -1326,6 +1326,8 @@ static const cairo_surface_backend_t cairo_os2_surface_backend = {
     NULL, /* composite */
     NULL, /* fill_rectangles */
     NULL, /* composite_trapezoids */
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     NULL, /* copy_page */
     NULL, /* show_page */
     NULL, /* set_clip_region */
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index 2b58e49..ce4e4de 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -678,6 +678,8 @@ static const cairo_surface_backend_t cairo_paginated_surface_backend = {
     NULL, /* composite */
     NULL, /* fill_rectangles */
     NULL, /* composite_trapezoids */
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     _cairo_paginated_surface_copy_page,
     _cairo_paginated_surface_show_page,
     NULL, /* set_clip_region */
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index b85a6c8..5862c4b 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -5308,6 +5308,8 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
     NULL, /* composite */
     NULL, /* fill_rectangles */
     NULL, /* composite_trapezoids */
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     NULL,  /* _cairo_pdf_surface_copy_page */
     _cairo_pdf_surface_show_page,
     NULL, /* set_clip_region */
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 9d2a7c5..a13be1d 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -3503,6 +3503,8 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = {
     NULL, /* composite */
     NULL, /* fill_rectangles */
     NULL, /* composite_trapezoids */
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     NULL, /* cairo_ps_surface_copy_page */
     _cairo_ps_surface_show_page,
     NULL, /* set_clip_region */
diff --git a/src/cairo-quartz-image-surface.c b/src/cairo-quartz-image-surface.c
index 3eee2c1..3bfd9e2 100644
--- a/src/cairo-quartz-image-surface.c
+++ b/src/cairo-quartz-image-surface.c
@@ -163,6 +163,8 @@ static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
     NULL, /* composite */
     NULL, /* fill_rectangles */
     NULL, /* composite_trapezoids */
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     NULL, /* copy_page */
     NULL, /* show_page */
     NULL, /* set_clip_region */
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 19160b4..9f6b245 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -2404,6 +2404,8 @@ static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
     NULL, /* composite */
     NULL, /* fill_rectangles */
     NULL, /* composite_trapezoids */
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     NULL, /* copy_page */
     NULL, /* show_page */
     NULL, /* set_clip_region */
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index 77a9e5f..cf2809f 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -2423,6 +2423,8 @@ _cairo_script_surface_backend = {
     NULL, /* composite */
     NULL, /* fill_rectangles */
     NULL, /* composite_trapezoids */
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     _cairo_script_surface_copy_page,
     _cairo_script_surface_show_page,
     NULL, /* set_clip_region */
diff --git a/src/cairo-sdl-surface.c b/src/cairo-sdl-surface.c
index d98566d..1f97fb4 100644
--- a/src/cairo-sdl-surface.c
+++ b/src/cairo-sdl-surface.c
@@ -357,6 +357,8 @@ static const cairo_surface_backend_t _cairo_sdl_surface_backend = {
     _cairo_sdl_surface_composite,
     NULL, /* fill rectangles */
     NULL, /* composite traps */
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     NULL, /* copy_page */
     NULL, /* show_page */
     _cairo_sdl_surface_set_clip_region,
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index dff8d9f..077af5b 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -1953,6 +1953,59 @@ _cairo_surface_composite_trapezoids (cairo_operator_t		op,
 							  traps, num_traps));
 }
 
+cairo_span_renderer_t *
+_cairo_surface_create_span_renderer (cairo_operator_t		op,
+				     const cairo_pattern_t     	*pattern,
+				     cairo_surface_t		*dst,
+				     cairo_antialias_t	        antialias,
+				     const cairo_composite_rectangles_t *rects)
+{
+    assert (! dst->is_snapshot);
+
+    if (dst->status)
+	return _cairo_span_renderer_create_in_error (dst->status);
+
+    if (dst->finished)
+	return _cairo_span_renderer_create_in_error (CAIRO_STATUS_SURFACE_FINISHED);
+
+    if (dst->backend->create_span_renderer) {
+	return dst->backend->create_span_renderer (op,
+						   pattern, dst,
+						   antialias,
+						   rects);
+    }
+    ASSERT_NOT_REACHED;
+    return _cairo_span_renderer_create_in_error (CAIRO_INT_STATUS_UNSUPPORTED);
+}
+
+cairo_bool_t
+_cairo_surface_check_span_renderer   (cairo_operator_t		op,
+				      const cairo_pattern_t     *pattern,
+				      cairo_surface_t		*dst,
+				      cairo_antialias_t	        antialias,
+				      const cairo_composite_rectangles_t *rects)
+{
+    cairo_int_status_t status;
+
+    assert (! dst->is_snapshot);
+
+    if (dst->status)
+	return FALSE;
+
+    if (dst->finished) {
+	status = _cairo_surface_set_error (dst, CAIRO_STATUS_SURFACE_FINISHED);
+	return FALSE;
+    }
+
+    if (dst->backend->check_span_renderer) {
+	return dst->backend->check_span_renderer (op,
+						  pattern, dst,
+						  antialias,
+						  rects);
+    }
+    return FALSE;
+}
+
 /**
  * cairo_surface_copy_page:
  * @surface: a #cairo_surface_t
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 8b66662..cfd9a2d 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -2422,6 +2422,8 @@ static const cairo_surface_backend_t cairo_svg_surface_backend = {
 	NULL, /* _cairo_svg_surface_composite, */
 	NULL, /* _cairo_svg_surface_fill_rectangles, */
 	NULL, /* _cairo_svg_surface_composite_trapezoids,*/
+	NULL, /* create_span_renderer */
+	NULL, /* check_span_renderer */
 	_cairo_svg_surface_copy_page,
 	_cairo_svg_surface_show_page,
 	NULL, /* set_clip_region */
diff --git a/src/cairo-type3-glyph-surface.c b/src/cairo-type3-glyph-surface.c
index ebc78dd..b3a4831 100644
--- a/src/cairo-type3-glyph-surface.c
+++ b/src/cairo-type3-glyph-surface.c
@@ -315,6 +315,8 @@ static const cairo_surface_backend_t cairo_type3_glyph_surface_backend = {
     NULL, /* composite */
     NULL, /* fill_rectangles */
     NULL, /* composite_trapezoids */
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     NULL, /* cairo_type3_glyph_surface_copy_page */
     NULL, /* _cairo_type3_glyph_surface_show_page */
     NULL, /* set_clip_region */
diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index 4133019..94927ae 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -1752,6 +1752,8 @@ static const cairo_surface_backend_t cairo_win32_printing_surface_backend = {
     NULL, /* composite */
     NULL, /* fill_rectangles */
     NULL, /* composite_trapezoids */
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     NULL, /* copy_page */
     _cairo_win32_printing_surface_show_page,
     NULL, /* set_clip_region */
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index bc66580..03a8f61 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -1982,6 +1982,8 @@ static const cairo_surface_backend_t cairo_win32_surface_backend = {
     _cairo_win32_surface_composite,
     _cairo_win32_surface_fill_rectangles,
     NULL, /* composite_trapezoids */
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     NULL, /* copy_page */
     NULL, /* show_page */
     _cairo_win32_surface_set_clip_region,
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 999f7d5..6f246f8 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -1684,6 +1684,8 @@ static const cairo_surface_backend_t cairo_xcb_surface_backend = {
     _cairo_xcb_surface_composite,
     _cairo_xcb_surface_fill_rectangles,
     _cairo_xcb_surface_composite_trapezoids,
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     NULL, /* copy_page */
     NULL, /* show_page */
     _cairo_xcb_surface_set_clip_region,
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 0e91513..68d8192 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -2446,6 +2446,8 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = {
     _cairo_xlib_surface_composite,
     _cairo_xlib_surface_fill_rectangles,
     _cairo_xlib_surface_composite_trapezoids,
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     NULL, /* copy_page */
     NULL, /* show_page */
     _cairo_xlib_surface_set_clip_region,
diff --git a/src/cairoint.h b/src/cairoint.h
index 6b26e29..cfc850e 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -634,6 +634,20 @@ struct _cairo_surface_backend {
 				 cairo_trapezoid_t	*traps,
 				 int			 num_traps);
 
+    cairo_warn cairo_span_renderer_t *
+    (*create_span_renderer)	(cairo_operator_t			 op,
+				 const cairo_pattern_t			*pattern,
+                                 void					*dst,
+                                 cairo_antialias_t			 antialias,
+                                 const cairo_composite_rectangles_t	*rects);
+
+    cairo_warn cairo_bool_t
+    (*check_span_renderer)	(cairo_operator_t			 op,
+				 const cairo_pattern_t			*pattern,
+                                 void					*dst,
+                                 cairo_antialias_t			 antialias,
+                                 const cairo_composite_rectangles_t	*rects);
+
     cairo_warn cairo_int_status_t
     (*copy_page)		(void			*surface);
 
@@ -1863,6 +1877,22 @@ _cairo_surface_composite_trapezoids (cairo_operator_t	op,
 				     cairo_trapezoid_t	*traps,
 				     int		ntraps);
 
+cairo_private cairo_span_renderer_t *
+_cairo_surface_create_span_renderer (
+        cairo_operator_t			 op,
+        const cairo_pattern_t			*pattern,
+        cairo_surface_t				*dst,
+        cairo_antialias_t			 antialias,
+        const cairo_composite_rectangles_t	*rects);
+
+cairo_private cairo_bool_t
+_cairo_surface_check_span_renderer (
+        cairo_operator_t			 op,
+        const cairo_pattern_t			*pattern,
+        cairo_surface_t				*dst,
+        cairo_antialias_t			 antialias,
+        const cairo_composite_rectangles_t	*rects);
+
 cairo_private cairo_status_t
 _cairo_surface_acquire_source_image (cairo_surface_t         *surface,
 				     cairo_image_surface_t  **image_out,
diff --git a/src/test-fallback-surface.c b/src/test-fallback-surface.c
index d20e7c9..8acd91e 100644
--- a/src/test-fallback-surface.c
+++ b/src/test-fallback-surface.c
@@ -214,6 +214,8 @@ static const cairo_surface_backend_t test_fallback_surface_backend = {
     NULL, /* composite */
     NULL, /* fill_rectangles */
     NULL, /* composite_trapezoids */
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     NULL, /* copy_page */
     NULL, /* show_page */
     NULL, /* set_clip_region */
diff --git a/src/test-meta-surface.c b/src/test-meta-surface.c
index 6ac1803..42bf6b0 100644
--- a/src/test-meta-surface.c
+++ b/src/test-meta-surface.c
@@ -313,6 +313,8 @@ static const cairo_surface_backend_t test_meta_surface_backend = {
     NULL, /* composite */
     NULL, /* fill_rectangles */
     NULL, /* composite_trapezoids */
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     NULL, /* copy_page */
     _test_meta_surface_show_page,
     NULL, /* set_clip_region */
diff --git a/src/test-paginated-surface.c b/src/test-paginated-surface.c
index 58d5b0a..4c56647 100644
--- a/src/test-paginated-surface.c
+++ b/src/test-paginated-surface.c
@@ -298,6 +298,8 @@ static const cairo_surface_backend_t test_paginated_surface_backend = {
     NULL, /* composite */
     NULL, /* fill_rectangles */
     NULL, /* composite_trapezoids */
+    NULL, /* create_span_renderer */
+    NULL, /* check_span_renderer */
     NULL, /* copy_page */
     NULL, /* show_page */
     _test_paginated_surface_set_clip_region,
commit 948c3526dcdbc440395fff4ce9bf4b7553930d92
Author: M Joonas Pihlaja <jpihlaja at cc.helsinki.fi>
Date:   Fri Oct 24 17:37:30 2008 +0300

    [cairo-spans] New abstract types for scan converting polygons.
    
    A cairo_span_renderer_t implementation can be provided by a surface if
    it wants to render paths as horizontal spans of the alpha component of
    a mask.  Its job is to composite a source pattern to the destination
    surface when given spans of alpha coverage for a row while taking care
    of backend specific clipping.
    
    A cairo_scan_converter_t takes edges of a flattened path and generates
    spans for a span renderer to render.

diff --git a/src/Makefile.sources b/src/Makefile.sources
index 5d643dc..9811650 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -81,6 +81,7 @@ cairo_private = \
 	cairo-region-private.h \
 	cairo-scaled-font-private.h \
 	cairo-skiplist-private.h \
+	cairo-spans-private.h \
 	cairo-surface-fallback-private.h \
 	cairo-surface-private.h \
 	cairo-types-private.h \
@@ -132,6 +133,7 @@ cairo_sources = \
 	cairo-scaled-font.c \
 	cairo-skiplist.c \
 	cairo-slope.c \
+	cairo-spans.c \
 	cairo-spline.c \
 	cairo-stroke-style.c \
 	cairo-surface.c \
diff --git a/src/cairo-spans-private.h b/src/cairo-spans-private.h
new file mode 100644
index 0000000..ba10d5b
--- /dev/null
+++ b/src/cairo-spans-private.h
@@ -0,0 +1,124 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright (c) 2008  M Joonas Pihlaja
+ *
+ * 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.
+ */
+#ifndef CAIRO_SPANS_PRIVATE_H
+#define CAIRO_SPANS_PRIVATE_H
+#include "cairo-types-private.h"
+#include "cairo-compiler-private.h"
+
+/* Number of bits of precision used for alpha. */
+#define CAIRO_SPANS_UNIT_COVERAGE_BITS 8
+#define CAIRO_SPANS_UNIT_COVERAGE ((1 << CAIRO_SPANS_UNIT_COVERAGE_BITS)-1)
+
+/* A structure representing an open-ended horizontal span of constant
+ * pixel coverage. */
+typedef struct _cairo_half_open_span {
+    /* The inclusive x-coordinate of the start of the span. */
+    int x;
+
+    /* The pixel coverage for the pixels to the right. */
+    int coverage;
+} cairo_half_open_span_t;
+
+/* Span renderer interface. Instances of renderers are provided by
+ * surfaces if they want to composite spans instead of trapezoids. */
+typedef struct _cairo_span_renderer cairo_span_renderer_t;
+struct _cairo_span_renderer {
+    /* Called to destroy the renderer. */
+    cairo_destroy_func_t	destroy;
+
+    /* Render the spans on row y of the source by whatever compositing
+     * method is required.  The function should ignore spans outside
+     * the bounding box set by the init() function. */
+    cairo_status_t (*render_row)(
+	void				*abstract_renderer,
+	int				 y,
+	const cairo_half_open_span_t	*coverages,
+	unsigned			 num_coverages);
+
+    /* Called after all rows have been rendered to perform whatever
+     * final rendering step is required.  This function is called just
+     * once before the renderer is destroyed. */
+    cairo_status_t (*finish)(
+	void		      *abstract_renderer);
+
+    /* Private status variable. */
+    cairo_status_t status;
+};
+
+/* Scan converter interface. */
+typedef struct _cairo_scan_converter cairo_scan_converter_t;
+struct _cairo_scan_converter {
+    /* Destroy this scan converter. */
+    cairo_destroy_func_t	destroy;
+
+    /* Add an edge to the converter. */
+    cairo_status_t
+    (*add_edge)(
+	void		*abstract_converter,
+	cairo_fixed_t	 x1,
+	cairo_fixed_t	 y1,
+	cairo_fixed_t	 x2,
+	cairo_fixed_t	 y2);
+
+    /* Generates coverage spans for rows for the added edges and calls
+     * the renderer function for each row. After generating spans the
+     * only valid thing to do with the converter is to destroy it. */
+    cairo_status_t
+    (*generate)(
+	void			*abstract_converter,
+	cairo_span_renderer_t	*renderer);
+
+    /* Private status. Read with _cairo_scan_converter_status(). */
+    cairo_status_t status;
+};
+
+/* cairo-spans.c: */
+
+cairo_private cairo_scan_converter_t *
+_cairo_scan_converter_create_in_error (cairo_status_t error);
+
+cairo_private cairo_status_t
+_cairo_scan_converter_status (void *abstract_converter);
+
+cairo_private cairo_status_t
+_cairo_scan_converter_set_error (void *abstract_converter,
+				 cairo_status_t error);
+
+cairo_private cairo_span_renderer_t *
+_cairo_span_renderer_create_in_error (cairo_status_t error);
+
+cairo_private cairo_status_t
+_cairo_span_renderer_status (void *abstract_renderer);
+
+/* Set the renderer into an error state.  This sets all the method
+ * pointers except ->destroy() of the renderer to no-op
+ * implementations that just return the error status. */
+cairo_private cairo_status_t
+_cairo_span_renderer_set_error (void *abstract_renderer,
+				cairo_status_t error);
+
+#endif /* CAIRO_SPANS_PRIVATE_H */
diff --git a/src/cairo-spans.c b/src/cairo-spans.c
new file mode 100644
index 0000000..9cf351b
--- /dev/null
+++ b/src/cairo-spans.c
@@ -0,0 +1,242 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright (c) 2008  M Joonas Pihlaja
+ *
+ * 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 "cairoint.h"
+
+static void
+_cairo_nil_destroy (void *abstract)
+{
+    (void) abstract;
+}
+
+static cairo_status_t
+_cairo_nil_scan_converter_add_edge (void *abstract_converter,
+				    cairo_fixed_t x1,
+				    cairo_fixed_t y1,
+				    cairo_fixed_t x2,
+				    cairo_fixed_t y2)
+{
+    (void) abstract_converter;
+    (void) x1;
+    (void) y1;
+    (void) x2;
+    (void) y2;
+    return _cairo_scan_converter_status (abstract_converter);
+}
+
+static cairo_status_t
+_cairo_nil_scan_converter_generate (void *abstract_converter,
+				    cairo_span_renderer_t *renderer)
+{
+    (void) abstract_converter;
+    (void) renderer;
+    return _cairo_scan_converter_status (abstract_converter);
+}
+
+cairo_status_t
+_cairo_scan_converter_status (void *abstract_converter)
+{
+    cairo_scan_converter_t *converter = abstract_converter;
+    return converter->status;
+}
+
+cairo_status_t
+_cairo_scan_converter_set_error (void *abstract_converter,
+				 cairo_status_t error)
+{
+    cairo_scan_converter_t *converter = abstract_converter;
+    if (error == CAIRO_STATUS_SUCCESS)
+	ASSERT_NOT_REACHED;
+    if (converter->status == CAIRO_STATUS_SUCCESS) {
+	converter->add_edge = _cairo_nil_scan_converter_add_edge;
+	converter->generate = _cairo_nil_scan_converter_generate;
+	converter->status = error;
+    }
+    return converter->status;
+}
+
+static void
+_cairo_nil_scan_converter_init (cairo_scan_converter_t *converter,
+				cairo_status_t status)
+{
+    converter->destroy = _cairo_nil_destroy;
+    converter->status = CAIRO_STATUS_SUCCESS;
+    status = _cairo_scan_converter_set_error (converter, status);
+}
+
+cairo_scan_converter_t *
+_cairo_scan_converter_create_in_error (cairo_status_t status)
+{
+#define RETURN_NIL {\
+	    static cairo_scan_converter_t nil;\
+	    _cairo_nil_scan_converter_init (&nil, status);\
+	    return &nil;\
+	}
+    switch (status) {
+    case CAIRO_STATUS_SUCCESS:
+	ASSERT_NOT_REACHED;
+	break;
+    case CAIRO_STATUS_INVALID_RESTORE: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_POP_GROUP: RETURN_NIL;
+    case CAIRO_STATUS_NO_CURRENT_POINT: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_MATRIX: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_STATUS: RETURN_NIL;
+    case CAIRO_STATUS_NULL_POINTER: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_STRING: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_PATH_DATA: RETURN_NIL;
+    case CAIRO_STATUS_READ_ERROR: RETURN_NIL;
+    case CAIRO_STATUS_WRITE_ERROR: RETURN_NIL;
+    case CAIRO_STATUS_SURFACE_FINISHED: RETURN_NIL;
+    case CAIRO_STATUS_SURFACE_TYPE_MISMATCH: RETURN_NIL;
+    case CAIRO_STATUS_PATTERN_TYPE_MISMATCH: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_CONTENT: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_FORMAT: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_VISUAL: RETURN_NIL;
+    case CAIRO_STATUS_FILE_NOT_FOUND: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_DASH: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_DSC_COMMENT: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_INDEX: RETURN_NIL;
+    case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE: RETURN_NIL;
+    case CAIRO_STATUS_TEMP_FILE_ERROR: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_STRIDE: RETURN_NIL;
+    case CAIRO_STATUS_FONT_TYPE_MISMATCH: RETURN_NIL;
+    case CAIRO_STATUS_USER_FONT_IMMUTABLE: RETURN_NIL;
+    case CAIRO_STATUS_USER_FONT_ERROR: RETURN_NIL;
+    case CAIRO_STATUS_NEGATIVE_COUNT: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_CLUSTERS: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_SLANT: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_WEIGHT: RETURN_NIL;
+    case CAIRO_STATUS_NO_MEMORY: RETURN_NIL;
+    default:
+	break;
+    }
+    status = CAIRO_STATUS_NO_MEMORY;
+    RETURN_NIL;
+#undef RETURN_NIL
+}
+
+static cairo_status_t
+_cairo_nil_span_renderer_render_row (
+    void				*abstract_renderer,
+    int					 y,
+    const cairo_half_open_span_t	*coverages,
+    unsigned				 num_coverages)
+{
+    (void) y;
+    (void) coverages;
+    (void) num_coverages;
+    return _cairo_span_renderer_status (abstract_renderer);
+}
+
+static cairo_status_t
+_cairo_nil_span_renderer_finish (void *abstract_renderer)
+{
+    return _cairo_span_renderer_status (abstract_renderer);
+}
+
+cairo_status_t
+_cairo_span_renderer_status (void *abstract_renderer)
+{
+    cairo_span_renderer_t *renderer = abstract_renderer;
+    return renderer->status;
+}
+
+cairo_status_t
+_cairo_span_renderer_set_error (
+    void *abstract_renderer,
+    cairo_status_t error)
+{
+    cairo_span_renderer_t *renderer = abstract_renderer;
+    if (error == CAIRO_STATUS_SUCCESS) {
+	ASSERT_NOT_REACHED;
+    }
+    if (renderer->status == CAIRO_STATUS_SUCCESS) {
+	renderer->render_row = _cairo_nil_span_renderer_render_row;
+	renderer->finish = _cairo_nil_span_renderer_finish;
+	renderer->status = error;
+    }
+    return renderer->status;
+}
+
+static void
+_cairo_nil_span_renderer_init (cairo_span_renderer_t *renderer,
+			       cairo_status_t status)
+{
+    renderer->destroy = _cairo_nil_destroy;
+    renderer->status = CAIRO_STATUS_SUCCESS;
+    status = _cairo_span_renderer_set_error (renderer, status);
+}
+
+cairo_span_renderer_t *
+_cairo_span_renderer_create_in_error (cairo_status_t status)
+{
+#define RETURN_NIL {\
+	    static cairo_span_renderer_t nil;\
+	    _cairo_nil_span_renderer_init (&nil, status);\
+	    return &nil;\
+	}
+    switch (status) {
+    case CAIRO_STATUS_SUCCESS:
+	ASSERT_NOT_REACHED;
+	break;
+    case CAIRO_STATUS_INVALID_RESTORE: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_POP_GROUP: RETURN_NIL;
+    case CAIRO_STATUS_NO_CURRENT_POINT: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_MATRIX: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_STATUS: RETURN_NIL;
+    case CAIRO_STATUS_NULL_POINTER: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_STRING: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_PATH_DATA: RETURN_NIL;
+    case CAIRO_STATUS_READ_ERROR: RETURN_NIL;
+    case CAIRO_STATUS_WRITE_ERROR: RETURN_NIL;
+    case CAIRO_STATUS_SURFACE_FINISHED: RETURN_NIL;
+    case CAIRO_STATUS_SURFACE_TYPE_MISMATCH: RETURN_NIL;
+    case CAIRO_STATUS_PATTERN_TYPE_MISMATCH: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_CONTENT: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_FORMAT: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_VISUAL: RETURN_NIL;
+    case CAIRO_STATUS_FILE_NOT_FOUND: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_DASH: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_DSC_COMMENT: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_INDEX: RETURN_NIL;
+    case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE: RETURN_NIL;
+    case CAIRO_STATUS_TEMP_FILE_ERROR: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_STRIDE: RETURN_NIL;
+    case CAIRO_STATUS_FONT_TYPE_MISMATCH: RETURN_NIL;
+    case CAIRO_STATUS_USER_FONT_IMMUTABLE: RETURN_NIL;
+    case CAIRO_STATUS_USER_FONT_ERROR: RETURN_NIL;
+    case CAIRO_STATUS_NEGATIVE_COUNT: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_CLUSTERS: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_SLANT: RETURN_NIL;
+    case CAIRO_STATUS_INVALID_WEIGHT: RETURN_NIL;
+    case CAIRO_STATUS_NO_MEMORY: RETURN_NIL;
+    default:
+	break;
+    }
+    status = CAIRO_STATUS_NO_MEMORY;
+    RETURN_NIL;
+#undef RETURN_NIL
+}
diff --git a/src/cairoint.h b/src/cairoint.h
index 4246ed9..6b26e29 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -234,6 +234,7 @@ be32_to_cpu(uint32_t v)
 #include "cairo-types-private.h"
 #include "cairo-cache-private.h"
 #include "cairo-reference-count-private.h"
+#include "cairo-spans-private.h"
 
 cairo_private void
 _cairo_box_from_doubles (cairo_box_t *box,
commit 4b227143b3daab75148cd54c9e7580d509864e0d
Author: M Joonas Pihlaja <jpihlaja at cc.helsinki.fi>
Date:   Thu Jul 31 01:54:53 2008 +0300

    [cairo-spans] Introduce a type to track which pixels combine in a compositing op.
    
    A cairo_composite_rectangles_t contains the coordinates of rectangular
    windows into each of the source pattern, mask, clip and destination
    surface containing the pixels that will combine in a compositing
    operation.  The idea is to have a uniform way to represent all the
    translations involved rather than overloading parameters like src_x/y,
    dst_x/y, etc., sometimes with different incompatible meanings across
    functions.

diff --git a/src/cairo-rectangle.c b/src/cairo-rectangle.c
index 2143f0c..9a68409 100644
--- a/src/cairo-rectangle.c
+++ b/src/cairo-rectangle.c
@@ -223,3 +223,24 @@ _cairo_box_contains_point (cairo_box_t *box, cairo_point_t *point)
 	return FALSE;
     return TRUE;
 }
+
+void
+_cairo_composite_rectangles_init(
+        cairo_composite_rectangles_t	*rects,
+        int				 all_x,
+        int				 all_y,
+        int				 width,
+        int				 height)
+{
+        rects->src.x = all_x;
+        rects->src.y = all_y;
+        rects->mask.x = all_x;
+        rects->mask.y = all_y;
+        rects->clip.x = all_x;
+        rects->clip.y = all_y;
+        rects->dst.x = all_x;
+        rects->dst.y = all_y;
+
+        rects->width = width;
+        rects->height = height;
+}
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index 6f1354d..d8d5a2c 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -252,6 +252,30 @@ typedef struct _cairo_box_int {
     cairo_point_int_t p2;
 } cairo_box_int_t;
 
+
+/* Rectangles that take part in a composite operation.
+ *
+ * This defines four translations that define which pixels of the
+ * source pattern, mask, clip and destination surface take part in a
+ * general composite operation.  The idea is that the pixels at
+ *
+ *	(i,j)+(src.x, src.y) of the source,
+ *      (i,j)+(mask.x, mask.y) of the mask,
+ *      (i,j)+(clip.x, clip.y) of the clip and
+ *      (i,j)+(dst.x, dst.y) of the destination
+ *
+ * all combine together to form the result at (i,j)+(dst.x,dst.y),
+ * for i,j ranging in [0,width) and [0,height) respectively.
+ */
+typedef struct _cairo_composite_rectangles {
+        cairo_point_int_t src;
+        cairo_point_int_t mask;
+        cairo_point_int_t clip;
+        cairo_point_int_t dst;
+        int width;
+        int height;
+} cairo_composite_rectangles_t;
+
 typedef enum _cairo_direction {
     CAIRO_DIRECTION_FORWARD,
     CAIRO_DIRECTION_REVERSE
diff --git a/src/cairoint.h b/src/cairoint.h
index 692c36a..4246ed9 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -263,6 +263,13 @@ _cairo_box_intersects_line_segment (cairo_box_t *box, cairo_line_t *line);
 cairo_private cairo_bool_t
 _cairo_box_contains_point (cairo_box_t *box, cairo_point_t *point);
 
+cairo_private void
+_cairo_composite_rectangles_init (cairo_composite_rectangles_t	*rects,
+                                  int				 all_x,
+                                  int				 all_y,
+                                  int				 width,
+                                  int				 height);
+
 /* cairo-array.c structures and functions */
 
 cairo_private void
commit a370d077bc697588b6dac2556afa0b95ff83a77d
Author: M Joonas Pihlaja <jpihlaja at cc.helsinki.fi>
Date:   Fri Jul 25 16:35:14 2008 +0300

    [path-fixed] New _cairo_path_fixed_is_region().
    
    We want to hit the current fast paths for rendering axis aligned
    rectilinear paths rather than spans, and for that we need to be able
    to identify regional paths.

diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c
index d6a3d7f..dd25bb8 100644
--- a/src/cairo-path-fixed.c
+++ b/src/cairo-path-fixed.c
@@ -1179,3 +1179,99 @@ _cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter)
 
     return FALSE;
 }
+
+/* Closure for path region testing.  Every move_to must be to integer
+ * coordinates, there must be no curves, and every line_to or
+ * close_path must represent an axis aligned line to an integer point.
+ * We're relying on the path interpreter always sending a single
+ * move_to at the start of any subpath, not receiving having any
+ * superfluous move_tos, and the path intepreter bailing with our
+ * first non-successful error. */
+typedef struct cairo_path_region_tester {
+    cairo_point_t last_move_point;
+    cairo_point_t current_point;
+} cprt_t;
+
+static cairo_status_t
+_cprt_line_to (void          *closure,
+	       cairo_point_t *p2)
+{
+    cprt_t *self = closure;
+    cairo_point_t *p1 = &self->current_point;
+    if (p2->x == p1->x) {
+	if (_cairo_fixed_is_integer(p2->y)) {
+	    *p1 = *p2;
+	    return CAIRO_STATUS_SUCCESS;
+	}
+    }
+    else if (p2->y == p1->y) {
+	if (_cairo_fixed_is_integer(p2->x)) {
+	    *p1 = *p2;
+	    return CAIRO_STATUS_SUCCESS;
+	}
+    }
+    return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_status_t
+_cprt_close_path (void *closure)
+{
+    cprt_t *self = closure;
+    return _cprt_line_to (closure, &self->last_move_point);
+}
+
+static cairo_status_t
+_cprt_move_to (void          *closure,
+	       cairo_point_t *p)
+{
+    cprt_t *self = closure;
+    cairo_status_t status = _cprt_close_path (closure);
+    if (status) return status;
+    if (_cairo_fixed_is_integer(p->x) &&
+	_cairo_fixed_is_integer(p->y))
+    {
+	self->current_point = *p;
+	self->last_move_point = *p;
+	return CAIRO_STATUS_SUCCESS;
+    }
+    return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_status_t
+_cprt_curve_to (void *closure,
+		cairo_point_t *p0,
+		cairo_point_t *p1,
+		cairo_point_t *p2)
+{
+    (void)closure;
+    (void)p0;
+    (void)p1;
+    (void)p2;
+    return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+/**
+ * Check whether the given path is representable as a region.
+ * That is, if the path contains only axis aligned lines between
+ * integer coordinates in device space.
+ */
+cairo_bool_t
+_cairo_path_fixed_is_region (cairo_path_fixed_t *path)
+{
+    cprt_t cprt;
+    cairo_status_t status;
+    if (path->has_curve_to)
+	return FALSE;
+    cprt.current_point.x = 0;
+    cprt.current_point.y = 0;
+    cprt.last_move_point.x = 0;
+    cprt.last_move_point.y = 0;
+    status = _cairo_path_fixed_interpret (path,
+					  CAIRO_DIRECTION_FORWARD,
+					  _cprt_move_to,
+					  _cprt_line_to,
+					  _cprt_curve_to,
+					  _cprt_close_path,
+					  &cprt);
+    return status == CAIRO_STATUS_SUCCESS;
+}
diff --git a/src/cairoint.h b/src/cairoint.h
index 34ea874..692c36a 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1536,6 +1536,9 @@ cairo_private cairo_bool_t
 _cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path,
 				cairo_box_t        *box);
 
+cairo_private cairo_bool_t
+_cairo_path_fixed_is_region (cairo_path_fixed_t *path);
+
 /* cairo-path-in-fill.c */
 cairo_private void
 _cairo_path_fixed_in_fill (cairo_path_fixed_t	*path,
commit 6acb8223930081f70b422ef93a49ea645c2cc12d
Author: M Joonas Pihlaja <jpihlaja at cc.helsinki.fi>
Date:   Fri Sep 12 19:32:12 2008 +0300

    [path-fixed] Avoid extra indirection when iterating already flat paths.
    
    Perform a plain iteration rather than a flattening one if the path
    knows it doesn't have any curves.

diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c
index 2f36562..d6a3d7f 100644
--- a/src/cairo-path-fixed.c
+++ b/src/cairo-path-fixed.c
@@ -930,6 +930,15 @@ _cairo_path_fixed_interpret_flat (const cairo_path_fixed_t		*path,
 {
     cpf_t flattener;
 
+    if (!path->has_curve_to) {
+	return _cairo_path_fixed_interpret (path, dir,
+					    move_to,
+					    line_to,
+					    NULL,
+					    close_path,
+					    closure);
+    }
+
     flattener.tolerance = tolerance;
     flattener.move_to = move_to;
     flattener.line_to = line_to;


More information about the cairo-commit mailing list