summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann <sandmann@redhat.com>2008-12-11 13:13:19 -0500
committerSøren Sandmann <sandmann@redhat.com>2008-12-11 13:13:19 -0500
commit51c51b8da7b49d273631ccbc3afca55b1173b051 (patch)
tree34797cfda80e9866122fd9f544beb260a359c76f
parent96012e97519bbb973ec91536428143b411158541 (diff)
parent391c6026402dee09bb34816637114cea990cd93a (diff)
Merge branch 'master' into newcoveringcovering
Conflicts: src/cairo.c
-rw-r--r--BIBLIOGRAPHY15
-rw-r--r--NEWS91
-rw-r--r--README2
-rw-r--r--boilerplate/Makefile.sources9
-rw-r--r--boilerplate/Makefile.win326
-rw-r--r--boilerplate/cairo-boilerplate-glitz-agl.c166
-rw-r--r--boilerplate/cairo-boilerplate-glitz-glx.c244
-rw-r--r--boilerplate/cairo-boilerplate-glitz-private.h6
-rw-r--r--boilerplate/cairo-boilerplate-glitz-wgl.c164
-rw-r--r--boilerplate/cairo-boilerplate-glitz.c517
-rw-r--r--boilerplate/cairo-boilerplate-pdf.c2
-rw-r--r--boilerplate/cairo-boilerplate-ps.c2
-rw-r--r--boilerplate/cairo-boilerplate-script-private.h57
-rw-r--r--boilerplate/cairo-boilerplate-script.c125
-rw-r--r--boilerplate/cairo-boilerplate-svg.c2
-rw-r--r--boilerplate/cairo-boilerplate-win32-printing.c2
-rw-r--r--boilerplate/cairo-boilerplate.c58
-rw-r--r--boilerplate/cairo-boilerplate.h1
-rw-r--r--build/Makefile.am.changelog2
-rw-r--r--build/aclocal.dolt.m42
-rw-r--r--build/configure.ac.features1
-rw-r--r--build/configure.ac.system2
-rw-r--r--configure.ac31
-rw-r--r--doc/public/tmpl/cairo-surface.sgml1
-rw-r--r--perf/Makefile.am11
-rwxr-xr-xperf/cairo-perf-diff2
-rw-r--r--perf/cairo-perf.c8
-rw-r--r--perf/cairo-perf.h4
-rw-r--r--perf/dragon.c166
-rw-r--r--perf/intersections.c97
-rw-r--r--perf/pythagoras-tree.c86
-rw-r--r--perf/spiral.c200
-rw-r--r--src/Makefile.am5
-rw-r--r--src/Makefile.sources9
-rw-r--r--src/cairo-analysis-surface.c109
-rw-r--r--src/cairo-array.c10
-rw-r--r--src/cairo-base85-stream.c3
-rw-r--r--src/cairo-bentley-ottmann.c25
-rw-r--r--src/cairo-beos-surface.cpp2
-rw-r--r--src/cairo-cache-private.h7
-rw-r--r--src/cairo-cache.c59
-rw-r--r--src/cairo-cff-subset.c298
-rw-r--r--src/cairo-clip.c207
-rw-r--r--src/cairo-compiler-private.h17
-rw-r--r--src/cairo-debug.c2
-rw-r--r--src/cairo-deflate-stream.c3
-rw-r--r--src/cairo-directfb-surface.c14
-rw-r--r--src/cairo-font-face-twin.c3
-rw-r--r--src/cairo-font-face.c31
-rw-r--r--src/cairo-ft-font.c87
-rw-r--r--src/cairo-ft-private.h3
-rw-r--r--src/cairo-glitz-surface.c695
-rw-r--r--src/cairo-gstate.c141
-rw-r--r--src/cairo-hash-private.h7
-rw-r--r--src/cairo-hash.c217
-rw-r--r--src/cairo-hull.c2
-rw-r--r--src/cairo-image-info-private.h63
-rw-r--r--src/cairo-image-info.c290
-rw-r--r--src/cairo-image-surface.c333
-rw-r--r--src/cairo-lzw.c8
-rw-r--r--src/cairo-matrix.c65
-rw-r--r--src/cairo-meta-surface-private.h1
-rw-r--r--src/cairo-meta-surface.c116
-rw-r--r--src/cairo-misc.c109
-rw-r--r--src/cairo-mutex-list-private.h1
-rw-r--r--src/cairo-os2-private.h11
-rw-r--r--src/cairo-os2-surface.c7
-rw-r--r--src/cairo-os2.h8
-rw-r--r--src/cairo-output-stream-private.h24
-rw-r--r--src/cairo-output-stream.c83
-rw-r--r--src/cairo-paginated-surface.c72
-rw-r--r--src/cairo-path-bounds.c65
-rw-r--r--src/cairo-path-fill.c114
-rw-r--r--src/cairo-path-fixed-private.h34
-rw-r--r--src/cairo-path-fixed.c455
-rw-r--r--src/cairo-path-in-fill.c262
-rw-r--r--src/cairo-path-stroke.c159
-rw-r--r--src/cairo-path.c14
-rw-r--r--src/cairo-pattern.c338
-rw-r--r--src/cairo-pdf-operators-private.h5
-rw-r--r--src/cairo-pdf-operators.c75
-rw-r--r--src/cairo-pdf-surface-private.h3
-rw-r--r--src/cairo-pdf-surface.c723
-rw-r--r--src/cairo-pdf.h24
-rw-r--r--src/cairo-pen.c266
-rw-r--r--src/cairo-png.c190
-rw-r--r--src/cairo-polygon.c25
-rw-r--r--src/cairo-ps-surface-private.h1
-rw-r--r--src/cairo-ps-surface.c360
-rw-r--r--src/cairo-quartz-image-surface.c2
-rw-r--r--src/cairo-quartz-surface.c127
-rw-r--r--src/cairo-rectangle.c21
-rw-r--r--src/cairo-region.c13
-rw-r--r--src/cairo-scaled-font-private.h9
-rw-r--r--src/cairo-scaled-font-subsets.c125
-rw-r--r--src/cairo-scaled-font.c135
-rw-r--r--src/cairo-script-surface.c2600
-rw-r--r--src/cairo-script.h74
-rw-r--r--src/cairo-sdl-surface.c9
-rw-r--r--src/cairo-skiplist.c254
-rw-r--r--src/cairo-spans-private.h144
-rw-r--r--src/cairo-spans.c395
-rw-r--r--src/cairo-spline.c127
-rw-r--r--src/cairo-stroke-style.c2
-rw-r--r--src/cairo-surface-fallback.c182
-rw-r--r--src/cairo-surface.c382
-rw-r--r--src/cairo-svg-surface.c208
-rw-r--r--src/cairo-tor-scan-converter.c2003
-rw-r--r--src/cairo-traps.c16
-rw-r--r--src/cairo-truetype-subset.c128
-rw-r--r--src/cairo-type1-fallback.c61
-rw-r--r--src/cairo-type1-subset.c86
-rw-r--r--src/cairo-type3-glyph-surface.c31
-rw-r--r--src/cairo-types-private.h48
-rw-r--r--src/cairo-user-font.c20
-rw-r--r--src/cairo-win32-printing-surface.c160
-rw-r--r--src/cairo-win32-private.h9
-rw-r--r--src/cairo-win32-surface.c15
-rw-r--r--src/cairo-xcb-surface.c6
-rw-r--r--src/cairo-xlib-display.c67
-rw-r--r--src/cairo-xlib-screen.c6
-rw-r--r--src/cairo-xlib-surface-private.h3
-rw-r--r--src/cairo-xlib-surface.c182
-rw-r--r--src/cairo-xlib-visual.c2
-rw-r--r--src/cairo-xlib-xrender-private.h18
-rw-r--r--src/cairo.c196
-rw-r--r--src/cairo.h22
-rw-r--r--src/cairoint.h238
-rwxr-xr-xsrc/check-doc-syntax.sh2
-rw-r--r--src/test-fallback-surface.c4
-rw-r--r--src/test-meta-surface.c29
-rw-r--r--src/test-paginated-surface.c29
-rw-r--r--test/Makefile.am65
-rw-r--r--test/README2
-rw-r--r--test/any2ppm.c95
-rw-r--r--test/cairo-test-runner.c124
-rw-r--r--test/cairo-test.c15
-rw-r--r--test/caps-joins-curve.c111
-rw-r--r--test/caps-joins-curve.ps.ref.pngbin0 -> 3728 bytes
-rw-r--r--test/caps-joins-curve.ref.pngbin0 -> 5132 bytes
-rw-r--r--test/caps-joins.c40
-rw-r--r--test/caps-joins.ps.ref.pngbin0 -> 2282 bytes
-rw-r--r--test/caps-joins.ps2.ref.pngbin1459 -> 0 bytes
-rw-r--r--test/caps-joins.ps3.ref.pngbin1459 -> 0 bytes
-rw-r--r--test/caps-joins.ref.pngbin1488 -> 2380 bytes
-rw-r--r--test/caps.c87
-rw-r--r--test/caps.ps.ref.pngbin0 -> 1466 bytes
-rw-r--r--test/caps.ref.pngbin0 -> 1601 bytes
-rw-r--r--test/clip-fill-rule.pdf.argb32.ref.pngbin0 -> 509 bytes
-rw-r--r--test/clip-fill-rule.rgb24.ref.pngbin380 -> 390 bytes
-rw-r--r--test/clip-fill-rule.test-fallback.rgb24.ref.pngbin0 -> 361 bytes
-rw-r--r--test/clip-fill-rule.test-paginated.rgb24.ref.pngbin0 -> 361 bytes
-rw-r--r--test/clip-fill-rule.xlib.rgb24.ref.pngbin0 -> 380 bytes
-rw-r--r--test/clip-nesting.pdf.argb32.ref.pngbin0 -> 850 bytes
-rw-r--r--test/clip-nesting.rgb24.ref.pngbin955 -> 963 bytes
-rw-r--r--test/clip-nesting.test-fallback.rgb24.ref.pngbin0 -> 936 bytes
-rw-r--r--test/clip-nesting.test-paginated.rgb24.ref.pngbin0 -> 936 bytes
-rw-r--r--test/clip-nesting.xlib.rgb24.ref.pngbin0 -> 955 bytes
-rw-r--r--test/clip-operator.pdf.argb32.ref.pngbin12125 -> 11604 bytes
-rw-r--r--test/clip-operator.pdf.rgb24.ref.pngbin7367 -> 6882 bytes
-rw-r--r--test/clip-operator.ps2.rgb24.ref.pngbin3624 -> 3736 bytes
-rw-r--r--test/clip-operator.ps3.argb32.ref.pngbin0 -> 7576 bytes
-rw-r--r--test/clip-operator.ps3.rgb24.ref.pngbin3624 -> 3736 bytes
-rw-r--r--test/clip-operator.ref.pngbin8271 -> 8210 bytes
-rw-r--r--test/clip-operator.rgb24.ref.pngbin3258 -> 3279 bytes
-rw-r--r--test/clip-operator.test-fallback.argb32.ref.pngbin0 -> 8252 bytes
-rw-r--r--test/clip-operator.test-fallback.rgb24.ref.pngbin0 -> 3241 bytes
-rw-r--r--test/clip-operator.test-paginated.argb32.ref.pngbin0 -> 8247 bytes
-rw-r--r--test/clip-operator.xlib-fallback.rgb24.ref.pngbin0 -> 3254 bytes
-rw-r--r--test/clip-operator.xlib.ref.pngbin0 -> 8271 bytes
-rw-r--r--test/clip-operator.xlib.rgb24.ref.pngbin0 -> 3258 bytes
-rw-r--r--test/clip-twice.pdf.argb32.ref.pngbin0 -> 1498 bytes
-rw-r--r--test/clip-twice.ref.pngbin1362 -> 1342 bytes
-rw-r--r--test/clip-twice.rgb24.ref.pngbin1198 -> 1203 bytes
-rw-r--r--test/clip-twice.test-fallback.argb32.ref.pngbin0 -> 1343 bytes
-rw-r--r--test/clip-twice.test-fallback.rgb24.ref.pngbin0 -> 1179 bytes
-rw-r--r--test/clip-twice.test-paginated.argb32.ref.pngbin0 -> 1361 bytes
-rw-r--r--test/clip-twice.test-paginated.rgb24.ref.pngbin0 -> 1199 bytes
-rw-r--r--test/clip-twice.xlib.ref.pngbin0 -> 1362 bytes
-rw-r--r--test/clip-twice.xlib.rgb24.ref.pngbin0 -> 1198 bytes
-rw-r--r--test/clipped-group.pdf.argb32.ref.pngbin0 -> 298 bytes
-rw-r--r--test/clipped-group.pdf.rgb24.ref.pngbin0 -> 298 bytes
-rw-r--r--test/dash-curve.ref.pngbin39642 -> 39696 bytes
-rw-r--r--test/degenerate-arc.ref.pngbin616 -> 544 bytes
-rw-r--r--test/degenerate-arc.test-fallback.argb32.ref.pngbin0 -> 547 bytes
-rw-r--r--test/degenerate-arc.test-fallback.rgb24.ref.pngbin0 -> 547 bytes
-rw-r--r--test/degenerate-arc.xlib.ref.pngbin0 -> 616 bytes
-rw-r--r--test/device-offset-fractional.pdf.argb32.ref.pngbin0 -> 275 bytes
-rw-r--r--test/device-offset-fractional.pdf.rgb24.ref.pngbin0 -> 275 bytes
-rw-r--r--test/device-offset-positive.c1
-rw-r--r--test/extend-pad-border.c95
-rw-r--r--test/extend-pad-border.ref.pngbin0 -> 616 bytes
-rw-r--r--test/extend-pad-similar.c82
-rw-r--r--test/extend-pad-similar.ref.pngbin0 -> 315 bytes
-rw-r--r--test/extend-pad.c50
-rw-r--r--test/extend-pad.ref.pngbin616 -> 315 bytes
-rw-r--r--test/fill-alpha-pattern.pdf.argb32.ref.pngbin3887 -> 3750 bytes
-rw-r--r--test/fill-alpha-pattern.pdf.rgb24.ref.pngbin3840 -> 3758 bytes
-rw-r--r--test/fill-alpha-pattern.ps3.argb32.ref.pngbin0 -> 4070 bytes
-rw-r--r--test/fill-alpha-pattern.ps3.rgb24.ref.pngbin0 -> 4473 bytes
-rw-r--r--test/fill-alpha-pattern.ref.pngbin3653 -> 3374 bytes
-rw-r--r--test/fill-alpha-pattern.test-fallback.argb32.ref.pngbin0 -> 3379 bytes
-rw-r--r--test/fill-alpha-pattern.test-fallback.rgb24.ref.pngbin0 -> 3379 bytes
-rw-r--r--test/fill-alpha-pattern.xlib.ref.pngbin0 -> 3653 bytes
-rw-r--r--test/fill-alpha.ref.pngbin2989 -> 2728 bytes
-rw-r--r--test/fill-alpha.test-fallback.argb32.ref.pngbin0 -> 2824 bytes
-rw-r--r--test/fill-alpha.test-fallback.rgb24.ref.pngbin0 -> 2824 bytes
-rw-r--r--test/fill-alpha.xlib.ref.pngbin0 -> 2989 bytes
-rw-r--r--test/fill-degenerate-sort-order.ref.pngbin2397 -> 2406 bytes
-rw-r--r--test/fill-degenerate-sort-order.rgb24.ref.pngbin2060 -> 2052 bytes
-rw-r--r--test/fill-degenerate-sort-order.test-fallback.argb32.ref.pngbin0 -> 2378 bytes
-rw-r--r--test/fill-degenerate-sort-order.test-fallback.rgb24.ref.pngbin0 -> 2041 bytes
-rw-r--r--test/fill-degenerate-sort-order.xlib.ref.pngbin0 -> 2397 bytes
-rw-r--r--test/fill-degenerate-sort-order.xlib.rgb24.ref.pngbin0 -> 2060 bytes
-rw-r--r--test/fill-missed-stop.pdf.argb32.ref.pngbin0 -> 452 bytes
-rw-r--r--test/fill-rule.ref.pngbin1979 -> 2061 bytes
-rw-r--r--test/fill-rule.rgb24.ref.pngbin1722 -> 1780 bytes
-rw-r--r--test/fill-rule.test-fallback.argb32.ref.pngbin0 -> 1979 bytes
-rw-r--r--test/fill-rule.test-fallback.rgb24.ref.pngbin0 -> 1703 bytes
-rw-r--r--test/fill-rule.xlib.ref.pngbin0 -> 1979 bytes
-rw-r--r--test/fill-rule.xlib.rgb24.ref.pngbin0 -> 1722 bytes
-rw-r--r--test/filter-nearest-offset.pdf.argb32.ref.pngbin0 -> 4295 bytes
-rw-r--r--test/filter-nearest-offset.pdf.rgb24.ref.pngbin0 -> 4295 bytes
-rw-r--r--test/filter-nearest-transformed.pdf.argb32.ref.pngbin0 -> 488 bytes
-rw-r--r--test/filter-nearest-transformed.pdf.rgb24.ref.pngbin0 -> 488 bytes
-rw-r--r--test/finer-grained-fallbacks.ps2.argb32.ref.pngbin0 -> 1173 bytes
-rw-r--r--test/finer-grained-fallbacks.ps2.rgb24.ref.pngbin1096 -> 1154 bytes
-rw-r--r--test/finer-grained-fallbacks.ps3.argb32.ref.pngbin0 -> 1173 bytes
-rw-r--r--test/finer-grained-fallbacks.ps3.rgb24.ref.pngbin1096 -> 1154 bytes
-rw-r--r--test/finer-grained-fallbacks.ref.pngbin1111 -> 1069 bytes
-rw-r--r--test/finer-grained-fallbacks.rgb24.ref.pngbin1114 -> 839 bytes
-rw-r--r--test/finer-grained-fallbacks.test-fallback.argb32.ref.pngbin0 -> 1111 bytes
-rw-r--r--test/finer-grained-fallbacks.test-fallback.rgb24.ref.pngbin0 -> 854 bytes
-rw-r--r--test/finer-grained-fallbacks.xlib.ref.pngbin0 -> 1111 bytes
-rw-r--r--test/finer-grained-fallbacks.xlib.rgb24.ref.pngbin0 -> 1114 bytes
-rw-r--r--test/font-matrix-translation.svg11.argb32.ref.pngbin0 -> 857 bytes
-rw-r--r--test/font-matrix-translation.svg11.rgb24.ref.pngbin0 -> 857 bytes
-rw-r--r--test/font-matrix-translation.svg12.argb32.ref.pngbin0 -> 857 bytes
-rw-r--r--test/font-matrix-translation.svg12.rgb24.ref.pngbin0 -> 857 bytes
-rw-r--r--test/ft-show-glyphs-table.svg11.argb32.ref.pngbin0 -> 9953 bytes
-rw-r--r--test/ft-show-glyphs-table.svg11.rgb24.ref.pngbin0 -> 9953 bytes
-rw-r--r--test/ft-show-glyphs-table.svg12.argb32.ref.pngbin0 -> 9953 bytes
-rw-r--r--test/ft-show-glyphs-table.svg12.rgb24.ref.pngbin0 -> 9953 bytes
-rw-r--r--test/ft-text-vertical-layout-type1.pdf.argb32.ref.pngbin0 -> 3632 bytes
-rw-r--r--test/ft-text-vertical-layout-type1.pdf.rgb24.ref.pngbin0 -> 3632 bytes
-rw-r--r--test/ft-text-vertical-layout-type1.ref.pngbin3980 -> 3643 bytes
-rw-r--r--test/ft-text-vertical-layout-type1.svg11.argb32.ref.pngbin0 -> 3614 bytes
-rw-r--r--test/ft-text-vertical-layout-type1.svg11.rgb24.ref.pngbin0 -> 3614 bytes
-rw-r--r--test/ft-text-vertical-layout-type1.svg12.argb32.ref.pngbin0 -> 3614 bytes
-rw-r--r--test/ft-text-vertical-layout-type1.svg12.rgb24.ref.pngbin0 -> 3614 bytes
-rw-r--r--test/ft-text-vertical-layout-type1.test-fallback.argb32.ref.pngbin0 -> 3639 bytes
-rw-r--r--test/ft-text-vertical-layout-type1.test-fallback.rgb24.ref.pngbin0 -> 3639 bytes
-rw-r--r--test/ft-text-vertical-layout-type1.xlib.ref.pngbin0 -> 3980 bytes
-rw-r--r--test/ft-text-vertical-layout-type3.pdf.argb32.ref.pngbin0 -> 3642 bytes
-rw-r--r--test/ft-text-vertical-layout-type3.pdf.rgb24.ref.pngbin0 -> 3642 bytes
-rw-r--r--test/ft-text-vertical-layout-type3.ref.pngbin3934 -> 3609 bytes
-rw-r--r--test/ft-text-vertical-layout-type3.svg11.argb32.ref.pngbin0 -> 3640 bytes
-rw-r--r--test/ft-text-vertical-layout-type3.svg11.rgb24.ref.pngbin0 -> 3640 bytes
-rw-r--r--test/ft-text-vertical-layout-type3.svg12.argb32.ref.pngbin0 -> 3640 bytes
-rw-r--r--test/ft-text-vertical-layout-type3.svg12.rgb24.ref.pngbin0 -> 3640 bytes
-rw-r--r--test/ft-text-vertical-layout-type3.test-fallback.argb32.ref.pngbin0 -> 3605 bytes
-rw-r--r--test/ft-text-vertical-layout-type3.test-fallback.rgb24.ref.pngbin0 -> 3605 bytes
-rw-r--r--test/ft-text-vertical-layout-type3.xlib.ref.pngbin0 -> 3934 bytes
-rw-r--r--test/glitz-surface-source.c96
-rw-r--r--test/glitz-surface-source.ps2.ref.pngbin0 -> 376 bytes
-rw-r--r--test/glitz-surface-source.ps3.ref.pngbin0 -> 376 bytes
-rw-r--r--test/huge-pattern.pdf.argb32.ref.pngbin0 -> 2430 bytes
-rw-r--r--test/imagediff.c17
-rw-r--r--test/in-fill-trapezoid.c156
-rw-r--r--test/jp2.jp2bin0 -> 2999 bytes
-rw-r--r--test/jpeg.jpgbin0 -> 2316 bytes
-rw-r--r--test/linear-gradient.pdf.argb32.ref.pngbin0 -> 1112 bytes
-rw-r--r--test/linear-gradient.pdf.rgb24.ref.pngbin0 -> 1112 bytes
-rw-r--r--test/linear-gradient.ref.pngbin1021 -> 983 bytes
-rw-r--r--test/linear-gradient.svg11.argb32.ref.pngbin0 -> 988 bytes
-rw-r--r--test/linear-gradient.svg11.rgb24.ref.pngbin0 -> 988 bytes
-rw-r--r--test/linear-gradient.svg12.argb32.ref.pngbin0 -> 988 bytes
-rw-r--r--test/linear-gradient.svg12.rgb24.ref.pngbin0 -> 988 bytes
-rw-r--r--test/linear-gradient.test-fallback.argb32.ref.pngbin0 -> 923 bytes
-rw-r--r--test/linear-gradient.test-fallback.rgb24.ref.pngbin0 -> 923 bytes
-rw-r--r--test/linear-gradient.xlib.ref.pngbin0 -> 1021 bytes
-rw-r--r--test/mask-alpha.ref.pngbin640 -> 643 bytes
-rw-r--r--test/mask-alpha.svg11.argb32.ref.pngbin615 -> 642 bytes
-rw-r--r--test/mask-alpha.svg11.rgb24.ref.pngbin0 -> 592 bytes
-rw-r--r--test/mask-alpha.svg12.argb32.ref.pngbin615 -> 642 bytes
-rw-r--r--test/mask-alpha.svg12.rgb24.ref.pngbin0 -> 592 bytes
-rw-r--r--test/mask-alpha.test-fallback.argb32.ref.pngbin0 -> 627 bytes
-rw-r--r--test/mask-alpha.xlib.ref.pngbin0 -> 640 bytes
-rw-r--r--test/mask-alpha.xlib.rgb24.ref.pngbin0 -> 599 bytes
-rw-r--r--test/mask.pdf.argb32.ref.pngbin8881 -> 9903 bytes
-rw-r--r--test/mask.pdf.rgb24.ref.pngbin8267 -> 8735 bytes
-rw-r--r--test/mask.ref.pngbin8476 -> 8581 bytes
-rw-r--r--test/mask.rgb24.ref.pngbin7041 -> 7216 bytes
-rw-r--r--test/mask.svg11.argb32.ref.pngbin8527 -> 8682 bytes
-rw-r--r--test/mask.svg11.rgb24.ref.pngbin7935 -> 7203 bytes
-rw-r--r--test/mask.svg12.argb32.ref.pngbin8527 -> 8682 bytes
-rw-r--r--test/mask.svg12.rgb24.ref.pngbin7935 -> 7203 bytes
-rw-r--r--test/mask.test-fallback.argb32.ref.pngbin0 -> 8457 bytes
-rw-r--r--test/mask.test-fallback.rgb24.ref.pngbin0 -> 7058 bytes
-rw-r--r--test/mask.xlib-fallback.rgb24.ref.pngbin0 -> 7216 bytes
-rw-r--r--test/mask.xlib.ref.pngbin0 -> 8476 bytes
-rw-r--r--test/mask.xlib.rgb24.ref.pngbin0 -> 7041 bytes
-rw-r--r--test/meta-surface-pattern.pdf.argb32.ref.pngbin0 -> 4011 bytes
-rw-r--r--test/meta-surface-pattern.pdf.rgb24.ref.pngbin4009 -> 3910 bytes
-rw-r--r--test/meta-surface-pattern.svg11.argb32.ref.pngbin3924 -> 3924 bytes
-rw-r--r--test/meta-surface-pattern.svg11.rgb24.ref.pngbin4593 -> 3914 bytes
-rw-r--r--test/meta-surface-pattern.svg12.argb32.ref.pngbin3924 -> 3924 bytes
-rw-r--r--test/meta-surface-pattern.svg12.rgb24.ref.pngbin4593 -> 3914 bytes
-rw-r--r--test/mime-data.c142
-rw-r--r--test/mime-data.pdf.ref.pngbin0 -> 6482 bytes
-rw-r--r--test/mime-data.ps.ref.pngbin0 -> 4554 bytes
-rw-r--r--test/mime-data.ref.pngbin0 -> 185 bytes
-rw-r--r--test/mime-data.script.ref.pngbin0 -> 1982 bytes
-rw-r--r--test/mime-data.svg.ref.pngbin0 -> 6264 bytes
-rw-r--r--test/operator-clear.pdf.argb32.ref.pngbin1614 -> 1607 bytes
-rw-r--r--test/operator-clear.ps2.argb32.ref.pngbin0 -> 1156 bytes
-rw-r--r--test/operator-clear.ps3.argb32.ref.pngbin0 -> 1156 bytes
-rw-r--r--test/operator-source.pdf.argb32.ref.pngbin5149 -> 5112 bytes
-rw-r--r--test/operator-source.pdf.rgb24.ref.pngbin4354 -> 4186 bytes
-rw-r--r--test/operator-source.ref.pngbin4420 -> 4425 bytes
-rw-r--r--test/operator-source.rgb24.ref.pngbin3201 -> 3231 bytes
-rw-r--r--test/operator-source.test-fallback.argb32.ref.pngbin0 -> 4401 bytes
-rw-r--r--test/operator-source.test-fallback.rgb24.ref.pngbin0 -> 3200 bytes
-rw-r--r--test/operator-source.xlib-fallback.rgb24.ref.pngbin0 -> 3193 bytes
-rw-r--r--test/operator-source.xlib.ref.pngbin0 -> 4420 bytes
-rw-r--r--test/operator-source.xlib.rgb24.ref.pngbin0 -> 3201 bytes
-rw-r--r--test/over-above-source.ps2.argb32.ref.pngbin636 -> 558 bytes
-rw-r--r--test/over-above-source.ps3.argb32.ref.pngbin636 -> 558 bytes
-rw-r--r--test/over-above-source.ref.pngbin538 -> 560 bytes
-rw-r--r--test/over-above-source.rgb24.ref.pngbin461 -> 466 bytes
-rw-r--r--test/over-above-source.test-fallback.argb32.ref.pngbin0 -> 533 bytes
-rw-r--r--test/over-above-source.test-fallback.rgb24.ref.pngbin0 -> 450 bytes
-rw-r--r--test/over-above-source.xlib.ref.pngbin0 -> 538 bytes
-rw-r--r--test/over-above-source.xlib.rgb24.ref.pngbin0 -> 461 bytes
-rw-r--r--test/over-around-source.pdf.argb32.ref.pngbin0 -> 585 bytes
-rw-r--r--test/over-around-source.ps2.argb32.ref.pngbin632 -> 522 bytes
-rw-r--r--test/over-around-source.ps3.argb32.ref.pngbin632 -> 522 bytes
-rw-r--r--test/over-around-source.ref.pngbin614 -> 645 bytes
-rw-r--r--test/over-around-source.test-fallback.argb32.ref.pngbin0 -> 610 bytes
-rw-r--r--test/over-around-source.xlib.ref.pngbin0 -> 614 bytes
-rw-r--r--test/over-around-source.xlib.rgb24.ref.pngbin0 -> 503 bytes
-rw-r--r--test/over-below-source.pdf.argb32.ref.pngbin0 -> 464 bytes
-rw-r--r--test/over-between-source.ps2.argb32.ref.pngbin678 -> 551 bytes
-rw-r--r--test/over-between-source.ps3.argb32.ref.pngbin678 -> 551 bytes
-rw-r--r--test/over-between-source.ref.pngbin575 -> 612 bytes
-rw-r--r--test/over-between-source.test-fallback.argb32.ref.pngbin0 -> 578 bytes
-rw-r--r--test/over-between-source.xlib.ref.pngbin0 -> 575 bytes
-rw-r--r--test/over-between-source.xlib.rgb24.ref.pngbin0 -> 473 bytes
-rw-r--r--test/pdf-mime-data.c173
-rw-r--r--test/pdf2png.c32
-rw-r--r--test/png.pngbin0 -> 2096 bytes
-rw-r--r--test/push-group.pdf.argb32.ref.pngbin0 -> 2722 bytes
-rw-r--r--test/push-group.pdf.rgb24.ref.pngbin2714 -> 2740 bytes
-rw-r--r--test/push-group.ref.pngbin3126 -> 3060 bytes
-rw-r--r--test/push-group.rgb24.ref.pngbin2961 -> 2912 bytes
-rw-r--r--test/push-group.svg11.argb32.ref.pngbin2935 -> 3034 bytes
-rw-r--r--test/push-group.svg12.argb32.ref.pngbin2935 -> 3034 bytes
-rw-r--r--test/push-group.test-fallback.argb32.ref.pngbin0 -> 3107 bytes
-rw-r--r--test/push-group.test-fallback.rgb24.ref.pngbin0 -> 2942 bytes
-rw-r--r--test/push-group.xlib-fallback.rgb24.ref.pngbin0 -> 2912 bytes
-rw-r--r--test/push-group.xlib.ref.pngbin0 -> 3126 bytes
-rw-r--r--test/push-group.xlib.rgb24.ref.pngbin0 -> 2961 bytes
-rw-r--r--test/quartz-surface-source.c42
-rw-r--r--test/quartz-surface-source.ps2.ref.pngbin0 -> 376 bytes
-rw-r--r--test/quartz-surface-source.ps3.ref.pngbin0 -> 376 bytes
-rw-r--r--test/quartz-surface-source.ref.pngbin0 -> 332 bytes
-rw-r--r--test/radial-gradient.pdf.argb32.ref.pngbin0 -> 79601 bytes
-rw-r--r--test/radial-gradient.pdf.rgb24.ref.pngbin0 -> 79601 bytes
-rw-r--r--test/random-intersections.ref.pngbin148722 -> 133462 bytes
-rw-r--r--test/random-intersections.test-fallback.argb32.ref.pngbin0 -> 132312 bytes
-rw-r--r--test/random-intersections.test-fallback.rgb24.ref.pngbin0 -> 132312 bytes
-rw-r--r--test/random-intersections.xlib.ref.pngbin0 -> 148722 bytes
-rw-r--r--test/romedalen.jpgbin0 -> 11400 bytes
-rw-r--r--test/rotate-image-surface-paint.pdf.argb32.ref.pngbin209 -> 215 bytes
-rw-r--r--test/rotate-image-surface-paint.pdf.rgb24.ref.pngbin207 -> 215 bytes
-rw-r--r--test/rotate-image-surface-paint.ref.pngbin232 -> 190 bytes
-rw-r--r--test/scale-offset-image.c142
-rw-r--r--test/scale-offset-image.ps.ref.pngbin0 -> 7289 bytes
-rw-r--r--test/scale-offset-image.ref.pngbin0 -> 9953 bytes
-rw-r--r--test/scale-offset-similar.c143
-rw-r--r--test/scale-offset-similar.ps.ref.pngbin0 -> 7860 bytes
-rw-r--r--test/scale-offset-similar.ref.pngbin0 -> 9953 bytes
-rw-r--r--test/scarab.jpgbin0 -> 9650 bytes
-rw-r--r--test/smask-fill.pdf.argb32.ref.pngbin0 -> 1909 bytes
-rw-r--r--test/smask-fill.pdf.rgb24.ref.pngbin0 -> 1909 bytes
-rw-r--r--test/smask-fill.ref.pngbin1223 -> 1156 bytes
-rw-r--r--test/smask-fill.svg11.argb32.ref.pngbin0 -> 1128 bytes
-rw-r--r--test/smask-fill.svg11.rgb24.ref.pngbin0 -> 1128 bytes
-rw-r--r--test/smask-fill.svg12.argb32.ref.pngbin0 -> 1128 bytes
-rw-r--r--test/smask-fill.svg12.rgb24.ref.pngbin0 -> 1128 bytes
-rw-r--r--test/smask-fill.test-fallback.argb32.ref.pngbin0 -> 1148 bytes
-rw-r--r--test/smask-fill.test-fallback.rgb24.ref.pngbin0 -> 1148 bytes
-rw-r--r--test/smask-fill.xlib-fallback.ref.pngbin0 -> 1156 bytes
-rw-r--r--test/smask-fill.xlib.ref.pngbin0 -> 1223 bytes
-rw-r--r--test/smask-image-mask.pdf.argb32.ref.pngbin0 -> 1651 bytes
-rw-r--r--test/smask-image-mask.pdf.rgb24.ref.pngbin0 -> 1651 bytes
-rw-r--r--test/smask-mask.pdf.argb32.ref.pngbin0 -> 4398 bytes
-rw-r--r--test/smask-mask.pdf.rgb24.ref.pngbin0 -> 4398 bytes
-rw-r--r--test/smask-paint.pdf.argb32.ref.pngbin0 -> 4496 bytes
-rw-r--r--test/smask-paint.pdf.rgb24.ref.pngbin0 -> 4496 bytes
-rw-r--r--test/smask-stroke.pdf.argb32.ref.pngbin0 -> 1417 bytes
-rw-r--r--test/smask-stroke.pdf.rgb24.ref.pngbin0 -> 1417 bytes
-rw-r--r--test/smask-text.svg11.argb32.ref.pngbin0 -> 1791 bytes
-rw-r--r--test/smask-text.svg11.rgb24.ref.pngbin0 -> 1791 bytes
-rw-r--r--test/smask-text.svg12.argb32.ref.pngbin0 -> 1791 bytes
-rw-r--r--test/smask-text.svg12.rgb24.ref.pngbin0 -> 1791 bytes
-rw-r--r--test/smask.pdf.argb32.ref.pngbin0 -> 4496 bytes
-rw-r--r--test/smask.pdf.rgb24.ref.pngbin0 -> 4496 bytes
-rw-r--r--test/surface-pattern-scale-down.pdf.argb32.ref.pngbin2386 -> 1532 bytes
-rw-r--r--test/surface-pattern-scale-down.pdf.rgb24.ref.pngbin2386 -> 1532 bytes
-rw-r--r--test/surface-pattern-scale-up.pdf.argb32.ref.pngbin4247 -> 3834 bytes
-rw-r--r--test/surface-pattern-scale-up.pdf.rgb24.ref.pngbin4247 -> 3834 bytes
-rw-r--r--test/surface-pattern.pdf.argb32.ref.pngbin0 -> 14808 bytes
-rw-r--r--test/surface-pattern.pdf.ref.pngbin15996 -> 14791 bytes
-rw-r--r--test/surface-pattern.pdf.rgb24.ref.pngbin0 -> 14808 bytes
-rw-r--r--test/surface-pattern.ref.pngbin11439 -> 11100 bytes
-rw-r--r--test/surface-pattern.svg.ref.pngbin0 -> 16069 bytes
-rw-r--r--test/surface-pattern.svg11.ref.pngbin17663 -> 0 bytes
-rw-r--r--test/surface-pattern.svg12.ref.pngbin17663 -> 0 bytes
-rw-r--r--test/text-pattern.pdf.argb32.ref.pngbin1823 -> 2151 bytes
-rw-r--r--test/text-pattern.svg11.argb32.ref.pngbin1733 -> 1743 bytes
-rw-r--r--test/text-pattern.svg12.argb32.ref.pngbin1733 -> 1743 bytes
-rw-r--r--test/text-rotate.svg11.argb32.ref.pngbin0 -> 16942 bytes
-rw-r--r--test/text-rotate.svg11.rgb24.ref.pngbin0 -> 16942 bytes
-rw-r--r--test/text-rotate.svg12.argb32.ref.pngbin0 -> 16942 bytes
-rw-r--r--test/text-rotate.svg12.rgb24.ref.pngbin0 -> 16942 bytes
-rw-r--r--test/text-transform.svg11.argb32.ref.pngbin0 -> 5677 bytes
-rw-r--r--test/text-transform.svg11.rgb24.ref.pngbin0 -> 5677 bytes
-rw-r--r--test/text-transform.svg12.argb32.ref.pngbin0 -> 5677 bytes
-rw-r--r--test/text-transform.svg12.rgb24.ref.pngbin0 -> 5677 bytes
-rw-r--r--test/trap-clip.pdf.argb32.ref.pngbin5809 -> 6720 bytes
-rw-r--r--test/trap-clip.pdf.rgb24.ref.pngbin5768 -> 6621 bytes
-rw-r--r--test/trap-clip.ps2.argb32.ref.pngbin5690 -> 4849 bytes
-rw-r--r--test/trap-clip.ref.pngbin5772 -> 5829 bytes
-rw-r--r--test/trap-clip.rgb24.ref.pngbin5365 -> 5457 bytes
-rw-r--r--test/trap-clip.test-fallback.argb32.ref.pngbin0 -> 5753 bytes
-rw-r--r--test/trap-clip.test-fallback.rgb24.ref.pngbin0 -> 5379 bytes
-rw-r--r--test/trap-clip.test-paginated.argb32.ref.pngbin0 -> 5865 bytes
-rw-r--r--test/trap-clip.xlib.ref.pngbin0 -> 5772 bytes
-rw-r--r--test/trap-clip.xlib.rgb24.ref.pngbin0 -> 5365 bytes
-rw-r--r--test/twin.c2
-rw-r--r--test/twin.pdf.ref.pngbin0 -> 1673 bytes
-rw-r--r--test/twin.ps2.ref.pngbin1167 -> 1095 bytes
-rw-r--r--test/twin.ps3.ref.pngbin1167 -> 1095 bytes
-rw-r--r--test/twin.ref.pngbin1836 -> 1718 bytes
-rw-r--r--test/twin.svg11.argb32.ref.pngbin0 -> 1797 bytes
-rw-r--r--test/twin.svg11.ref.pngbin1773 -> 1662 bytes
-rw-r--r--test/twin.svg11.rgb24.ref.pngbin0 -> 1797 bytes
-rw-r--r--test/twin.svg12.argb32.ref.pngbin0 -> 1797 bytes
-rw-r--r--test/twin.svg12.ref.pngbin1773 -> 1662 bytes
-rw-r--r--test/twin.svg12.rgb24.ref.pngbin0 -> 1797 bytes
-rw-r--r--test/unbounded-operator.pdf.argb32.ref.pngbin0 -> 2713 bytes
-rw-r--r--test/unbounded-operator.ps2.argb32.ref.pngbin0 -> 2713 bytes
-rw-r--r--test/unbounded-operator.ps3.argb32.ref.pngbin0 -> 2713 bytes
-rw-r--r--test/unbounded-operator.rgb24.ref.pngbin1315 -> 1341 bytes
-rw-r--r--test/unbounded-operator.test-fallback.rgb24.ref.pngbin0 -> 1306 bytes
-rw-r--r--test/unbounded-operator.xlib.rgb24.ref.pngbin0 -> 1315 bytes
-rw-r--r--test/user-font-proxy.pdf.argb32.ref.pngbin0 -> 16937 bytes
-rw-r--r--test/user-font-proxy.pdf.rgb24.ref.pngbin0 -> 16937 bytes
-rw-r--r--test/user-font-proxy.ref.pngbin18121 -> 16937 bytes
-rw-r--r--test/user-font-proxy.svg11.argb32.ref.pngbin0 -> 16836 bytes
-rw-r--r--test/user-font-proxy.svg11.rgb24.ref.pngbin0 -> 16836 bytes
-rw-r--r--test/user-font-proxy.svg12.argb32.ref.pngbin0 -> 16836 bytes
-rw-r--r--test/user-font-proxy.svg12.rgb24.ref.pngbin0 -> 16836 bytes
-rw-r--r--test/user-font-proxy.test-fallback.argb32.ref.pngbin0 -> 16835 bytes
-rw-r--r--test/user-font-proxy.test-fallback.rgb24.ref.pngbin0 -> 16835 bytes
-rw-r--r--test/user-font-proxy.xlib.ref.pngbin0 -> 18121 bytes
-rw-r--r--test/user-font.ref.pngbin6183 -> 6082 bytes
-rw-r--r--test/user-font.svg11.argb32.ref.pngbin0 -> 6411 bytes
-rw-r--r--test/user-font.svg11.rgb24.ref.pngbin0 -> 6411 bytes
-rw-r--r--test/user-font.svg12.argb32.ref.pngbin0 -> 6411 bytes
-rw-r--r--test/user-font.svg12.rgb24.ref.pngbin0 -> 6411 bytes
-rw-r--r--test/user-font.test-fallback.argb32.ref.pngbin0 -> 5601 bytes
-rw-r--r--test/user-font.test-fallback.rgb24.ref.pngbin0 -> 5601 bytes
-rw-r--r--test/user-font.xlib.ref.pngbin0 -> 6183 bytes
-rw-r--r--util/Makefile.am2
-rw-r--r--util/cairo-script/.gitignore1
-rw-r--r--util/cairo-script/COPYING17
-rw-r--r--util/cairo-script/Makefile.am26
-rw-r--r--util/cairo-script/cairo-script-file.c1021
-rw-r--r--util/cairo-script/cairo-script-hash.c448
-rw-r--r--util/cairo-script/cairo-script-interpreter.c472
-rw-r--r--util/cairo-script/cairo-script-interpreter.h98
-rw-r--r--util/cairo-script/cairo-script-objects.c666
-rw-r--r--util/cairo-script/cairo-script-operators.c5791
-rw-r--r--util/cairo-script/cairo-script-private.h870
-rw-r--r--util/cairo-script/cairo-script-scanner.c1179
-rw-r--r--util/cairo-script/cairo-script-stack.c196
-rw-r--r--util/cairo-script/csi-replay.c93
-rw-r--r--util/cairo-trace/Makefile.am21
-rw-r--r--util/cairo-trace/cairo-trace.in86
-rw-r--r--util/cairo-trace/lookup-symbol.c140
-rw-r--r--util/cairo-trace/trace.c1050
493 files changed, 26441 insertions, 3980 deletions
diff --git a/BIBLIOGRAPHY b/BIBLIOGRAPHY
index dacd5321..90a6cef2 100644
--- a/BIBLIOGRAPHY
+++ b/BIBLIOGRAPHY
@@ -68,6 +68,21 @@ of Bentley-Ottmann:
http://citeseer.ist.psu.edu/pugh90skip.html
+The random number generator used in our skip list implementation is a
+very small generator by Hars and Petruska. The generator is based on
+an invertable function on Z_{2^32} with full period and is described
+in
+
+ Hars L. and Petruska G.,
+ ``Pseudorandom Recursions: Small and Fast Pseurodandom
+ Number Generators for Embedded Applications'',
+ Hindawi Publishing Corporation
+ EURASIP Journal on Embedded Systems
+ Volume 2007, Article ID 98417, 13 pages
+ doi:10.1155/2007/98417
+
+ http://www.hindawi.com/getarticle.aspx?doi=10.1155/2007/98417&e=cta
+
From the result of the intersection-finding pass, we are currently
computing a tessellation of trapezoids, (the exact manner is
undergoing some work right now with some important speedup), but we
diff --git a/NEWS b/NEWS
index ec2041ff..ec147011 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,94 @@
+Release 1.9.2 (2008-11-??)
+==========================
+API additions:
+
+ cairo_surface_set_mime_data()
+ cairo_surface_get_mime_data()
+
+ Associate an alternate, compressed, representation for a surface.
+ Currently:
+ "image/jpeg" is understood by PDF,PS,SVG,win32-printing.
+ "image/png" is understood by SVG.
+
+New backend:
+
+ Simple DirectMedia Layer
+
+New utility:
+
+ cairo-trace
+
+ Generates a human-readable, replayable, compact representation of
+ the sequences of drawing commands made by an application.
+ Though currently the replay tools are out-of-tree -
+ people.freedesktop.org:~ickle/cairo-script,
+ people.freedesktop.org:~ickle/sphinx
+
+Test suite overhaul:
+ The test suite is undergoing an overhaul, primarily to improve its speed
+ and utility.
+
+Optimisations:
+Tweaks to tessellator, allocations of patterns, delayed initialisation of
+the xlib backend (reduce the cairo overhead of render_bench by ~80%).
+
+Bug fixes:
+EXTEND_PAD.
+Better handling of large scale-factors on image patterns.
+Emit /Interpolate for PS,PDF images.
+
+Release 1.8.4 (2008-11-14 Carl Worth <cworth@cworth.org>)
+=========================================================
+The cairo community is pleased to announce the 1.8.4 release of the
+cairo graphics library. This is the second update to cairo's stable
+1.8 series and contains a small number of bug fixes, (in particular a
+few fixes for build failures of cairo 1.8.2 on various systems). This
+is being released just over two weeks after cairo 1.8.2.
+
+We recommend that everyone using cairo upgrade to 1.8.4.
+
+-Carl
+
+Build fixes
+-----------
+Fix build with older XRender that doesn't define RepeatNone:
+
+ Build of xlib backend fails against old XRender (RepeatNone undeclared)
+ https://bugs.freedesktop.org/show_bug.cgi?id=18385
+
+Fix build with bash version <= 3.0:
+
+ doltlibtool broken on linux with bash 3.00.0
+ https://bugs.freedesktop.org/show_bug.cgi?id=18363
+
+Bug fixes
+---------
+Avoid triggering a bug in X.org server 6.9 resulting in a hung machine
+requiring a reboot:
+
+ https://bugs.freedesktop.org/show_bug.cgi?id=15628#c2
+
+Fix display of user fonts as exercised by proposed support for type3
+fonts in poppler (unsigned promotion fixes):
+
+ Use cairo user-font for Type 3 fonts
+ http://lists.freedesktop.org/archives/poppler/2008-October/004181.html
+
+Avoid miscomputing size of fallback images required when rendering
+with CLEAR, IN, or SOURCE operator to vector surfaces, (PS, PDF, SVG,
+etc.).
+
+Be more tolerant of broken fonts when subsetting type1 fonts:
+
+ Error handling in cairo_type1_font_subset_get_glyph_names_and_widths
+ http://lists.cairographics.org/archives/cairo/2008-October/015569.html
+
+Fix cairo_fill_extents, cairo_stroke_extents, cairo_path_extents, to
+correctly allow NULL parameters as documented.
+
+Fix potential crash on emitting a type3 glyph after having drawn text
+paths from the same font, (for example with cairo_text_path).
+
Release 1.8.2 (2008-10-29 Carl Worth <cworth@cworth.org>)
=========================================================
The cairo community is pleased to announce the 1.8.2 release of the
diff --git a/README b/README
index c01e0b23..a4ace94d 100644
--- a/README
+++ b/README
@@ -89,7 +89,7 @@ Supported, "standard" surface backends
------------------------------------
image backend (required)
------------------------
- pixman >= 0.10.0 http://cairographics.org/releases
+ pixman >= 0.12.0 http://cairographics.org/releases
png support (can be left out if desired, but many
----------- applications expect it to be present)
diff --git a/boilerplate/Makefile.sources b/boilerplate/Makefile.sources
index 44eeb39b..b3cea817 100644
--- a/boilerplate/Makefile.sources
+++ b/boilerplate/Makefile.sources
@@ -25,7 +25,11 @@ cairo_boilerplate_directfb_private = cairo-boilerplate-directfb-private.h
cairo_boilerplate_directfb_sources = cairo-boilerplate-directfb.c
cairo_boilerplate_glitz_private = cairo-boilerplate-glitz-private.h
-cairo_boilerplate_glitz_sources = cairo-boilerplate-glitz.c
+cairo_boilerplate_glitz_sources = \
+ cairo-boilerplate-glitz-agl.c \
+ cairo-boilerplate-glitz-glx.c \
+ cairo-boilerplate-glitz-wgl.c \
+ $(NULL)
cairo_boilerplate_pdf_private = cairo-boilerplate-pdf-private.h
cairo_boilerplate_pdf_sources = cairo-boilerplate-pdf.c
@@ -36,6 +40,9 @@ cairo_boilerplate_ps_sources = cairo-boilerplate-ps.c
cairo_boilerplate_quartz_private = cairo-boilerplate-quartz-private.h
cairo_boilerplate_quartz_sources = cairo-boilerplate-quartz.c
+cairo_boilerplate_script_private = cairo-boilerplate-script-private.h
+cairo_boilerplate_script_sources = cairo-boilerplate-script.c
+
cairo_boilerplate_sdl_private = cairo-boilerplate-sdl-private.h
cairo_boilerplate_sdl_sources = cairo-boilerplate-sdl.c
diff --git a/boilerplate/Makefile.win32 b/boilerplate/Makefile.win32
index a98b9fe3..84075dab 100644
--- a/boilerplate/Makefile.win32
+++ b/boilerplate/Makefile.win32
@@ -4,9 +4,12 @@ include Makefile.win32.features
CFLAGS += -I../src
-SOURCES = \
+HEADERS = \
$(enabled_cairo_boilerplate_headers) \
$(enabled_cairo_boilerplate_private) \
+ $(NULL)
+
+SOURCES = \
$(enabled_cairo_boilerplate_sources) \
$(NULL)
@@ -15,5 +18,6 @@ OBJECTS = $(patsubst %.c, $(CFG)/%.obj, $(SOURCES))
all: $(CFG)/boiler.lib
+
$(CFG)/boiler.lib: $(OBJECTS)
lib -NOLOGO -OUT:$@ $(OBJECTS) $(WIN_LIBS)
diff --git a/boilerplate/cairo-boilerplate-glitz-agl.c b/boilerplate/cairo-boilerplate-glitz-agl.c
new file mode 100644
index 00000000..06b90308
--- /dev/null
+++ b/boilerplate/cairo-boilerplate-glitz-agl.c
@@ -0,0 +1,166 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
+/*
+ * Copyright © 2004,2006 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Red Hat, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Red Hat, Inc. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Carl D. Worth <cworth@cworth.org>
+ */
+
+#include "cairo-boilerplate.h"
+#include "cairo-boilerplate-glitz-private.h"
+
+#if CAIRO_CAN_TEST_GLITZ_AGL_SURFACE
+#include <cairo-glitz.h>
+#include <glitz-agl.h>
+
+static const cairo_user_data_key_t glitz_closure_key;
+
+typedef struct _glitz_agl_target_closure {
+ glitz_target_closure_base_t base;
+} glitz_agl_target_closure_t;
+
+static glitz_surface_t *
+_cairo_boilerplate_glitz_agl_create_surface_internal (glitz_format_name_t formatname,
+ int width,
+ int height,
+ glitz_agl_target_closure_t *closure)
+{
+ glitz_drawable_format_t *dformat;
+ glitz_drawable_format_t templ;
+ glitz_drawable_t *gdraw;
+ glitz_format_t *format;
+ glitz_surface_t *sr = NULL;
+ unsigned long mask;
+
+ memset(&templ, 0, sizeof(templ));
+ templ.color.red_size = 8;
+ templ.color.green_size = 8;
+ templ.color.blue_size = 8;
+ templ.color.alpha_size = 8;
+ templ.color.fourcc = GLITZ_FOURCC_RGB;
+ templ.samples = 1;
+
+ mask = GLITZ_FORMAT_SAMPLES_MASK | GLITZ_FORMAT_FOURCC_MASK |
+ GLITZ_FORMAT_RED_SIZE_MASK | GLITZ_FORMAT_GREEN_SIZE_MASK |
+ GLITZ_FORMAT_BLUE_SIZE_MASK;
+ if (formatname == GLITZ_STANDARD_ARGB32)
+ mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK;
+
+ dformat = glitz_agl_find_pbuffer_format (mask, &templ, 0);
+ if (!dformat) {
+ CAIRO_BOILERPLATE_LOG ("Glitz failed to find pbuffer format for template.");
+ goto FAIL;
+ }
+
+ gdraw = glitz_agl_create_pbuffer_drawable (dformat, width, height);
+ if (!gdraw) {
+ CAIRO_BOILERPLATE_LOG ("Glitz failed to create pbuffer drawable.");
+ goto FAIL;
+ }
+
+ format = glitz_find_standard_format (gdraw, formatname);
+ if (!format) {
+ CAIRO_BOILERPLATE_LOG ("Glitz failed to find standard format for drawable.");
+ goto DESTROY_DRAWABLE;
+ }
+
+ sr = glitz_surface_create (gdraw, format, width, height, 0, NULL);
+ if (!sr) {
+ CAIRO_BOILERPLATE_LOG ("Glitz failed to create a surface.");
+ goto DESTROY_DRAWABLE;
+ }
+
+ glitz_surface_attach (sr, gdraw, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR);
+
+ DESTROY_DRAWABLE:
+ glitz_drawable_destroy (gdraw);
+ return sr;
+
+ FAIL:
+ return NULL;
+}
+
+cairo_surface_t *
+_cairo_boilerplate_glitz_agl_create_surface (const char *name,
+ cairo_content_t content,
+ int width,
+ int height,
+ int max_width,
+ int max_height,
+ cairo_boilerplate_mode_t mode,
+ int id,
+ void **closure)
+{
+ glitz_surface_t *glitz_surface;
+ cairo_surface_t *surface = NULL;
+ glitz_agl_target_closure_t *aglc;
+ int status;
+
+ glitz_agl_init ();
+
+ *closure = aglc = xmalloc (sizeof (glitz_agl_target_closure_t));
+
+ switch (content) {
+ case CAIRO_CONTENT_COLOR:
+ glitz_surface = _cairo_boilerplate_glitz_agl_create_surface_internal (GLITZ_STANDARD_RGB24, width, height, NULL);
+ break;
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ glitz_surface = _cairo_boilerplate_glitz_agl_create_surface_internal (GLITZ_STANDARD_ARGB32, width, height, NULL);
+ break;
+ case CAIRO_CONTENT_ALPHA:
+ default:
+ CAIRO_BOILERPLATE_LOG ("Invalid content for glitz-agl test: %d\n", content);
+ goto FAIL;
+ }
+
+ if (!glitz_surface)
+ goto FAIL;
+
+ surface = cairo_glitz_surface_create (glitz_surface);
+ glitz_surface_destroy (glitz_surface);
+
+ if (cairo_surface_status (surface))
+ goto FAIL;
+
+ aglc->base.width = width;
+ aglc->base.height = height;
+ aglc->base.content = content;
+ status = cairo_surface_set_user_data (surface,
+ &glitz_closure_key, aglc, NULL);
+ if (status == CAIRO_STATUS_SUCCESS)
+ return surface;
+
+ cairo_surface_destroy (surface);
+ surface = cairo_boilerplate_surface_create_in_error (status);
+
+ FAIL:
+ glitz_agl_fini ();
+ return surface;
+}
+
+void
+_cairo_boilerplate_glitz_agl_cleanup (void *closure)
+{
+ free (closure);
+ glitz_agl_fini ();
+}
+
+#endif
diff --git a/boilerplate/cairo-boilerplate-glitz-glx.c b/boilerplate/cairo-boilerplate-glitz-glx.c
new file mode 100644
index 00000000..5dcf8b69
--- /dev/null
+++ b/boilerplate/cairo-boilerplate-glitz-glx.c
@@ -0,0 +1,244 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
+/*
+ * Copyright © 2004,2006 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Red Hat, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Red Hat, Inc. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Carl D. Worth <cworth@cworth.org>
+ */
+
+#include "cairo-boilerplate.h"
+#include "cairo-boilerplate-glitz-private.h"
+
+#if CAIRO_CAN_TEST_GLITZ_GLX_SURFACE
+#include <cairo-glitz.h>
+#include <glitz-glx.h>
+
+static const cairo_user_data_key_t glitz_closure_key;
+
+typedef struct _glitz_glx_target_closure {
+ glitz_target_closure_base_t base;
+ Display *dpy;
+ int scr;
+ Window win;
+} glitz_glx_target_closure_t;
+
+static glitz_surface_t *
+_cairo_boilerplate_glitz_glx_create_surface_internal (glitz_format_name_t formatname,
+ int width,
+ int height,
+ glitz_glx_target_closure_t *closure)
+{
+ Display * dpy = closure->dpy;
+ int scr = closure->scr;
+ glitz_drawable_format_t templ;
+ glitz_drawable_format_t * dformat = NULL;
+ unsigned long mask;
+ glitz_drawable_t * drawable = NULL;
+ glitz_format_t * format;
+ glitz_surface_t * sr;
+
+ XSizeHints xsh;
+ XSetWindowAttributes xswa;
+ XVisualInfo * vinfo;
+
+ memset(&templ, 0, sizeof(templ));
+ templ.color.red_size = 8;
+ templ.color.green_size = 8;
+ templ.color.blue_size = 8;
+ templ.color.alpha_size = 8;
+ templ.color.fourcc = GLITZ_FOURCC_RGB;
+ templ.samples = 1;
+
+ glitz_glx_init (NULL);
+
+ mask = GLITZ_FORMAT_SAMPLES_MASK | GLITZ_FORMAT_FOURCC_MASK |
+ GLITZ_FORMAT_RED_SIZE_MASK | GLITZ_FORMAT_GREEN_SIZE_MASK |
+ GLITZ_FORMAT_BLUE_SIZE_MASK;
+ if (formatname == GLITZ_STANDARD_ARGB32)
+ mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK;
+
+ /* Try for a pbuffer first */
+ if (!getenv("CAIRO_TEST_FORCE_GLITZ_WINDOW"))
+ dformat = glitz_glx_find_pbuffer_format (dpy, scr, mask, &templ, 0);
+
+ if (dformat) {
+ closure->win = None;
+
+ drawable = glitz_glx_create_pbuffer_drawable (dpy, scr, dformat,
+ width, height);
+ if (!drawable)
+ goto FAIL;
+ } else {
+ /* No pbuffer, try window */
+ dformat = glitz_glx_find_window_format (dpy, scr, mask, &templ, 0);
+
+ if (!dformat)
+ goto FAIL;
+
+ vinfo = glitz_glx_get_visual_info_from_format(dpy,
+ DefaultScreen(dpy),
+ dformat);
+
+ if (!vinfo)
+ goto FAIL;
+
+ xsh.flags = PSize;
+ xsh.x = 0;
+ xsh.y = 0;
+ xsh.width = width;
+ xsh.height = height;
+
+ xswa.colormap = XCreateColormap (dpy, RootWindow(dpy, scr),
+ vinfo->visual, AllocNone);
+ closure->win = XCreateWindow (dpy, RootWindow(dpy, scr),
+ xsh.x, xsh.y, xsh.width, xsh.height,
+ 0, vinfo->depth, CopyFromParent,
+ vinfo->visual, CWColormap, &xswa);
+ XFree (vinfo);
+
+ drawable =
+ glitz_glx_create_drawable_for_window (dpy, scr,
+ dformat, closure->win,
+ width, height);
+
+ if (!drawable)
+ goto DESTROY_WINDOW;
+ }
+
+ format = glitz_find_standard_format (drawable, formatname);
+ if (!format)
+ goto DESTROY_DRAWABLE;
+
+ sr = glitz_surface_create (drawable, format, width, height, 0, NULL);
+ if (!sr)
+ goto DESTROY_DRAWABLE;
+
+ if (closure->win == None || dformat->doublebuffer) {
+ glitz_surface_attach (sr, drawable, GLITZ_DRAWABLE_BUFFER_BACK_COLOR);
+ } else {
+ XMapWindow (closure->dpy, closure->win);
+ glitz_surface_attach (sr, drawable, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR);
+ }
+
+ glitz_drawable_destroy (drawable);
+
+ return sr;
+
+ DESTROY_DRAWABLE:
+ glitz_drawable_destroy (drawable);
+ DESTROY_WINDOW:
+ if (closure->win)
+ XDestroyWindow (dpy, closure->win);
+ FAIL:
+ return NULL;
+}
+
+cairo_surface_t *
+_cairo_boilerplate_glitz_glx_create_surface (const char *name,
+ cairo_content_t content,
+ int width,
+ int height,
+ int max_width,
+ int max_height,
+ cairo_boilerplate_mode_t mode,
+ int id,
+ void **closure)
+{
+ glitz_glx_target_closure_t *gxtc;
+ glitz_surface_t * glitz_surface;
+ cairo_surface_t * surface = NULL;
+ cairo_status_t status;
+
+ *closure = gxtc = xmalloc (sizeof (glitz_glx_target_closure_t));
+
+ if (width == 0)
+ width = 1;
+ if (height == 0)
+ height = 1;
+
+ gxtc->dpy = XOpenDisplay (getenv("CAIRO_TEST_GLITZ_DISPLAY"));
+ if (!gxtc->dpy) {
+ CAIRO_BOILERPLATE_LOG ("Failed to open display: %s\n", XDisplayName(0));
+ goto FAIL;
+ }
+
+ XSynchronize (gxtc->dpy, 1);
+
+ gxtc->scr = DefaultScreen(gxtc->dpy);
+
+ switch (content) {
+ case CAIRO_CONTENT_COLOR:
+ glitz_surface = _cairo_boilerplate_glitz_glx_create_surface_internal (GLITZ_STANDARD_RGB24, width, height, gxtc);
+ break;
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ glitz_surface = _cairo_boilerplate_glitz_glx_create_surface_internal (GLITZ_STANDARD_ARGB32, width, height, gxtc);
+ break;
+ case CAIRO_CONTENT_ALPHA:
+ default:
+ CAIRO_BOILERPLATE_LOG ("Invalid content for glitz-glx test: %d\n", content);
+ goto FAIL_CLOSE_DISPLAY;
+ }
+ if (!glitz_surface) {
+ CAIRO_BOILERPLATE_LOG ("Failed to create glitz-glx surface\n");
+ goto FAIL_CLOSE_DISPLAY;
+ }
+
+ surface = cairo_glitz_surface_create (glitz_surface);
+ glitz_surface_destroy (glitz_surface);
+
+ if (cairo_surface_status (surface))
+ goto FAIL_CLOSE_DISPLAY;
+
+ gxtc->base.width = width;
+ gxtc->base.height = height;
+ gxtc->base.content = content;
+ status = cairo_surface_set_user_data (surface,
+ &glitz_closure_key, gxtc, NULL);
+ if (status == CAIRO_STATUS_SUCCESS)
+ return surface;
+
+ cairo_surface_destroy (surface);
+ surface = cairo_boilerplate_surface_create_in_error (status);
+
+ FAIL_CLOSE_DISPLAY:
+ glitz_glx_fini ();
+ XCloseDisplay (gxtc->dpy);
+ FAIL:
+ free (gxtc);
+ return surface;
+}
+
+void
+_cairo_boilerplate_glitz_glx_cleanup (void *closure)
+{
+ glitz_glx_target_closure_t *gxtc = closure;
+
+ glitz_glx_fini ();
+
+ if (gxtc->win)
+ XDestroyWindow (gxtc->dpy, gxtc->win);
+
+ XCloseDisplay (gxtc->dpy);
+
+ free (gxtc);
+}
+
+#endif
diff --git a/boilerplate/cairo-boilerplate-glitz-private.h b/boilerplate/cairo-boilerplate-glitz-private.h
index faeeb630..052c7e06 100644
--- a/boilerplate/cairo-boilerplate-glitz-private.h
+++ b/boilerplate/cairo-boilerplate-glitz-private.h
@@ -31,6 +31,12 @@
#include "config.h"
#endif
+typedef struct _glitz_target_closure_base {
+ int width;
+ int height;
+ cairo_content_t content;
+} glitz_target_closure_base_t;
+
#if CAIRO_CAN_TEST_GLITZ_GLX_SURFACE
cairo_surface_t *
_cairo_boilerplate_glitz_glx_create_surface (const char *name,
diff --git a/boilerplate/cairo-boilerplate-glitz-wgl.c b/boilerplate/cairo-boilerplate-glitz-wgl.c
new file mode 100644
index 00000000..b11a8189
--- /dev/null
+++ b/boilerplate/cairo-boilerplate-glitz-wgl.c
@@ -0,0 +1,164 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
+/*
+ * Copyright © 2004,2006 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Red Hat, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Red Hat, Inc. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Carl D. Worth <cworth@cworth.org>
+ */
+
+#include "cairo-boilerplate.h"
+#include "cairo-boilerplate-glitz-private.h"
+
+#if CAIRO_CAN_TEST_GLITZ_WGL_SURFACE
+#include <cairo-glitz.h>
+#include <glitz-wgl.h>
+
+static const cairo_user_data_key_t glitz_closure_key;
+
+typedef struct _glitz_wgl_target_closure {
+ glitz_target_closure_base_t base;
+} glitz_wgl_target_closure_t;
+
+glitz_surface_t *
+_cairo_boilerplate_glitz_wgl_create_surface_internal (glitz_format_name_t formatname,
+ int width,
+ int height,
+ glitz_wgl_target_closure_t *closure)
+{
+ glitz_drawable_format_t *dformat;
+ glitz_drawable_format_t templ;
+ glitz_drawable_t *gdraw;
+ glitz_format_t *format;
+ glitz_surface_t *sr = NULL;
+ unsigned long mask;
+
+ memset(&templ, 0, sizeof(templ));
+ templ.color.red_size = 8;
+ templ.color.green_size = 8;
+ templ.color.blue_size = 8;
+ templ.color.alpha_size = 8;
+ templ.color.fourcc = GLITZ_FOURCC_RGB;
+ templ.samples = 1;
+
+ mask = GLITZ_FORMAT_SAMPLES_MASK | GLITZ_FORMAT_FOURCC_MASK |
+ GLITZ_FORMAT_RED_SIZE_MASK | GLITZ_FORMAT_GREEN_SIZE_MASK |
+ GLITZ_FORMAT_BLUE_SIZE_MASK;
+ if (formatname == GLITZ_STANDARD_ARGB32)
+ mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK;
+
+ dformat = glitz_wgl_find_pbuffer_format (mask, &templ, 0);
+ if (!dformat) {
+ CAIRO_BOILERPLATE_LOG ("Glitz failed to find pbuffer format for template.");
+ goto FAIL;
+ }
+
+ gdraw = glitz_wgl_create_pbuffer_drawable (dformat, width, height);
+ if (!gdraw) {
+ CAIRO_BOILERPLATE_LOG ("Glitz failed to create pbuffer drawable.");
+ goto FAIL;
+ }
+
+ format = glitz_find_standard_format (gdraw, formatname);
+ if (!format) {
+ CAIRO_BOILERPLATE_LOG ("Glitz failed to find standard format for drawable.");
+ goto DESTROY_DRAWABLE;
+ }
+
+ sr = glitz_surface_create (gdraw, format, width, height, 0, NULL);
+ if (!sr) {
+ CAIRO_BOILERPLATE_LOG ("Glitz failed to create a surface.");
+ goto DESTROY_DRAWABLE;
+ }
+
+ glitz_surface_attach (sr, gdraw, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR);
+
+ DESTROY_DRAWABLE:
+ glitz_drawable_destroy (gdraw);
+
+ FAIL:
+ return sr; /* will be NULL unless we create it and attach */
+}
+
+cairo_surface_t *
+_cairo_boilerplate_glitz_wgl_create_surface (const char *name,
+ cairo_content_t content,
+ int width,
+ int height,
+ int max_width,
+ int max_height,
+ cairo_boilerplate_mode_t mode,
+ int id,
+ void **closure)
+{
+ glitz_surface_t *glitz_surface;
+ cairo_surface_t *surface = NULL;
+ glitz_wgl_target_closure_t *wglc;
+
+ glitz_wgl_init (NULL);
+
+ *closure = wglc = xmalloc (sizeof (glitz_wgl_target_closure_t));
+
+ switch (content) {
+ case CAIRO_CONTENT_COLOR:
+ glitz_surface = _cairo_boilerplate_glitz_wgl_create_surface_internal (GLITZ_STANDARD_RGB24, width, height, NULL);
+ break;
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ glitz_surface = _cairo_boilerplate_glitz_wgl_create_surface_internal (GLITZ_STANDARD_ARGB32, width, height, NULL);
+ break;
+ default:
+ CAIRO_BOILERPLATE_LOG ("Invalid content for glitz-wgl test: %d\n", content);
+ goto FAIL;
+ }
+
+ if (!glitz_surface)
+ goto FAIL;
+
+ surface = cairo_glitz_surface_create (glitz_surface);
+ glitz_surface_destroy (glitz_surface);
+
+ if (cairo_surface_status (surface))
+ goto FAIL;
+
+ wglc->base.width = width;
+ wglc->base.height = height;
+ wglc->base.content = content;
+ status = cairo_surface_set_user_data (surface,
+ &glitz_closure_key, wglc, NULL);
+ if (status == CAIRO_STATUS_SUCCESS)
+ return surface;
+
+ cairo_surface_destroy (surface);
+ surface = cairo_boilerplate_surface_create_in_error (status);
+
+ FAIL:
+ glitz_wgl_fini ();
+ free (wglc);
+ return surface;
+}
+
+void
+_cairo_boilerplate_glitz_wgl_cleanup (void *closure)
+{
+ free (closure);
+ glitz_wgl_fini ();
+}
+
+#endif
diff --git a/boilerplate/cairo-boilerplate-glitz.c b/boilerplate/cairo-boilerplate-glitz.c
deleted file mode 100644
index a7640801..00000000
--- a/boilerplate/cairo-boilerplate-glitz.c
+++ /dev/null
@@ -1,517 +0,0 @@
-/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
-/*
- * Copyright © 2004,2006 Red Hat, Inc.
- *
- * Permission to use, copy, modify, distribute, and sell this software
- * and its documentation for any purpose is hereby granted without
- * fee, provided that the above copyright notice appear in all copies
- * and that both that copyright notice and this permission notice
- * appear in supporting documentation, and that the name of
- * Red Hat, Inc. not be used in advertising or publicity pertaining to
- * distribution of the software without specific, written prior
- * permission. Red Hat, Inc. makes no representations about the
- * suitability of this software for any purpose. It is provided "as
- * is" without express or implied warranty.
- *
- * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
- * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
- * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
- * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: Carl D. Worth <cworth@cworth.org>
- */
-
-#include "cairo-boilerplate.h"
-#include "cairo-boilerplate-glitz-private.h"
-
-#include <cairo-glitz.h>
-
-static const cairo_user_data_key_t glitz_closure_key;
-
-typedef struct _glitz_target_closure_base {
- int width;
- int height;
- cairo_content_t content;
-} glitz_target_closure_base_t;
-
-#if CAIRO_CAN_TEST_GLITZ_GLX_SURFACE
-#include <glitz-glx.h>
-
-typedef struct _glitz_glx_target_closure {
- glitz_target_closure_base_t base;
- Display *dpy;
- int scr;
- Window win;
-} glitz_glx_target_closure_t;
-
-static glitz_surface_t *
-_cairo_boilerplate_glitz_glx_create_surface_internal (glitz_format_name_t formatname,
- int width,
- int height,
- glitz_glx_target_closure_t *closure)
-{
- Display * dpy = closure->dpy;
- int scr = closure->scr;
- glitz_drawable_format_t templ;
- glitz_drawable_format_t * dformat = NULL;
- unsigned long mask;
- glitz_drawable_t * drawable = NULL;
- glitz_format_t * format;
- glitz_surface_t * sr;
-
- XSizeHints xsh;
- XSetWindowAttributes xswa;
- XVisualInfo * vinfo;
-
- memset(&templ, 0, sizeof(templ));
- templ.color.red_size = 8;
- templ.color.green_size = 8;
- templ.color.blue_size = 8;
- templ.color.alpha_size = 8;
- templ.color.fourcc = GLITZ_FOURCC_RGB;
- templ.samples = 1;
-
- glitz_glx_init (NULL);
-
- mask = GLITZ_FORMAT_SAMPLES_MASK | GLITZ_FORMAT_FOURCC_MASK |
- GLITZ_FORMAT_RED_SIZE_MASK | GLITZ_FORMAT_GREEN_SIZE_MASK |
- GLITZ_FORMAT_BLUE_SIZE_MASK;
- if (formatname == GLITZ_STANDARD_ARGB32)
- mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK;
-
- /* Try for a pbuffer first */
- if (!getenv("CAIRO_TEST_FORCE_GLITZ_WINDOW"))
- dformat = glitz_glx_find_pbuffer_format (dpy, scr, mask, &templ, 0);
-
- if (dformat) {
- closure->win = None;
-
- drawable = glitz_glx_create_pbuffer_drawable (dpy, scr, dformat,
- width, height);
- if (!drawable)
- goto FAIL;
- } else {
- /* No pbuffer, try window */
- dformat = glitz_glx_find_window_format (dpy, scr, mask, &templ, 0);
-
- if (!dformat)
- goto FAIL;
-
- vinfo = glitz_glx_get_visual_info_from_format(dpy,
- DefaultScreen(dpy),
- dformat);
-
- if (!vinfo)
- goto FAIL;
-
- xsh.flags = PSize;
- xsh.x = 0;
- xsh.y = 0;
- xsh.width = width;
- xsh.height = height;
-
- xswa.colormap = XCreateColormap (dpy, RootWindow(dpy, scr),
- vinfo->visual, AllocNone);
- closure->win = XCreateWindow (dpy, RootWindow(dpy, scr),
- xsh.x, xsh.y, xsh.width, xsh.height,
- 0, vinfo->depth, CopyFromParent,
- vinfo->visual, CWColormap, &xswa);
- XFree (vinfo);
-
- drawable =
- glitz_glx_create_drawable_for_window (dpy, scr,
- dformat, closure->win,
- width, height);
-
- if (!drawable)
- goto DESTROY_WINDOW;
- }
-
- format = glitz_find_standard_format (drawable, formatname);
- if (!format)
- goto DESTROY_DRAWABLE;
-
- sr = glitz_surface_create (drawable, format, width, height, 0, NULL);
- if (!sr)
- goto DESTROY_DRAWABLE;
-
- if (closure->win == None || dformat->doublebuffer) {
- glitz_surface_attach (sr, drawable, GLITZ_DRAWABLE_BUFFER_BACK_COLOR);
- } else {
- XMapWindow (closure->dpy, closure->win);
- glitz_surface_attach (sr, drawable, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR);
- }
-
- glitz_drawable_destroy (drawable);
-
- return sr;
-
- DESTROY_DRAWABLE:
- glitz_drawable_destroy (drawable);
- DESTROY_WINDOW:
- if (closure->win)
- XDestroyWindow (dpy, closure->win);
- FAIL:
- return NULL;
-}
-
-cairo_surface_t *
-_cairo_boilerplate_glitz_glx_create_surface (const char *name,
- cairo_content_t content,
- int width,
- int height,
- int max_width,
- int max_height,
- cairo_boilerplate_mode_t mode,
- int id,
- void **closure)
-{
- glitz_glx_target_closure_t *gxtc;
- glitz_surface_t * glitz_surface;
- cairo_surface_t * surface = NULL;
- cairo_status_t status;
-
- *closure = gxtc = xmalloc (sizeof (glitz_glx_target_closure_t));
-
- if (width == 0)
- width = 1;
- if (height == 0)
- height = 1;
-
- gxtc->dpy = XOpenDisplay (getenv("CAIRO_TEST_GLITZ_DISPLAY"));
- if (!gxtc->dpy) {
- CAIRO_BOILERPLATE_LOG ("Failed to open display: %s\n", XDisplayName(0));
- goto FAIL;
- }
-
- XSynchronize (gxtc->dpy, 1);
-
- gxtc->scr = DefaultScreen(gxtc->dpy);
-
- switch (content) {
- case CAIRO_CONTENT_COLOR:
- glitz_surface = _cairo_boilerplate_glitz_glx_create_surface_internal (GLITZ_STANDARD_RGB24, width, height, gxtc);
- break;
- case CAIRO_CONTENT_COLOR_ALPHA:
- glitz_surface = _cairo_boilerplate_glitz_glx_create_surface_internal (GLITZ_STANDARD_ARGB32, width, height, gxtc);
- break;
- case CAIRO_CONTENT_ALPHA:
- default:
- CAIRO_BOILERPLATE_LOG ("Invalid content for glitz-glx test: %d\n", content);
- goto FAIL_CLOSE_DISPLAY;
- }
- if (!glitz_surface) {
- CAIRO_BOILERPLATE_LOG ("Failed to create glitz-glx surface\n");
- goto FAIL_CLOSE_DISPLAY;
- }
-
- surface = cairo_glitz_surface_create (glitz_surface);
- glitz_surface_destroy (glitz_surface);
-
- if (cairo_surface_status (surface))
- goto FAIL_CLOSE_DISPLAY;
-
- gxtc->base.width = width;
- gxtc->base.height = height;
- gxtc->base.content = content;
- status = cairo_surface_set_user_data (surface,
- &glitz_closure_key, gxtc, NULL);
- if (status == CAIRO_STATUS_SUCCESS)
- return surface;
-
- cairo_surface_destroy (surface);
- surface = cairo_boilerplate_surface_create_in_error (status);
-
- FAIL_CLOSE_DISPLAY:
- glitz_glx_fini ();
- XCloseDisplay (gxtc->dpy);
- FAIL:
- free (gxtc);
- return surface;
-}
-
-void
-_cairo_boilerplate_glitz_glx_cleanup (void *closure)
-{
- glitz_glx_target_closure_t *gxtc = closure;
-
- glitz_glx_fini ();
-
- if (gxtc->win)
- XDestroyWindow (gxtc->dpy, gxtc->win);
-
- XCloseDisplay (gxtc->dpy);
-
- free (gxtc);
-}
-
-#endif /* CAIRO_CAN_TEST_GLITZ_GLX_SURFACE */
-
-#if CAIRO_CAN_TEST_GLITZ_AGL_SURFACE
-#include <glitz-agl.h>
-
-typedef struct _glitz_agl_target_closure {
- glitz_target_closure_base_t base;
-} glitz_agl_target_closure_t;
-
-glitz_surface_t *
-_cairo_boilerplate_glitz_agl_create_surface_internal (glitz_format_name_t formatname,
- int width,
- int height,
- glitz_agl_target_closure_t *closure)
-{
- glitz_drawable_format_t *dformat;
- glitz_drawable_format_t templ;
- glitz_drawable_t *gdraw;
- glitz_format_t *format;
- glitz_surface_t *sr = NULL;
- unsigned long mask;
-
- memset(&templ, 0, sizeof(templ));
- templ.color.red_size = 8;
- templ.color.green_size = 8;
- templ.color.blue_size = 8;
- templ.color.alpha_size = 8;
- templ.color.fourcc = GLITZ_FOURCC_RGB;
- templ.samples = 1;
-
- mask = GLITZ_FORMAT_SAMPLES_MASK | GLITZ_FORMAT_FOURCC_MASK |
- GLITZ_FORMAT_RED_SIZE_MASK | GLITZ_FORMAT_GREEN_SIZE_MASK |
- GLITZ_FORMAT_BLUE_SIZE_MASK;
- if (formatname == GLITZ_STANDARD_ARGB32)
- mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK;
-
- dformat = glitz_agl_find_pbuffer_format (mask, &templ, 0);
- if (!dformat) {
- CAIRO_BOILERPLATE_LOG ("Glitz failed to find pbuffer format for template.");
- goto FAIL;
- }
-
- gdraw = glitz_agl_create_pbuffer_drawable (dformat, width, height);
- if (!gdraw) {
- CAIRO_BOILERPLATE_LOG ("Glitz failed to create pbuffer drawable.");
- goto FAIL;
- }
-
- format = glitz_find_standard_format (gdraw, formatname);
- if (!format) {
- CAIRO_BOILERPLATE_LOG ("Glitz failed to find standard format for drawable.");
- goto DESTROY_DRAWABLE;
- }
-
- sr = glitz_surface_create (gdraw, format, width, height, 0, NULL);
- if (!sr) {
- CAIRO_BOILERPLATE_LOG ("Glitz failed to create a surface.");
- goto DESTROY_DRAWABLE;
- }
-
- glitz_surface_attach (sr, gdraw, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR);
-
- DESTROY_DRAWABLE:
- glitz_drawable_destroy (gdraw);
- return sr;
-
- FAIL:
- return NULL;
-}
-
-cairo_surface_t *
-_cairo_boilerplate_glitz_agl_create_surface (const char *name,
- cairo_content_t content,
- int width,
- int height,
- int max_width,
- int max_height,
- cairo_boilerplate_mode_t mode,
- int id,
- void **closure)
-{
- glitz_surface_t *glitz_surface;
- cairo_surface_t *surface = NULL;
- glitz_agl_target_closure_t *aglc;
-
- glitz_agl_init ();
-
- *closure = aglc = xmalloc (sizeof (glitz_agl_target_closure_t));
-
- switch (content) {
- case CAIRO_CONTENT_COLOR:
- glitz_surface = _cairo_boilerplate_glitz_agl_create_surface_internal (GLITZ_STANDARD_RGB24, width, height, NULL);
- break;
- case CAIRO_CONTENT_COLOR_ALPHA:
- glitz_surface = _cairo_boilerplate_glitz_agl_create_surface_internal (GLITZ_STANDARD_ARGB32, width, height, NULL);
- break;
- default:
- CAIRO_BOILERPLATE_LOG ("Invalid content for glitz-agl test: %d\n", content);
- goto FAIL;
- }
-
- if (!glitz_surface)
- goto FAIL;
-
- surface = cairo_glitz_surface_create (glitz_surface);
- glitz_surface_destroy (glitz_surface);
-
- if (cairo_surface_status (surface))
- goto FAIL;
-
- aglc->base.width = width;
- aglc->base.height = height;
- aglc->base.content = content;
- status = cairo_surface_set_user_data (surface,
- &glitz_closure_key, aglc, NULL);
- if (status == CAIRO_STATUS_SUCCESS)
- return surface;
-
- cairo_surface_destroy (surface);
- surface = cairo_boilerplate_surface_create_in_error (status);
-
- FAIL:
- glitz_agl_fini ();
- return surface;
-}
-
-void
-_cairo_boilerplate_glitz_agl_cleanup (void *closure)
-{
- free (closure);
- glitz_agl_fini ();
-}
-
-#endif /* CAIRO_CAN_TEST_GLITZ_AGL_SURFACE */
-
-#if CAIRO_CAN_TEST_GLITZ_WGL_SURFACE
-#include <glitz-wgl.h>
-
-typedef struct _glitz_wgl_target_closure {
- glitz_target_closure_base_t base;
-} glitz_wgl_target_closure_t;
-
-glitz_surface_t *
-_cairo_boilerplate_glitz_wgl_create_surface_internal (glitz_format_name_t formatname,
- int width,
- int height,
- glitz_wgl_target_closure_t *closure)
-{
- glitz_drawable_format_t *dformat;
- glitz_drawable_format_t templ;
- glitz_drawable_t *gdraw;
- glitz_format_t *format;
- glitz_surface_t *sr = NULL;
- unsigned long mask;
-
- memset(&templ, 0, sizeof(templ));
- templ.color.red_size = 8;
- templ.color.green_size = 8;
- templ.color.blue_size = 8;
- templ.color.alpha_size = 8;
- templ.color.fourcc = GLITZ_FOURCC_RGB;
- templ.samples = 1;
-
- mask = GLITZ_FORMAT_SAMPLES_MASK | GLITZ_FORMAT_FOURCC_MASK |
- GLITZ_FORMAT_RED_SIZE_MASK | GLITZ_FORMAT_GREEN_SIZE_MASK |
- GLITZ_FORMAT_BLUE_SIZE_MASK;
- if (formatname == GLITZ_STANDARD_ARGB32)
- mask |= GLITZ_FORMAT_ALPHA_SIZE_MASK;
-
- dformat = glitz_wgl_find_pbuffer_format (mask, &templ, 0);
- if (!dformat) {
- CAIRO_BOILERPLATE_LOG ("Glitz failed to find pbuffer format for template.");
- goto FAIL;
- }
-
- gdraw = glitz_wgl_create_pbuffer_drawable (dformat, width, height);
- if (!gdraw) {
- CAIRO_BOILERPLATE_LOG ("Glitz failed to create pbuffer drawable.");
- goto FAIL;
- }
-
- format = glitz_find_standard_format (gdraw, formatname);
- if (!format) {
- CAIRO_BOILERPLATE_LOG ("Glitz failed to find standard format for drawable.");
- goto DESTROY_DRAWABLE;
- }
-
- sr = glitz_surface_create (gdraw, format, width, height, 0, NULL);
- if (!sr) {
- CAIRO_BOILERPLATE_LOG ("Glitz failed to create a surface.");
- goto DESTROY_DRAWABLE;
- }
-
- glitz_surface_attach (sr, gdraw, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR);
-
- DESTROY_DRAWABLE:
- glitz_drawable_destroy (gdraw);
-
- FAIL:
- return sr; /* will be NULL unless we create it and attach */
-}
-
-cairo_surface_t *
-_cairo_boilerplate_glitz_wgl_create_surface (const char *name,
- cairo_content_t content,
- int width,
- int height,
- int max_width,
- int max_height,
- cairo_boilerplate_mode_t mode,
- int id,
- void **closure)
-{
- glitz_surface_t *glitz_surface;
- cairo_surface_t *surface = NULL;
- glitz_wgl_target_closure_t *wglc;
-
- glitz_wgl_init (NULL);
-
- *closure = wglc = xmalloc (sizeof (glitz_wgl_target_closure_t));
-
- switch (content) {
- case CAIRO_CONTENT_COLOR:
- glitz_surface = _cairo_boilerplate_glitz_wgl_create_surface_internal (GLITZ_STANDARD_RGB24, width, height, NULL);
- break;
- case CAIRO_CONTENT_COLOR_ALPHA:
- glitz_surface = _cairo_boilerplate_glitz_wgl_create_surface_internal (GLITZ_STANDARD_ARGB32, width, height, NULL);
- break;
- default:
- CAIRO_BOILERPLATE_LOG ("Invalid content for glitz-wgl test: %d\n", content);
- goto FAIL;
- }
-
- if (!glitz_surface)
- goto FAIL;
-
- surface = cairo_glitz_surface_create (glitz_surface);
- glitz_surface_destroy (glitz_surface);
-
- if (cairo_surface_status (surface))
- goto FAIL;
-
- wglc->base.width = width;
- wglc->base.height = height;
- wglc->base.content = content;
- status = cairo_surface_set_user_data (surface,
- &glitz_closure_key, wglc, NULL);
- if (status == CAIRO_STATUS_SUCCESS)
- return surface;
-
- cairo_surface_destroy (surface);
- surface = cairo_boilerplate_surface_create_in_error (status);
-
- FAIL:
- glitz_wgl_fini ();
- free (wglc);
- return surface;
-}
-
-void
-_cairo_boilerplate_glitz_wgl_cleanup (void *closure)
-{
- free (closure);
- glitz_wgl_fini ();
-}
-
-#endif /* CAIRO_CAN_TEST_GLITZ_WGL_SURFACE */
diff --git a/boilerplate/cairo-boilerplate-pdf.c b/boilerplate/cairo-boilerplate-pdf.c
index 70002385..7e5e1624 100644
--- a/boilerplate/cairo-boilerplate-pdf.c
+++ b/boilerplate/cairo-boilerplate-pdf.c
@@ -72,7 +72,7 @@ _cairo_boilerplate_pdf_create_surface (const char *name,
ptc->width = width;
ptc->height = height;
- xasprintf (&ptc->filename, "%s-out.pdf", name);
+ xasprintf (&ptc->filename, "%s.out.pdf", name);
xunlink (ptc->filename);
surface = cairo_pdf_surface_create (ptc->filename, width, height);
diff --git a/boilerplate/cairo-boilerplate-ps.c b/boilerplate/cairo-boilerplate-ps.c
index b2e1e122..c3efceab 100644
--- a/boilerplate/cairo-boilerplate-ps.c
+++ b/boilerplate/cairo-boilerplate-ps.c
@@ -86,7 +86,7 @@ _cairo_boilerplate_ps_create_surface (const char *name,
*closure = ptc = xmalloc (sizeof (ps_target_closure_t));
- xasprintf (&ptc->filename, "%s-out.ps", name);
+ xasprintf (&ptc->filename, "%s.out.ps", name);
xunlink (ptc->filename);
ptc->level = level;
diff --git a/boilerplate/cairo-boilerplate-script-private.h b/boilerplate/cairo-boilerplate-script-private.h
new file mode 100644
index 00000000..480e4221
--- /dev/null
+++ b/boilerplate/cairo-boilerplate-script-private.h
@@ -0,0 +1,57 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
+/*
+ * Copyright © 2008 Chris Wilson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Red Hat, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Red Hat, Inc. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#ifndef _CAIRO_BOILERPLATE_SCRIPT_PRIVATE_H_
+#define _CAIRO_BOILERPLATE_SCRIPT_PRIVATE_H_
+
+cairo_surface_t *
+_cairo_boilerplate_script_create_surface (const char *name,
+ cairo_content_t content,
+ int width,
+ int height,
+ int max_width,
+ int max_height,
+ cairo_boilerplate_mode_t mode,
+ int id,
+ void **closure);
+
+cairo_status_t
+_cairo_boilerplate_script_finish_surface (cairo_surface_t *surface);
+
+cairo_status_t
+_cairo_boilerplate_script_surface_write_to_png (cairo_surface_t *surface,
+ const char *filename);
+
+cairo_surface_t *
+_cairo_boilerplate_script_get_image_surface (cairo_surface_t *surface,
+ int page,
+ int width,
+ int height);
+
+void
+_cairo_boilerplate_script_cleanup (void *closure);
+
+#endif
diff --git a/boilerplate/cairo-boilerplate-script.c b/boilerplate/cairo-boilerplate-script.c
new file mode 100644
index 00000000..ae08cbc5
--- /dev/null
+++ b/boilerplate/cairo-boilerplate-script.c
@@ -0,0 +1,125 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
+/*
+ * Copyright © Chris Wilson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Chris Wilson not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Chris Wilson makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairo-boilerplate.h"
+#include "cairo-boilerplate-script-private.h"
+
+#include "cairo-script.h"
+
+cairo_user_data_key_t script_closure_key;
+
+typedef struct _script_target_closure {
+ char *filename;
+ int width;
+ int height;
+} script_target_closure_t;
+
+cairo_surface_t *
+_cairo_boilerplate_script_create_surface (const char *name,
+ cairo_content_t content,
+ int width,
+ int height,
+ int max_width,
+ int max_height,
+ cairo_boilerplate_mode_t mode,
+ int id,
+ void **closure)
+{
+ script_target_closure_t *ptc;
+ cairo_surface_t *surface;
+ cairo_status_t status;
+
+ *closure = ptc = xmalloc (sizeof (script_target_closure_t));
+
+ ptc->width = width;
+ ptc->height = height;
+
+ xasprintf (&ptc->filename, "%s.out.cs", name);
+ xunlink (ptc->filename);
+
+ surface = cairo_script_surface_create (ptc->filename, width, height);
+
+ status = cairo_surface_set_user_data (surface,
+ &script_closure_key, ptc, NULL);
+ if (status == CAIRO_STATUS_SUCCESS)
+ return surface;
+
+ cairo_surface_destroy (surface);
+ surface = cairo_boilerplate_surface_create_in_error (status);
+
+ free (ptc->filename);
+ free (ptc);
+ return surface;
+}
+
+cairo_status_t
+_cairo_boilerplate_script_finish_surface (cairo_surface_t *surface)
+{
+ cairo_surface_finish (surface);
+ return cairo_surface_status (surface);
+}
+
+cairo_status_t
+_cairo_boilerplate_script_surface_write_to_png (cairo_surface_t *surface,
+ const char *filename)
+{
+ return CAIRO_STATUS_WRITE_ERROR;
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_script_convert_to_image (cairo_surface_t *surface,
+ int page)
+{
+ script_target_closure_t *ptc = cairo_surface_get_user_data (surface,
+ &script_closure_key);
+ return cairo_boilerplate_convert_to_image (ptc->filename, page);
+}
+
+cairo_surface_t *
+_cairo_boilerplate_script_get_image_surface (cairo_surface_t *surface,
+ int page,
+ int width,
+ int height)
+{
+ cairo_surface_t *image;
+
+ image = _cairo_boilerplate_script_convert_to_image (surface, page);
+ cairo_surface_set_device_offset (image,
+ cairo_image_surface_get_width (image) - width,
+ cairo_image_surface_get_height (image) - height);
+ surface = _cairo_boilerplate_get_image_surface (image, 0, width, height);
+ cairo_surface_destroy (image);
+
+ return surface;
+}
+
+void
+_cairo_boilerplate_script_cleanup (void *closure)
+{
+ script_target_closure_t *ptc = closure;
+ free (ptc->filename);
+ free (ptc);
+}
diff --git a/boilerplate/cairo-boilerplate-svg.c b/boilerplate/cairo-boilerplate-svg.c
index 195dc786..e6c1355f 100644
--- a/boilerplate/cairo-boilerplate-svg.c
+++ b/boilerplate/cairo-boilerplate-svg.c
@@ -65,7 +65,7 @@ _cairo_boilerplate_svg_create_surface (const char *name,
ptc->width = width;
ptc->height = height;
- xasprintf (&ptc->filename, "%s-out.svg", name);
+ xasprintf (&ptc->filename, "%s.out.svg", name);
xunlink (ptc->filename);
surface = cairo_svg_surface_create (ptc->filename, width, height);
diff --git a/boilerplate/cairo-boilerplate-win32-printing.c b/boilerplate/cairo-boilerplate-win32-printing.c
index a5f21fff..13a65515 100644
--- a/boilerplate/cairo-boilerplate-win32-printing.c
+++ b/boilerplate/cairo-boilerplate-win32-printing.c
@@ -181,7 +181,7 @@ _cairo_boilerplate_win32_printing_create_surface (const char *name,
*closure = ptc = xmalloc (sizeof (win32_target_closure_t));
- xasprintf (&ptc->filename, "%s-out.ps", name);
+ xasprintf (&ptc->filename, "%s.out.ps", name);
xunlink (ptc->filename);
memset (&di, 0, sizeof (DOCINFO));
diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c
index 632624f5..f6f68f9c 100644
--- a/boilerplate/cairo-boilerplate.c
+++ b/boilerplate/cairo-boilerplate.c
@@ -47,6 +47,9 @@
#if CAIRO_HAS_QUARTZ_SURFACE
#include "cairo-boilerplate-quartz-private.h"
#endif
+#if CAIRO_HAS_SCRIPT_SURFACE
+#include "cairo-boilerplate-script-private.h"
+#endif
#if CAIRO_HAS_SDL_SURFACE
#include "cairo-boilerplate-sdl-private.h"
#endif
@@ -313,7 +316,9 @@ static cairo_boilerplate_target_t targets[] =
_cairo_boilerplate_test_meta_create_surface, NULL,
NULL,
_cairo_boilerplate_get_image_surface,
- cairo_surface_write_to_png
+ cairo_surface_write_to_png,
+ NULL, NULL,
+ FALSE, TRUE
},
{
"test-meta", "image", NULL,
@@ -322,7 +327,9 @@ static cairo_boilerplate_target_t targets[] =
_cairo_boilerplate_test_meta_create_surface, NULL,
NULL,
_cairo_boilerplate_get_image_surface,
- cairo_surface_write_to_png
+ cairo_surface_write_to_png,
+ NULL, NULL,
+ FALSE, TRUE
},
{
"test-paginated", "image", NULL,
@@ -332,7 +339,9 @@ static cairo_boilerplate_target_t targets[] =
NULL,
_cairo_boilerplate_test_paginated_get_image_surface,
_cairo_boilerplate_test_paginated_surface_write_to_png,
- _cairo_boilerplate_test_paginated_cleanup
+ _cairo_boilerplate_test_paginated_cleanup,
+ NULL,
+ FALSE, TRUE,
},
{
"test-paginated", "image", NULL,
@@ -342,7 +351,9 @@ static cairo_boilerplate_target_t targets[] =
NULL,
_cairo_boilerplate_test_paginated_get_image_surface,
_cairo_boilerplate_test_paginated_surface_write_to_png,
- _cairo_boilerplate_test_paginated_cleanup
+ _cairo_boilerplate_test_paginated_cleanup,
+ NULL,
+ FALSE, TRUE
},
#endif
#ifdef CAIRO_HAS_GLITZ_SURFACE
@@ -457,7 +468,7 @@ static cairo_boilerplate_target_t targets[] =
_cairo_boilerplate_win32_printing_get_image_surface,
_cairo_boilerplate_win32_printing_surface_write_to_png,
_cairo_boilerplate_win32_printing_cleanup,
- NULL, TRUE
+ NULL, TRUE, TRUE
},
{
"win32-printing", "win32"".ps",
@@ -467,7 +478,7 @@ static cairo_boilerplate_target_t targets[] =
_cairo_boilerplate_win32_printing_get_image_surface,
_cairo_boilerplate_win32_printing_surface_write_to_png,
_cairo_boilerplate_win32_printing_cleanup,
- NULL, TRUE
+ NULL, TRUE, TRUE
},
#endif
#endif
@@ -533,7 +544,7 @@ static cairo_boilerplate_target_t targets[] =
_cairo_boilerplate_ps_get_image_surface,
_cairo_boilerplate_ps_surface_write_to_png,
_cairo_boilerplate_ps_cleanup,
- NULL, TRUE
+ NULL, TRUE, TRUE
},
{
"ps2", "ps", ".ps",
@@ -544,7 +555,7 @@ static cairo_boilerplate_target_t targets[] =
_cairo_boilerplate_ps_get_image_surface,
_cairo_boilerplate_ps_surface_write_to_png,
_cairo_boilerplate_ps_cleanup,
- NULL, TRUE
+ NULL, TRUE, TRUE
},
{
"ps3", "ps", ".ps",
@@ -556,7 +567,7 @@ static cairo_boilerplate_target_t targets[] =
_cairo_boilerplate_ps_get_image_surface,
_cairo_boilerplate_ps_surface_write_to_png,
_cairo_boilerplate_ps_cleanup,
- NULL, TRUE
+ NULL, TRUE, TRUE
},
{
"ps3", "ps", ".ps",
@@ -567,7 +578,7 @@ static cairo_boilerplate_target_t targets[] =
_cairo_boilerplate_ps_get_image_surface,
_cairo_boilerplate_ps_surface_write_to_png,
_cairo_boilerplate_ps_cleanup,
- NULL, TRUE
+ NULL, TRUE, TRUE
},
#endif
#if CAIRO_HAS_PDF_SURFACE && CAIRO_CAN_TEST_PDF_SURFACE
@@ -581,7 +592,7 @@ static cairo_boilerplate_target_t targets[] =
_cairo_boilerplate_pdf_get_image_surface,
_cairo_boilerplate_pdf_surface_write_to_png,
_cairo_boilerplate_pdf_cleanup,
- NULL, TRUE
+ NULL, TRUE, TRUE
},
{
"pdf", "pdf", ".pdf",
@@ -592,7 +603,20 @@ static cairo_boilerplate_target_t targets[] =
_cairo_boilerplate_pdf_get_image_surface,
_cairo_boilerplate_pdf_surface_write_to_png,
_cairo_boilerplate_pdf_cleanup,
- NULL, TRUE
+ NULL, TRUE, TRUE
+ },
+#endif
+#if CAIRO_HAS_SCRIPT_SURFACE
+ {
+ "script", "script", ".cs",
+ CAIRO_SURFACE_TYPE_SCRIPT, CAIRO_CONTENT_COLOR_ALPHA, 0,
+ _cairo_boilerplate_script_create_surface,
+ NULL,
+ _cairo_boilerplate_script_finish_surface,
+ _cairo_boilerplate_script_get_image_surface,
+ _cairo_boilerplate_script_surface_write_to_png,
+ _cairo_boilerplate_script_cleanup,
+ NULL, FALSE
},
#endif
#if CAIRO_HAS_SVG_SURFACE && CAIRO_CAN_TEST_SVG_SURFACE
@@ -610,7 +634,7 @@ static cairo_boilerplate_target_t targets[] =
_cairo_boilerplate_svg_get_image_surface,
_cairo_boilerplate_svg_surface_write_to_png,
_cairo_boilerplate_svg_cleanup,
- NULL, TRUE
+ NULL, TRUE, TRUE
},
{
"svg11", "svg", NULL,
@@ -621,7 +645,7 @@ static cairo_boilerplate_target_t targets[] =
_cairo_boilerplate_svg_get_image_surface,
_cairo_boilerplate_svg_surface_write_to_png,
_cairo_boilerplate_svg_cleanup,
- NULL, TRUE
+ NULL, TRUE, TRUE
},
{
"svg12", "svg", NULL,
@@ -632,7 +656,7 @@ static cairo_boilerplate_target_t targets[] =
_cairo_boilerplate_svg_get_image_surface,
_cairo_boilerplate_svg_surface_write_to_png,
_cairo_boilerplate_svg_cleanup,
- NULL, TRUE
+ NULL, TRUE, TRUE
},
{
"svg12", "svg", NULL,
@@ -643,7 +667,7 @@ static cairo_boilerplate_target_t targets[] =
_cairo_boilerplate_svg_get_image_surface,
_cairo_boilerplate_svg_surface_write_to_png,
_cairo_boilerplate_svg_cleanup,
- NULL, TRUE
+ NULL, TRUE, TRUE
},
#endif
#if CAIRO_HAS_BEOS_SURFACE
@@ -982,6 +1006,8 @@ cairo_boilerplate_image_surface_create_from_ppm_stream (FILE *file)
for (x = 0; x < width; x++) {
if (! freadn (buf, 3, file))
goto FAIL;
+ *(uint32_t *) buf =
+ (buf[0] << 16) | (buf[1] << 8) | (buf[2] << 0);
buf += 4;
}
break;
diff --git a/boilerplate/cairo-boilerplate.h b/boilerplate/cairo-boilerplate.h
index 9d12b8dd..19b29572 100644
--- a/boilerplate/cairo-boilerplate.h
+++ b/boilerplate/cairo-boilerplate.h
@@ -162,6 +162,7 @@ typedef struct _cairo_boilerplate_target
cairo_boilerplate_cleanup_t cleanup;
cairo_boilerplate_wait_t synchronize;
cairo_bool_t is_vector;
+ cairo_bool_t is_meta;
} cairo_boilerplate_target_t;
cairo_boilerplate_target_t **
diff --git a/build/Makefile.am.changelog b/build/Makefile.am.changelog
index b9fbdcf3..888f4e79 100644
--- a/build/Makefile.am.changelog
+++ b/build/Makefile.am.changelog
@@ -71,7 +71,7 @@ $(srcdir)/ChangeLog.cache-% $(srcdir)/ChangeLog.pre-%:
test "x$$from" = xinitial || from=$$from.0; \
spec=$$from..$$to; \
fi; \
- $(srcdir)/build/missing --run git-log --stat "$$spec") > $@.tmp \
+ $(top_srcdir)/build/missing --run git-log --stat "$$spec") > $@.tmp \
&& mv -f $@.tmp $@ \
|| ($(RM) $@.tmp; \
echo Failed to generate $@, your $@ may be outdated >&2); \
diff --git a/build/aclocal.dolt.m4 b/build/aclocal.dolt.m4
index 8c75480a..8f94582f 100644
--- a/build/aclocal.dolt.m4
+++ b/build/aclocal.dolt.m4
@@ -157,7 +157,7 @@ for arg in "$[]@"; do
case "$arg" in
--mode=compile) modeok=true ;;
--tag=CC|--tag=CXX) tagok=true ;;
- *) args+=("$arg")
+ *) args@<:@${#args[@]}@:>@="$arg" ;;
esac
done
if $modeok && $tagok ; then
diff --git a/build/configure.ac.features b/build/configure.ac.features
index 9fa7086a..71738083 100644
--- a/build/configure.ac.features
+++ b/build/configure.ac.features
@@ -367,6 +367,7 @@ AC_DEFUN([CAIRO_REPORT],
echo " XCB: $use_xcb"
echo " Win32: $use_win32"
echo " OS2: $use_os2"
+ echo " CairoScript: $use_script"
echo " PostScript: $use_ps"
echo " PDF: $use_pdf"
echo " SVG: $use_svg"
diff --git a/build/configure.ac.system b/build/configure.ac.system
index d06b7989..4544a54f 100644
--- a/build/configure.ac.system
+++ b/build/configure.ac.system
@@ -69,7 +69,7 @@ AC_CHECK_HEADER(fenv.h,
dnl check for misc headers and functions
AC_CHECK_HEADERS([libgen.h byteswap.h signal.h setjmp.h])
-AC_CHECK_FUNCS([vasnprintf link ctime_r drand48 flockfile])
+AC_CHECK_FUNCS([vasnprintf link ctime_r drand48 flockfile ffs])
dnl check for win32 headers (this detects mingw as well)
AC_CHECK_HEADERS([windows.h], have_windows=yes, have_windows=no)
diff --git a/configure.ac b/configure.ac
index da2f8613..47a3ac60 100644
--- a/configure.ac
+++ b/configure.ac
@@ -29,7 +29,10 @@ AC_CACHE_SAVE
dnl ===========================================================================
AC_CHECK_LIB(z, compress,
- [AC_CHECK_HEADER(zlib.h, [have_libz=yes],
+ [AC_CHECK_HEADER(zlib.h, [
+ have_libz=yes
+ AC_DEFINE(HAVE_ZLIB, 1, [Define to 1 if you have zlib available])
+ ],
[have_libz="no (requires zlib http://www.gzip.org/zlib/)"])],
[have_libz="no (requires zlib http://www.gzip.org/zlib/)"])
@@ -236,6 +239,13 @@ CAIRO_ENABLE_SURFACE_BACKEND(directfb, directfb, no, [
dnl ===========================================================================
+any2ppm_cs=no
+CAIRO_ENABLE_SURFACE_BACKEND(script, script, no, [
+ any2ppm_cs=yes
+])
+
+dnl ===========================================================================
+
# We use pkg-config to look for freetype2, but fall back to
# freetype-config if it fails. We prefer pkg-config, since we can
# then just put freetype2 >= $FREETYPE_MIN_VERSION in
@@ -391,7 +401,7 @@ test_pdf=no
any2ppm_pdf=no
if test "x$use_pdf" = "xyes"; then
poppler_DEPENDENCY="poppler-glib >= $POPPLER_VERSION_REQUIRED"
- PKG_CHECK_MODULES(POPPLER, $poppler_DEPENDENCY pango gtk+-2.0,
+ PKG_CHECK_MODULES(POPPLER, $poppler_DEPENDENCY,
[CAIRO_CHECK_FUNCS_WITH_FLAGS(poppler_page_render, [$POPPLER_CFLAGS], [$POPPLER_LIBS],
[test_pdf=yes; any2ppm_pdf=yes],
[AC_MSG_RESULT(no); test_pdf="no (requires $poppler_DEPENDENCY)"])],
@@ -478,7 +488,8 @@ dnl Build the external converter if we have any of the test backends
AM_CONDITIONAL(BUILD_ANY2PPM,
test "x$any2ppm_svg" = "xyes" \
-o "x$any2ppm_pdf" = "xyes" \
- -o "x$any2ppm_ps" = "xyes")
+ -o "x$any2ppm_ps" = "xyes" \
+ -o "x$any2ppm_cs" = "xyes")
dnl ===========================================================================
dnl The tracing utility requires LD_PRELOAD, so only build it for systems
@@ -493,7 +504,18 @@ case $host in
;;
esac
-AM_CONDITIONAL(BUILD_TRACE, test "x$have_ld_preload" = "xyes")
+AM_CONDITIONAL(BUILD_TRACE,
+ test "x$have_ld_preload" = "xyes" \
+ -a "x$have_libz" = "xyes")
+
+AC_CHECK_LIB(bfd, bfd_openr,
+ [AC_CHECK_HEADER(bfd.h, [have_bfd=yes],
+ [have_bfd=no])], [have_bfd=no])
+if test "x$have_bfd" = "xyes"; then
+ AC_DEFINE([HAVE_BFD], [1], [Define to 1 if you have the binutils development files installed])
+ BFD_LIBS=-lbfd
+ AC_SUBST(BFD_LIBS)
+fi
dnl ===========================================================================
@@ -531,6 +553,7 @@ test/Makefile
test/pdiff/Makefile
perf/Makefile
util/Makefile
+util/cairo-script/Makefile
util/cairo-trace/Makefile
util/cairo-trace/cairo-trace
doc/Makefile
diff --git a/doc/public/tmpl/cairo-surface.sgml b/doc/public/tmpl/cairo-surface.sgml
index 3a6cd8d9..93bfe083 100644
--- a/doc/public/tmpl/cairo-surface.sgml
+++ b/doc/public/tmpl/cairo-surface.sgml
@@ -194,6 +194,7 @@ cairo_<emphasis>backend</emphasis>_surface_create().
@CAIRO_SURFACE_TYPE_WIN32_PRINTING:
@CAIRO_SURFACE_TYPE_QUARTZ_IMAGE:
@CAIRO_SURFACE_TYPE_SDL:
+@CAIRO_SURFACE_TYPE_SCRIPT:
<!-- ##### FUNCTION cairo_surface_get_type ##### -->
<para>
diff --git a/perf/Makefile.am b/perf/Makefile.am
index edd4c685..5dcc0ab3 100644
--- a/perf/Makefile.am
+++ b/perf/Makefile.am
@@ -41,7 +41,11 @@ cairo_perf_SOURCES = \
world-map.h \
zrusin.c \
zrusin-another.h \
- long-dashed-lines.c
+ long-dashed-lines.c \
+ dragon.c \
+ pythagoras-tree.c \
+ intersections.c \
+ spiral.c
if CAIRO_HAS_WIN32_SURFACE
cairo_perf_SOURCES += cairo-perf-win32.c
@@ -52,6 +56,11 @@ else
cairo_perf_SOURCES += cairo-perf-posix.c
endif
endif
+cairo_perf_LDADD = $(LDADD)
+
+if CAIRO_HAS_SDL_SURFACE
+cairo_perf_LDADD += $(sdl_LIBS)
+endif
libcairoperf_la_SOURCES = \
cairo-perf-report.c \
diff --git a/perf/cairo-perf-diff b/perf/cairo-perf-diff
index 50cd1f2c..718cdc57 100755
--- a/perf/cairo-perf-diff
+++ b/perf/cairo-perf-diff
@@ -89,7 +89,7 @@ fi
git_setup() {
SUBDIRECTORY_OK='Yes'
- . git-sh-setup
+ . "$(git --exec-path)/git-sh-setup"
CAIRO_DIR=`dirname $GIT_DIR`
if [ "$CAIRO_DIR" = "." ]; then
CAIRO_DIR=`pwd`
diff --git a/perf/cairo-perf.c b/perf/cairo-perf.c
index a6d59a57..6bb48f13 100644
--- a/perf/cairo-perf.c
+++ b/perf/cairo-perf.c
@@ -33,6 +33,10 @@
#include "cairo-boilerplate-getopt.h"
+#if CAIRO_HAS_SDL_SURFACE
+#include <SDL_main.h>
+#endif
+
/* For basename */
#ifdef HAVE_LIBGEN_H
#include <libgen.h>
@@ -459,5 +463,9 @@ const cairo_perf_case_t perf_cases[] = {
{ long_dashed_lines, 512, 512},
{ composite_checker, 16, 512},
{ twin, 800, 800},
+ { dragon, 1024, 1024 },
+ { pythagoras_tree, 768, 768 },
+ { intersections, 512, 512 },
+ { spiral, 512, 512 },
{ NULL }
};
diff --git a/perf/cairo-perf.h b/perf/cairo-perf.h
index 0cedb691..3affcb82 100644
--- a/perf/cairo-perf.h
+++ b/perf/cairo-perf.h
@@ -173,5 +173,9 @@ CAIRO_PERF_DECL (rounded_rectangles);
CAIRO_PERF_DECL (long_dashed_lines);
CAIRO_PERF_DECL (composite_checker);
CAIRO_PERF_DECL (twin);
+CAIRO_PERF_DECL (dragon);
+CAIRO_PERF_DECL (pythagoras_tree);
+CAIRO_PERF_DECL (intersections);
+CAIRO_PERF_DECL (spiral);
#endif
diff --git a/perf/dragon.c b/perf/dragon.c
new file mode 100644
index 00000000..6d0328eb
--- /dev/null
+++ b/perf/dragon.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright © 2007 Chris Wilson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Chris Wilson not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Chris Wilson makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ * Inspiration (and path!) taken from
+ * http://labs.trolltech.com/blogs/2007/08/31/rasterizing-dragons/
+ */
+
+#include "cairo-perf.h"
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+static inline int
+next_pot (int v)
+{
+ v--;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ v++;
+ return v;
+}
+
+static cairo_bool_t
+direction (int i)
+{
+ int pivot, np2;
+
+ if (i < 2)
+ return TRUE;
+
+ np2 = next_pot (i + 1);
+ if (np2 == i + 1)
+ return TRUE;
+
+ pivot = np2 / 2 - 1;
+ return ! direction (2 * pivot - i);
+}
+
+
+static void
+path (cairo_t *cr, int step, int dir, int iterations)
+{
+ double dx, dy;
+ int i;
+
+ switch (dir) {
+ case 0: dx = step; dy = 0; break;
+ case 1: dx = -step; dy = 0; break;
+ case 2: dx = 0; dy = step; break;
+ case 3: dx = 0; dy = -step; break;
+ }
+
+ for (i = 0; i < iterations; i++) {
+ cairo_rel_line_to (cr, dx, dy);
+
+ if (direction (i)) {
+ double t = dx;
+ dx = dy;
+ dy = -t;
+ } else {
+ double t = dx;
+ dx = -dy;
+ dy = t;
+ }
+ }
+}
+
+static cairo_perf_ticks_t
+do_dragon (cairo_t *cr, int width, int height)
+{
+ cairo_pattern_t *pattern;
+ double cx, cy, r;
+
+ cx = cy = .5 * MAX (width, height);
+ r = .5 * MIN (width, height);
+
+ cairo_perf_timer_start ();
+
+ pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r);
+ cairo_pattern_add_color_stop_rgb (pattern, 0., .0, .0, .0);
+ cairo_pattern_add_color_stop_rgb (pattern, 0.25, .5, .4, .4);
+ cairo_pattern_add_color_stop_rgb (pattern, .5, .8, .8, .9);
+ cairo_pattern_add_color_stop_rgb (pattern, 1., .9, .9, 1.);
+ cairo_set_source (cr, pattern);
+ cairo_pattern_destroy (pattern);
+ cairo_paint (cr);
+
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+ cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
+ cairo_set_line_width (cr, 4.);
+
+ cairo_move_to (cr, cx, cy);
+ path (cr, 12, 0, 2048);
+ pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r);
+ cairo_pattern_add_color_stop_rgb (pattern, 0., 1., 1., 1.);
+ cairo_pattern_add_color_stop_rgb (pattern, 1., 0., 0., 0.);
+ cairo_set_source (cr, pattern);
+ cairo_pattern_destroy (pattern);
+ cairo_stroke(cr);
+
+ cairo_move_to (cr, cx, cy);
+ path (cr, 12, 1, 2048);
+ pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r);
+ cairo_pattern_add_color_stop_rgb (pattern, 1., 1., 1., 0.);
+ cairo_pattern_add_color_stop_rgb (pattern, 0., 1., 0., 0.);
+ cairo_set_source (cr, pattern);
+ cairo_pattern_destroy (pattern);
+ cairo_stroke(cr);
+
+ cairo_move_to (cr, cx, cy);
+ path (cr, 12, 2, 2048);
+ pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r);
+ cairo_pattern_add_color_stop_rgb (pattern, 1., 0., 1., 1.);
+ cairo_pattern_add_color_stop_rgb (pattern, 0., 0., 1., 0.);
+ cairo_set_source (cr, pattern);
+ cairo_pattern_destroy (pattern);
+ cairo_stroke(cr);
+
+ cairo_move_to (cr, cx, cy);
+ path (cr, 12, 3, 2048);
+ pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r);
+ cairo_pattern_add_color_stop_rgb (pattern, 1., 1., 0., 1.);
+ cairo_pattern_add_color_stop_rgb (pattern, 0., 0., 0., 1.);
+ cairo_set_source (cr, pattern);
+ cairo_pattern_destroy (pattern);
+ cairo_stroke(cr);
+
+ cairo_perf_timer_stop ();
+
+ return cairo_perf_timer_elapsed ();
+}
+
+void
+dragon (cairo_perf_t *perf, cairo_t *cr, int width, int height)
+{
+ cairo_perf_run (perf, "dragon", do_dragon);
+}
diff --git a/perf/intersections.c b/perf/intersections.c
new file mode 100644
index 00000000..5e410366
--- /dev/null
+++ b/perf/intersections.c
@@ -0,0 +1,97 @@
+/* -*- 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 "cairo-perf.h"
+
+#define NUM_SEGMENTS 256
+
+static unsigned state;
+static double
+uniform_random (double minval, double maxval)
+{
+ static unsigned const poly = 0x9a795537U;
+ unsigned n = 32;
+ while (n-->0)
+ state = 2*state < state ? (2*state ^ poly) : 2*state;
+ return minval + state * (maxval - minval) / 4294967296.0;
+}
+
+static cairo_perf_ticks_t
+draw_random (cairo_t *cr, cairo_fill_rule_t fill_rule, int width, int height)
+{
+ int i;
+ double x[NUM_SEGMENTS];
+ double y[NUM_SEGMENTS];
+
+ cairo_save (cr);
+ cairo_set_source_rgb (cr, 0, 0, 0);
+ cairo_paint (cr);
+
+ for (i = 0; i < NUM_SEGMENTS; i++) {
+ x[i] = uniform_random (0, width);
+ y[i] = uniform_random (0, height);
+ }
+
+ state = 0x12345678;
+ cairo_translate (cr, 1, 1);
+ cairo_set_fill_rule (cr, fill_rule);
+ cairo_set_source_rgb (cr, 1, 0, 0);
+
+ cairo_perf_timer_start (); {
+
+ cairo_move_to (cr, 0, 0);
+ for (i = 0; i < NUM_SEGMENTS; i++) {
+ cairo_line_to (cr, x[i], y[i]);
+ }
+ cairo_close_path (cr);
+
+ cairo_fill (cr);
+ }
+ cairo_perf_timer_stop ();
+
+ cairo_restore (cr);
+
+ return cairo_perf_timer_elapsed ();
+}
+
+static cairo_perf_ticks_t
+random_eo (cairo_t *cr, int width, int height)
+{
+ return draw_random (cr, CAIRO_FILL_RULE_EVEN_ODD, width, height);
+}
+
+static cairo_perf_ticks_t
+random_nz (cairo_t *cr, int width, int height)
+{
+ return draw_random (cr, CAIRO_FILL_RULE_WINDING, width, height);
+}
+
+void
+intersections (cairo_perf_t *perf, cairo_t *cr, int width, int height)
+{
+ cairo_perf_run (perf, "intersections-nz-fill", random_nz);
+ cairo_perf_run (perf, "intersections-eo-fill", random_eo);
+}
diff --git a/perf/pythagoras-tree.c b/perf/pythagoras-tree.c
new file mode 100644
index 00000000..5a78d8a7
--- /dev/null
+++ b/perf/pythagoras-tree.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright © 2007 Chris Wilson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Chris Wilson not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Chris Wilson makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairo-perf.h"
+#include <math.h>
+
+static void
+add_rectangle (cairo_t *cr, double size)
+{
+ double x, y;
+
+ if (size < 1)
+ return;
+
+ cairo_get_current_point (cr, &x, &y);
+
+ cairo_rel_move_to (cr, -size/2., -size/2.);
+ cairo_rel_line_to (cr, size, 0);
+ cairo_rel_line_to (cr, 0, size);
+ cairo_rel_line_to (cr, -size, 0);
+ cairo_close_path (cr);
+
+ cairo_save (cr);
+ cairo_translate (cr, -size/2., size);
+ cairo_move_to (cr, x, y);
+ cairo_rotate (cr, M_PI/4);
+ add_rectangle (cr, size / M_SQRT2);
+ cairo_restore (cr);
+
+ cairo_save (cr);
+ cairo_translate (cr, size/2., size);
+ cairo_move_to (cr, x, y);
+ cairo_rotate (cr, -M_PI/4);
+ add_rectangle (cr, size / M_SQRT2);
+ cairo_restore (cr);
+}
+
+static cairo_perf_ticks_t
+do_pythagoras_tree (cairo_t *cr, int width, int height)
+{
+ double size = 128;
+
+ cairo_perf_timer_start ();
+
+ cairo_save (cr);
+ cairo_translate (cr, 0, height);
+ cairo_scale (cr, 1, -1);
+
+ cairo_move_to (cr, width/2, size/2);
+ add_rectangle (cr, size);
+ cairo_set_source_rgb (cr, 0., 0., 0.);
+ cairo_fill (cr);
+ cairo_restore (cr);
+
+ cairo_perf_timer_stop ();
+
+ return cairo_perf_timer_elapsed ();
+}
+
+void
+pythagoras_tree (cairo_perf_t *perf, cairo_t *cr, int width, int height)
+{
+ cairo_perf_run (perf, "pythagoras_tree", do_pythagoras_tree);
+}
diff --git a/perf/spiral.c b/perf/spiral.c
new file mode 100644
index 00000000..f26d0a2b
--- /dev/null
+++ b/perf/spiral.c
@@ -0,0 +1,200 @@
+/* -*- 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 <assert.h>
+#include "cairo-perf.h"
+
+#define MAX_SEGMENTS 2560
+
+typedef enum {
+ PIXALIGN, /* pixel aligned path */
+ NONALIGN /* unaligned path. */
+} align_t;
+
+typedef enum {
+ RECTCLOSE, /* keeps the path rectilinear */
+ DIAGCLOSE /* forces a diagonal */
+} close_t;
+
+static cairo_perf_ticks_t
+draw_spiral (cairo_t *cr,
+ cairo_fill_rule_t fill_rule,
+ align_t align,
+ close_t close,
+ int width, int height)
+{
+ int i;
+ int n=0;
+ double x[MAX_SEGMENTS];
+ double y[MAX_SEGMENTS];
+ int step = 3;
+ int side = width < height ? width : height;
+
+ assert(5*(side/step/2+1)+2 < MAX_SEGMENTS);
+
+#define L(x_,y_) (x[n] = (x_), y[n] = (y_), n++)
+#define M(x_,y_) L(x_,y_)
+#define v(t) L(x[n-1], y[n-1] + (t))
+#define h(t) L(x[n-1] + (t), y[n-1])
+
+ switch (align) {
+ case PIXALIGN: M(0,0); break;
+ case NONALIGN: M(0.1415926, 0.7182818); break;
+ }
+
+ while (side >= step && side >= 0) {
+ v(side);
+ h(side);
+ v(-side);
+ h(-side+step);
+ v(step);
+ side -= 2*step;
+ }
+
+ switch (close) {
+ case RECTCLOSE: L(x[n-1],y[0]); break;
+ case DIAGCLOSE: L(x[0],y[0]); break;
+ }
+
+ assert(n < MAX_SEGMENTS);
+
+ cairo_save (cr);
+ cairo_set_source_rgb (cr, 0, 0, 0);
+ cairo_paint (cr);
+
+ cairo_translate (cr, 1, 1);
+ cairo_set_fill_rule (cr, fill_rule);
+ cairo_set_source_rgb (cr, 1, 0, 0);
+
+ cairo_perf_timer_start (); {
+
+ cairo_move_to (cr, x[0], y[0]);
+ for (i = 1; i < n; i++) {
+ cairo_line_to (cr, x[i], y[i]);
+ }
+ cairo_close_path (cr);
+
+ cairo_fill (cr);
+ }
+ cairo_perf_timer_stop ();
+
+ cairo_restore (cr);
+
+ return cairo_perf_timer_elapsed ();
+}
+
+static cairo_perf_ticks_t
+draw_spiral_eo_pa_re (cairo_t *cr, int width, int height)
+{
+ return draw_spiral (cr,
+ CAIRO_FILL_RULE_EVEN_ODD,
+ PIXALIGN,
+ RECTCLOSE,
+ width, height);
+}
+
+static cairo_perf_ticks_t
+draw_spiral_nz_pa_re (cairo_t *cr, int width, int height)
+{
+ return draw_spiral (cr,
+ CAIRO_FILL_RULE_WINDING,
+ PIXALIGN,
+ RECTCLOSE,
+ width, height);
+}
+
+static cairo_perf_ticks_t
+draw_spiral_eo_na_re (cairo_t *cr, int width, int height)
+{
+ return draw_spiral (cr,
+ CAIRO_FILL_RULE_EVEN_ODD,
+ NONALIGN,
+ RECTCLOSE,
+ width, height);
+}
+
+static cairo_perf_ticks_t
+draw_spiral_nz_na_re (cairo_t *cr, int width, int height)
+{
+ return draw_spiral (cr,
+ CAIRO_FILL_RULE_WINDING,
+ NONALIGN,
+ RECTCLOSE,
+ width, height);
+}
+
+static cairo_perf_ticks_t
+draw_spiral_eo_pa_di (cairo_t *cr, int width, int height)
+{
+ return draw_spiral (cr,
+ CAIRO_FILL_RULE_EVEN_ODD,
+ PIXALIGN,
+ DIAGCLOSE,
+ width, height);
+}
+
+static cairo_perf_ticks_t
+draw_spiral_nz_pa_di (cairo_t *cr, int width, int height)
+{
+ return draw_spiral (cr,
+ CAIRO_FILL_RULE_WINDING,
+ PIXALIGN,
+ DIAGCLOSE,
+ width, height);
+}
+
+static cairo_perf_ticks_t
+draw_spiral_eo_na_di (cairo_t *cr, int width, int height)
+{
+ return draw_spiral (cr,
+ CAIRO_FILL_RULE_EVEN_ODD,
+ NONALIGN,
+ DIAGCLOSE,
+ width, height);
+}
+
+static cairo_perf_ticks_t
+draw_spiral_nz_na_di (cairo_t *cr, int width, int height)
+{
+ return draw_spiral (cr,
+ CAIRO_FILL_RULE_WINDING,
+ NONALIGN,
+ DIAGCLOSE,
+ width, height);
+}
+
+void
+spiral (cairo_perf_t *perf, cairo_t *cr, int width, int height)
+{
+ cairo_perf_run (perf, "spiral-diag-nonalign-evenodd-fill", draw_spiral_eo_na_di);
+ cairo_perf_run (perf, "spiral-diag-nonalign-nonzero-fill", draw_spiral_nz_na_di);
+ cairo_perf_run (perf, "spiral-diag-pixalign-evenodd-fill", draw_spiral_eo_pa_di);
+ cairo_perf_run (perf, "spiral-diag-pixalign-nonzero-fill", draw_spiral_nz_pa_di);
+ cairo_perf_run (perf, "spiral-rect-nonalign-evenodd-fill", draw_spiral_eo_na_re);
+ cairo_perf_run (perf, "spiral-rect-nonalign-nonzero-fill", draw_spiral_nz_na_re);
+ cairo_perf_run (perf, "spiral-rect-pixalign-evenodd-fill", draw_spiral_eo_pa_re);
+ cairo_perf_run (perf, "spiral-rect-pixalign-nonzero-fill", draw_spiral_nz_pa_re);
+}
diff --git a/src/Makefile.am b/src/Makefile.am
index bf87efb7..b09fadf4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -84,9 +84,12 @@ TESTS += check-link$(EXEEXT)
endif
EXTRA_DIST += $(TESTS_SH) check-has-hidden-symbols.c
-check_PROGRAMS += check-link
+check_PROGRAMS += check-link check-skiplist
check_link_LDADD = libcairo.la
+check_skiplist_SOURCES = cairo-skiplist.c
+check_skiplist_CPPFLAGS = -DMAIN $(AM_CPPFLAGS)
+
check: headers-standalone
PREPROCESS_ARGS = $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS)
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 082b6af8..5f387f43 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -64,6 +64,7 @@ cairo_private = \
cairo-freelist-private.h \
cairo-gstate-private.h \
cairo-hash-private.h \
+ cairo-image-info-private.h \
cairo-malloc-private.h \
cairo-meta-surface-private.h \
cairo-mutex-impl-private.h \
@@ -80,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 \
@@ -108,6 +110,7 @@ cairo_sources = \
cairo-gstate.c \
cairo-hash.c \
cairo-hull.c \
+ cairo-image-info.c \
cairo-image-surface.c \
cairo-lzw.c \
cairo-matrix.c \
@@ -120,6 +123,7 @@ cairo_sources = \
cairo-path.c \
cairo-path-fill.c \
cairo-path-fixed.c \
+ cairo-path-in-fill.c \
cairo-path-stroke.c \
cairo-pattern.c \
cairo-pen.c \
@@ -129,10 +133,12 @@ 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 \
cairo-surface-fallback.c \
+ cairo-tor-scan-converter.c \
cairo-system.c \
cairo-traps.c \
cairo-unicode.c \
@@ -246,3 +252,6 @@ cairo_directfb_sources = cairo-directfb-surface.c
cairo_sdl_headers = cairo-sdl.h
cairo_sdl_sources = cairo-sdl-surface.c
+
+cairo_script_headers = cairo-script.h
+cairo_script_sources = cairo-script-surface.c
diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index 4337e92c..50005c21 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -283,9 +283,6 @@ _cairo_analysis_surface_intersect_clip_path (void *abstract_surface,
cairo_antialias_t antialias)
{
cairo_analysis_surface_t *surface = abstract_surface;
- double x1, y1, x2, y2;
- cairo_rectangle_int_t extent;
- cairo_bool_t is_empty;
if (path == NULL) {
surface->current_clip.x = 0;
@@ -293,17 +290,10 @@ _cairo_analysis_surface_intersect_clip_path (void *abstract_surface,
surface->current_clip.width = surface->width;
surface->current_clip.height = surface->height;
} else {
- cairo_status_t status;
-
- status = _cairo_path_fixed_bounds (path, &x1, &y1, &x2, &y2, tolerance);
- if (status)
- return status;
-
- extent.x = floor (x1);
- extent.y = floor (y1);
- extent.width = ceil (x2) - extent.x;
- extent.height = ceil (y2) - extent.y;
+ cairo_rectangle_int_t extent;
+ cairo_bool_t is_empty;
+ _cairo_path_fixed_approximate_extents (path, &extent);
is_empty = _cairo_rectangle_intersect (&surface->current_clip, &extent);
}
@@ -322,7 +312,8 @@ _cairo_analysis_surface_get_extents (void *abstract_surface,
static cairo_int_status_t
_cairo_analysis_surface_paint (void *abstract_surface,
cairo_operator_t op,
- const cairo_pattern_t *source)
+ const cairo_pattern_t *source,
+ cairo_rectangle_int_t *paint_extents)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
@@ -333,7 +324,7 @@ _cairo_analysis_surface_paint (void *abstract_surface,
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
else
backend_status = (*surface->target->backend->paint) (surface->target, op,
- source);
+ source, NULL);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
@@ -346,13 +337,15 @@ _cairo_analysis_surface_paint (void *abstract_surface,
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
- if (status)
+ if (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
}
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
+ if (paint_extents)
+ *paint_extents = extents;
status = _add_operation (surface, &extents, backend_status);
@@ -363,7 +356,8 @@ static cairo_int_status_t
_cairo_analysis_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- const cairo_pattern_t *mask)
+ const cairo_pattern_t *mask,
+ cairo_rectangle_int_t *mask_extents)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_int_status_t status, backend_status;
@@ -374,7 +368,7 @@ _cairo_analysis_surface_mask (void *abstract_surface,
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
else
backend_status = (*surface->target->backend->mask) (surface->target, op,
- source, mask);
+ source, mask, NULL);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN) {
cairo_int_status_t backend_source_status = CAIRO_STATUS_SUCCESS;
@@ -413,7 +407,7 @@ _cairo_analysis_surface_mask (void *abstract_surface,
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
- if (status)
+ if (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
@@ -423,13 +417,15 @@ _cairo_analysis_surface_mask (void *abstract_surface,
cairo_rectangle_int_t mask_extents;
status = _cairo_pattern_get_extents (mask, &mask_extents);
- if (status)
+ if (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
}
is_empty = _cairo_rectangle_intersect (&extents, &surface->current_clip);
+ if (mask_extents)
+ *mask_extents = extents;
status = _add_operation (surface, &extents, backend_status);
@@ -445,7 +441,8 @@ _cairo_analysis_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *stroke_extents)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
@@ -459,7 +456,7 @@ _cairo_analysis_surface_stroke (void *abstract_surface,
backend_status = (*surface->target->backend->stroke) (surface->target, op,
source, path, style,
ctm, ctm_inverse,
- tolerance, antialias);
+ tolerance, antialias, NULL);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
@@ -472,7 +469,7 @@ _cairo_analysis_surface_stroke (void *abstract_surface,
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
- if (status)
+ if (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
@@ -492,7 +489,7 @@ _cairo_analysis_surface_stroke (void *abstract_surface,
ctm, ctm_inverse,
tolerance,
&traps);
- if (status) {
+ if (unlikely (status)) {
_cairo_traps_fini (&traps);
return status;
}
@@ -502,6 +499,8 @@ _cairo_analysis_surface_stroke (void *abstract_surface,
_cairo_box_round_to_rectangle (&box, &extents);
}
+ if (stroke_extents)
+ *stroke_extents = extents;
status = _add_operation (surface, &extents, backend_status);
@@ -515,7 +514,8 @@ _cairo_analysis_surface_fill (void *abstract_surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *fill_extents)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
@@ -528,7 +528,7 @@ _cairo_analysis_surface_fill (void *abstract_surface,
else
backend_status = (*surface->target->backend->fill) (surface->target, op,
source, path, fill_rule,
- tolerance, antialias);
+ tolerance, antialias, NULL);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN)
backend_status = _analyze_meta_surface_pattern (surface, source);
@@ -541,7 +541,7 @@ _cairo_analysis_surface_fill (void *abstract_surface,
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
- if (status)
+ if (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
@@ -560,7 +560,7 @@ _cairo_analysis_surface_fill (void *abstract_surface,
fill_rule,
tolerance,
&traps);
- if (status) {
+ if (unlikely (status)) {
_cairo_traps_fini (&traps);
return status;
}
@@ -570,6 +570,8 @@ _cairo_analysis_surface_fill (void *abstract_surface,
_cairo_box_round_to_rectangle (&box, &extents);
}
+ if (fill_extents)
+ *fill_extents = extents;
status = _add_operation (surface, &extents, backend_status);
@@ -583,7 +585,8 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs)
+ int *remaining_glyphs,
+ cairo_rectangle_int_t *show_glyphs_extents)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
@@ -596,7 +599,7 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
source,
glyphs, num_glyphs,
scaled_font,
- remaining_glyphs);
+ remaining_glyphs, NULL);
else if (surface->target->backend->show_text_glyphs)
backend_status = surface->target->backend->show_text_glyphs (surface->target, op,
source,
@@ -604,7 +607,7 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
glyphs, num_glyphs,
NULL, 0,
FALSE,
- scaled_font);
+ scaled_font, NULL);
else
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
@@ -619,7 +622,7 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
- if (status)
+ if (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
@@ -632,11 +635,13 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
glyphs,
num_glyphs,
&glyph_extents);
- if (status)
+ if (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents);
}
+ if (show_glyphs_extents)
+ *show_glyphs_extents = extents;
status = _add_operation (surface, &extents, backend_status);
@@ -662,7 +667,8 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
- cairo_scaled_font_t *scaled_font)
+ cairo_scaled_font_t *scaled_font,
+ cairo_rectangle_int_t *show_text_glyphs_extents)
{
cairo_analysis_surface_t *surface = abstract_surface;
cairo_status_t status, backend_status;
@@ -677,14 +683,14 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters, cluster_flags,
- scaled_font);
+ scaled_font, NULL);
if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED && surface->target->backend->show_glyphs) {
int remaining_glyphs = num_glyphs;
backend_status = surface->target->backend->show_glyphs (surface->target, op,
source,
glyphs, num_glyphs,
scaled_font,
- &remaining_glyphs);
+ &remaining_glyphs, NULL);
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (remaining_glyphs == 0)
@@ -702,7 +708,7 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
- if (status)
+ if (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &source_extents);
@@ -715,11 +721,13 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
glyphs,
num_glyphs,
&glyph_extents);
- if (status)
+ if (unlikely (status))
return status;
is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents);
}
+ if (show_text_glyphs_extents)
+ *show_text_glyphs_extents = extents;
status = _add_operation (surface, &extents, backend_status);
@@ -738,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 */
@@ -772,11 +782,11 @@ _cairo_analysis_surface_create (cairo_surface_t *target,
cairo_status_t status;
status = target->status;
- if (status)
+ if (unlikely (status))
return _cairo_surface_create_in_error (status);
surface = malloc (sizeof (cairo_analysis_surface_t));
- if (surface == NULL)
+ if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
/* I believe the content type here is truly arbitrary. I'm quite
@@ -898,13 +908,15 @@ typedef cairo_int_status_t
typedef cairo_int_status_t
(*_paint_func) (void *surface,
cairo_operator_t op,
- const cairo_pattern_t *source);
+ const cairo_pattern_t *source,
+ cairo_rectangle_int_t *extents);
typedef cairo_int_status_t
(*_mask_func) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- const cairo_pattern_t *mask);
+ const cairo_pattern_t *mask,
+ cairo_rectangle_int_t *extents);
typedef cairo_int_status_t
(*_stroke_func) (void *surface,
@@ -915,7 +927,8 @@ typedef cairo_int_status_t
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
- cairo_antialias_t antialias);
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents);
typedef cairo_int_status_t
(*_fill_func) (void *surface,
@@ -924,7 +937,8 @@ typedef cairo_int_status_t
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
- cairo_antialias_t antialias);
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents);
typedef cairo_int_status_t
(*_show_glyphs_func) (void *surface,
@@ -933,7 +947,8 @@ typedef cairo_int_status_t
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs);
+ int *remaining_glyphs,
+ cairo_rectangle_int_t *extents);
static const cairo_surface_backend_t cairo_null_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_NULL,
@@ -948,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 */
@@ -979,7 +996,7 @@ _cairo_null_surface_create (cairo_content_t content)
cairo_surface_t *surface;
surface = malloc (sizeof (cairo_surface_t));
- if (surface == NULL) {
+ if (unlikely (surface == NULL)) {
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
diff --git a/src/cairo-array.c b/src/cairo-array.c
index f38cfe3e..9c084b9e 100644
--- a/src/cairo-array.c
+++ b/src/cairo-array.c
@@ -138,7 +138,7 @@ _cairo_array_grow_by (cairo_array_t *array, unsigned int additional)
if (array->elements == NULL) {
array->elements = malloc (sizeof (char *));
- if (array->elements == NULL)
+ if (unlikely (array->elements == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
*array->elements = NULL;
@@ -148,7 +148,7 @@ _cairo_array_grow_by (cairo_array_t *array, unsigned int additional)
new_elements = _cairo_realloc_ab (*array->elements,
array->size, array->element_size);
- if (new_elements == NULL) {
+ if (unlikely (new_elements == NULL)) {
array->size = old_size;
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -279,7 +279,7 @@ _cairo_array_append_multiple (cairo_array_t *array,
assert (! array->is_snapshot);
status = _cairo_array_allocate (array, num_elements, &dest);
- if (status)
+ if (unlikely (status))
return status;
memcpy (dest, elements, num_elements * array->element_size);
@@ -310,7 +310,7 @@ _cairo_array_allocate (cairo_array_t *array,
assert (! array->is_snapshot);
status = _cairo_array_grow_by (array, num_elements);
- if (status)
+ if (unlikely (status))
return status;
assert (array->num_elements + num_elements <= array->size);
@@ -489,7 +489,7 @@ _cairo_user_data_array_set_data (cairo_user_data_array_t *array,
}
status = _cairo_array_append (array, &new_slot);
- if (status)
+ if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
diff --git a/src/cairo-base85-stream.c b/src/cairo-base85-stream.c
index 88974039..9d42ef48 100644
--- a/src/cairo-base85-stream.c
+++ b/src/cairo-base85-stream.c
@@ -117,13 +117,14 @@ _cairo_base85_stream_create (cairo_output_stream_t *output)
return _cairo_output_stream_create_in_error (output->status);
stream = malloc (sizeof (cairo_base85_stream_t));
- if (stream == NULL) {
+ if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base,
_cairo_base85_stream_write,
+ NULL,
_cairo_base85_stream_close);
stream->output = output;
stream->pending = 0;
diff --git a/src/cairo-bentley-ottmann.c b/src/cairo-bentley-ottmann.c
index b22731df..cd150218 100644
--- a/src/cairo-bentley-ottmann.c
+++ b/src/cairo-bentley-ottmann.c
@@ -87,7 +87,7 @@ struct _cairo_bo_edge {
cairo_bo_point32_t top;
cairo_bo_point32_t middle;
cairo_bo_point32_t bottom;
- cairo_bool_t reversed;
+ int dir;
cairo_bo_edge_t *prev;
cairo_bo_edge_t *next;
cairo_bo_trap_t *deferred_trap;
@@ -979,7 +979,7 @@ _cairo_bo_event_queue_init (cairo_bo_event_queue_t *event_queue,
sizeof (cairo_bo_event_t) +
sizeof (cairo_bo_event_t *),
sizeof (cairo_bo_event_t *));
- if (events == NULL)
+ if (unlikely (events == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
sorted_event_ptrs = (cairo_bo_event_t **) (events + num_events);
@@ -1079,8 +1079,8 @@ _cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line,
cairo_bo_edge_t **prev_of_next, **next_of_prev;
sweep_line_elt = _cairo_skip_list_insert (&sweep_line->active_edges, &edge,
- 1 /* unique inserts*/);
- if (sweep_line_elt == NULL)
+ 1 /* unique inserts*/);
+ if (unlikely (sweep_line_elt == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
next_elt = sweep_line_elt->elt.next[0];
@@ -1439,10 +1439,7 @@ _active_edges_to_traps (cairo_bo_edge_t *head,
for (edge = head; edge; edge = edge->next) {
if (fill_rule == CAIRO_FILL_RULE_WINDING) {
- if (edge->reversed)
- in_out++;
- else
- in_out--;
+ in_out += edge->dir;
if (in_out == 0) {
status = _cairo_bo_edge_end_trap (edge, top, bo_traps);
if (status)
@@ -1662,11 +1659,10 @@ _cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps,
has_limits = _cairo_traps_get_limit (traps, &limit);
- if (polygon->num_edges < ARRAY_LENGTH (stack_edges)) {
- edges = stack_edges;
- } else {
+ edges = stack_edges;
+ if (polygon->num_edges > ARRAY_LENGTH (stack_edges)) {
edges = _cairo_malloc_ab (polygon->num_edges, sizeof (cairo_bo_edge_t));
- if (edges == NULL)
+ if (unlikely (edges == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -1734,10 +1730,7 @@ _cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps,
edge->top.y = top.y;
edge->bottom.x = bot.x;
edge->bottom.y = bot.y;
- /* XXX: The 'clockWise' name that cairo_polygon_t uses is
- * totally bogus. It's really a (negated!) description of
- * whether the edge is reversed. */
- edge->reversed = (! polygon->edges[i].clockWise);
+ edge->dir = polygon->edges[i].dir;
edge->deferred_trap = NULL;
edge->prev = NULL;
edge->next = NULL;
diff --git a/src/cairo-beos-surface.cpp b/src/cairo-beos-surface.cpp
index ec4aff03..e527272e 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-cache-private.h b/src/cairo-cache-private.h
index 4ae63ade..5ac8cc8b 100644
--- a/src/cairo-cache-private.h
+++ b/src/cairo-cache-private.h
@@ -109,17 +109,16 @@ _cairo_cache_freeze (cairo_cache_t *cache);
cairo_private void
_cairo_cache_thaw (cairo_cache_t *cache);
-cairo_private cairo_bool_t
+cairo_private void *
_cairo_cache_lookup (cairo_cache_t *cache,
- cairo_cache_entry_t *key,
- cairo_cache_entry_t **entry_return);
+ cairo_cache_entry_t *key);
cairo_private cairo_status_t
_cairo_cache_insert (cairo_cache_t *cache,
cairo_cache_entry_t *entry);
cairo_private void
-_cairo_cache_foreach (cairo_cache_t *cache,
+_cairo_cache_foreach (cairo_cache_t *cache,
cairo_cache_callback_func_t cache_callback,
void *closure);
diff --git a/src/cairo-cache.c b/src/cairo-cache.c
index 1c458dff..07c8b71f 100644
--- a/src/cairo-cache.c
+++ b/src/cairo-cache.c
@@ -44,7 +44,7 @@ _cairo_cache_remove (cairo_cache_t *cache,
static void
_cairo_cache_shrink_to_accommodate (cairo_cache_t *cache,
- unsigned long additional);
+ unsigned long additional);
static cairo_status_t
_cairo_cache_init (cairo_cache_t *cache,
@@ -53,7 +53,7 @@ _cairo_cache_init (cairo_cache_t *cache,
unsigned long max_size)
{
cache->hash_table = _cairo_hash_table_create (keys_equal);
- if (cache->hash_table == NULL)
+ if (unlikely (cache->hash_table == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
cache->entry_destroy = entry_destroy;
@@ -67,24 +67,19 @@ _cairo_cache_init (cairo_cache_t *cache,
}
static void
-_cairo_cache_fini (cairo_cache_t *cache)
+_cairo_cache_pluck (void *entry, void *closure)
{
- cairo_cache_entry_t *entry;
-
- /* We have to manually remove all entries from the cache ourselves
- * rather than relying on _cairo_hash_table_destroy() to do that
- * since otherwise the cache->entry_destroy callback would not get
- * called on each entry. */
-
- while (1) {
- entry = _cairo_hash_table_random_entry (cache->hash_table, NULL);
- if (entry == NULL)
- break;
- _cairo_cache_remove (cache, entry);
- }
+ _cairo_cache_remove (closure, entry);
+}
+static void
+_cairo_cache_fini (cairo_cache_t *cache)
+{
+ _cairo_hash_table_foreach (cache->hash_table,
+ _cairo_cache_pluck,
+ cache);
+ assert (cache->size == 0);
_cairo_hash_table_destroy (cache->hash_table);
- cache->size = 0;
}
/**
@@ -130,13 +125,13 @@ _cairo_cache_create (cairo_cache_keys_equal_func_t keys_equal,
cairo_cache_t *cache;
cache = malloc (sizeof (cairo_cache_t));
- if (cache == NULL) {
+ if (unlikely (cache == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
status = _cairo_cache_init (cache, keys_equal, entry_destroy, max_size);
- if (status) {
+ if (unlikely (status)) {
free (cache);
return NULL;
}
@@ -222,14 +217,12 @@ _cairo_cache_thaw (cairo_cache_t *cache)
* @key, (which will now be in *entry_return). %FALSE otherwise, (in
* which case *entry_return will be %NULL).
**/
-cairo_bool_t
+void *
_cairo_cache_lookup (cairo_cache_t *cache,
- cairo_cache_entry_t *key,
- cairo_cache_entry_t **entry_return)
+ cairo_cache_entry_t *key)
{
return _cairo_hash_table_lookup (cache->hash_table,
- (cairo_hash_entry_t *) key,
- (cairo_hash_entry_t **) entry_return);
+ (cairo_hash_entry_t *) key);
}
/**
@@ -247,7 +240,7 @@ _cairo_cache_remove_random (cairo_cache_t *cache)
cairo_cache_entry_t *entry;
entry = _cairo_hash_table_random_entry (cache->hash_table, NULL);
- if (entry == NULL)
+ if (unlikely (entry == NULL))
return FALSE;
_cairo_cache_remove (cache, entry);
@@ -300,7 +293,7 @@ _cairo_cache_insert (cairo_cache_t *cache,
status = _cairo_hash_table_insert (cache->hash_table,
(cairo_hash_entry_t *) entry);
- if (status)
+ if (unlikely (status))
return status;
cache->size += entry->size;
@@ -356,8 +349,20 @@ unsigned long
_cairo_hash_string (const char *c)
{
/* This is the djb2 hash. */
- unsigned long hash = 5381;
+ unsigned long hash = _CAIRO_HASH_INIT_VALUE;
while (c && *c)
hash = ((hash << 5) + hash) + *c++;
return hash;
}
+
+unsigned long
+_cairo_hash_bytes (unsigned long hash,
+ const void *ptr,
+ unsigned int length)
+{
+ const uint8_t *bytes = ptr;
+ /* This is the djb2 hash. */
+ while (length--)
+ hash = ((hash << 5) + hash) + *bytes++;
+ return hash;
+}
diff --git a/src/cairo-cff-subset.c b/src/cairo-cff-subset.c
index 9a4e3d6a..75e1ab51 100644
--- a/src/cairo-cff-subset.c
+++ b/src/cairo-cff-subset.c
@@ -298,7 +298,7 @@ cff_index_read (cairo_array_t *index, unsigned char **ptr, unsigned char *end_pt
element.is_copy = FALSE;
element.data = data + start;
status = _cairo_array_append (index, &element);
- if (status)
+ if (unlikely (status))
return status;
start = end;
}
@@ -324,7 +324,7 @@ cff_index_write (cairo_array_t *index, cairo_array_t *output)
num_elem = _cairo_array_num_elements (index);
count = cpu_to_be16 ((uint16_t) num_elem);
status = _cairo_array_append_multiple (output, &count, 2);
- if (status)
+ if (unlikely (status))
return status;
if (num_elem == 0)
@@ -347,13 +347,13 @@ cff_index_write (cairo_array_t *index, cairo_array_t *output)
buf[0] = (unsigned char) offset_size;
status = _cairo_array_append (output, buf);
- if (status)
+ if (unlikely (status))
return status;
offset = 1;
encode_index_offset (buf, offset_size, offset);
status = _cairo_array_append_multiple (output, buf, offset_size);
- if (status)
+ if (unlikely (status))
return status;
for (i = 0; i < num_elem; i++) {
@@ -361,7 +361,7 @@ cff_index_write (cairo_array_t *index, cairo_array_t *output)
offset += element->length;
encode_index_offset (buf, offset_size, offset);
status = _cairo_array_append_multiple (output, buf, offset_size);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -370,7 +370,7 @@ cff_index_write (cairo_array_t *index, cairo_array_t *output)
status = _cairo_array_append_multiple (output,
element->data,
element->length);
- if (status)
+ if (unlikely (status))
return status;
}
return CAIRO_STATUS_SUCCESS;
@@ -399,13 +399,13 @@ cff_index_append_copy (cairo_array_t *index,
element.length = length;
element.is_copy = TRUE;
element.data = malloc (element.length);
- if (element.data == NULL)
+ if (unlikely (element.data == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (element.data, object, element.length);
status = _cairo_array_append (index, &element);
- if (status) {
+ if (unlikely (status)) {
free (element.data);
return status;
}
@@ -440,8 +440,8 @@ static cairo_status_t
cff_dict_init (cairo_hash_table_t **dict)
{
*dict = _cairo_hash_table_create (_cairo_cff_dict_equal);
- if (*dict == NULL)
- return CAIRO_STATUS_NO_MEMORY;
+ if (unlikely (*dict == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_SUCCESS;
}
@@ -462,12 +462,12 @@ cff_dict_create_operator (int operator,
cff_dict_operator_t *op;
op = malloc (sizeof (cff_dict_operator_t));
- if (op == NULL)
+ if (unlikely (op == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_cairo_dict_init_key (op, operator);
op->operand = malloc (size);
- if (op->operand == NULL) {
+ if (unlikely (op->operand == NULL)) {
free (op);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -496,7 +496,7 @@ cff_dict_read (cairo_hash_table_t *dict, unsigned char *p, int dict_size)
size = operand_length (p);
if (size != 0) {
status = _cairo_array_append_multiple (&operands, p, size);
- if (status)
+ if (unlikely (status))
goto fail;
p += size;
@@ -506,11 +506,11 @@ cff_dict_read (cairo_hash_table_t *dict, unsigned char *p, int dict_size)
_cairo_array_index (&operands, 0),
_cairo_array_num_elements (&operands),
&op);
- if (status)
+ if (unlikely (status))
goto fail;
status = _cairo_hash_table_insert (dict, &op->base);
- if (status)
+ if (unlikely (status))
goto fail;
_cairo_array_truncate (&operands, 0);
@@ -529,9 +529,8 @@ cff_dict_remove (cairo_hash_table_t *dict, unsigned short operator)
cff_dict_operator_t key, *op;
_cairo_dict_init_key (&key, operator);
- if (_cairo_hash_table_lookup (dict, &key.base,
- (cairo_hash_entry_t **) &op))
- {
+ op = _cairo_hash_table_lookup (dict, &key.base);
+ if (op != NULL) {
free (op->operand);
_cairo_hash_table_remove (dict, (cairo_hash_entry_t *) op);
free (op);
@@ -546,9 +545,8 @@ cff_dict_get_operands (cairo_hash_table_t *dict,
cff_dict_operator_t key, *op;
_cairo_dict_init_key (&key, operator);
- if (_cairo_hash_table_lookup (dict, &key.base,
- (cairo_hash_entry_t **) &op))
- {
+ op = _cairo_hash_table_lookup (dict, &key.base);
+ if (op != NULL) {
*size = op->operand_length;
return op->operand;
}
@@ -566,12 +564,11 @@ cff_dict_set_operands (cairo_hash_table_t *dict,
cairo_status_t status;
_cairo_dict_init_key (&key, operator);
- if (_cairo_hash_table_lookup (dict, &key.base,
- (cairo_hash_entry_t **) &op))
- {
+ op = _cairo_hash_table_lookup (dict, &key.base);
+ if (op != NULL) {
free (op->operand);
op->operand = malloc (size);
- if (op->operand == NULL)
+ if (unlikely (op->operand == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (op->operand, operand, size);
@@ -580,11 +577,11 @@ cff_dict_set_operands (cairo_hash_table_t *dict,
else
{
status = cff_dict_create_operator (operator, operand, size, &op);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_hash_table_insert (dict, &op->base);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -599,9 +596,8 @@ cff_dict_get_location (cairo_hash_table_t *dict,
cff_dict_operator_t key, *op;
_cairo_dict_init_key (&key, operator);
- if (_cairo_hash_table_lookup (dict, &key.base,
- (cairo_hash_entry_t **) &op))
- {
+ op = _cairo_hash_table_lookup (dict, &key.base);
+ if (op != NULL) {
*size = op->operand_length;
return op->operand_offset;
}
@@ -660,8 +656,8 @@ cff_dict_write (cairo_hash_table_t *dict, cairo_array_t *output)
/* The CFF specification requires that the Top Dict of CID fonts
* begin with the ROS operator. */
_cairo_dict_init_key (&key, ROS_OP);
- if (_cairo_hash_table_lookup (dict, &key.base,
- (cairo_hash_entry_t **) &op))
+ op = _cairo_hash_table_lookup (dict, &key.base);
+ if (op != NULL)
cairo_dict_write_operator (op, &write_info);
_cairo_hash_table_foreach (dict, _cairo_dict_collect, &write_info);
@@ -728,7 +724,7 @@ cairo_cff_font_read_private_dict (cairo_cff_font_t *font,
unsigned char *p;
status = cff_dict_read (private_dict, ptr, size);
- if (status)
+ if (unlikely (status))
return status;
operand = cff_dict_get_operands (private_dict, LOCAL_SUB_OP, &i);
@@ -736,13 +732,13 @@ cairo_cff_font_read_private_dict (cairo_cff_font_t *font,
decode_integer (operand, &offset);
p = ptr + offset;
status = cff_index_read (local_sub_index, &p, font->data_end);
- if (status)
+ if (unlikely (status))
return status;
/* Use maximum sized encoding to reserve space for later modification. */
end_buf = encode_integer_max (buf, 0);
status = cff_dict_set_operands (private_dict, LOCAL_SUB_OP, buf, end_buf - buf);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -755,7 +751,7 @@ cairo_cff_font_read_fdselect (cairo_cff_font_t *font, unsigned char *p)
int type, num_ranges, first, last, fd, i, j;
font->fdselect = calloc (font->num_glyphs, sizeof (int));
- if (font->fdselect == NULL)
+ if (unlikely (font->fdselect == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
type = *p++;
@@ -797,37 +793,37 @@ cairo_cff_font_read_cid_fontdict (cairo_cff_font_t *font, unsigned char *ptr)
cff_index_init (&index);
status = cff_index_read (&index, &ptr, font->data_end);
- if (status)
+ if (unlikely (status))
goto fail;
font->num_fontdicts = _cairo_array_num_elements (&index);
font->fd_dict = calloc (sizeof (cairo_hash_table_t *), font->num_fontdicts);
- if (font->fd_dict == NULL) {
+ if (unlikely (font->fd_dict == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail;
}
font->fd_private_dict = calloc (sizeof (cairo_hash_table_t *), font->num_fontdicts);
- if (font->fd_private_dict == NULL) {
+ if (unlikely (font->fd_private_dict == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail;
}
font->fd_local_sub_index = calloc (sizeof (cairo_array_t), font->num_fontdicts);
- if (font->fd_local_sub_index == NULL) {
+ if (unlikely (font->fd_local_sub_index == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail;
}
for (i = 0; i < font->num_fontdicts; i++) {
status = cff_dict_init (&font->fd_dict[i]);
- if (status)
+ if (unlikely (status))
goto fail;
element = _cairo_array_index (&index, i);
status = cff_dict_read (font->fd_dict[i], element->data, element->length);
- if (status)
+ if (unlikely (status))
goto fail;
operand = cff_dict_get_operands (font->fd_dict[i], PRIVATE_OP, &size);
@@ -838,7 +834,7 @@ cairo_cff_font_read_cid_fontdict (cairo_cff_font_t *font, unsigned char *ptr)
operand = decode_integer (operand, &size);
decode_integer (operand, &offset);
status = cff_dict_init (&font->fd_private_dict[i]);
- if (status)
+ if (unlikely (status))
goto fail;
cff_index_init (&font->fd_local_sub_index[i]);
@@ -847,7 +843,7 @@ cairo_cff_font_read_cid_fontdict (cairo_cff_font_t *font, unsigned char *ptr)
&font->fd_local_sub_index[i],
font->data + offset,
size);
- if (status)
+ if (unlikely (status))
goto fail;
/* Set integer operand to max value to use max size encoding to reserve
@@ -855,7 +851,7 @@ cairo_cff_font_read_cid_fontdict (cairo_cff_font_t *font, unsigned char *ptr)
end_buf = encode_integer_max (buf, 0);
end_buf = encode_integer_max (end_buf, 0);
status = cff_dict_set_operands (font->fd_dict[i], PRIVATE_OP, buf, end_buf - buf);
- if (status)
+ if (unlikely (status))
goto fail;
}
@@ -882,12 +878,12 @@ cairo_cff_font_read_top_dict (cairo_cff_font_t *font)
cff_index_init (&index);
status = cff_index_read (&index, &font->current_ptr, font->data_end);
- if (status)
+ if (unlikely (status))
goto fail;
element = _cairo_array_index (&index, 0);
status = cff_dict_read (font->top_dict, element->data, element->length);
- if (status)
+ if (unlikely (status))
goto fail;
if (cff_dict_get_operands (font->top_dict, ROS_OP, &size) != NULL)
@@ -899,7 +895,7 @@ cairo_cff_font_read_top_dict (cairo_cff_font_t *font)
decode_integer (operand, &offset);
p = font->data + offset;
status = cff_index_read (&font->charstrings_index, &p, font->data_end);
- if (status)
+ if (unlikely (status))
goto fail;
font->num_glyphs = _cairo_array_num_elements (&font->charstrings_index);
@@ -907,13 +903,13 @@ cairo_cff_font_read_top_dict (cairo_cff_font_t *font)
operand = cff_dict_get_operands (font->top_dict, FDSELECT_OP, &size);
decode_integer (operand, &offset);
status = cairo_cff_font_read_fdselect (font, font->data + offset);
- if (status)
+ if (unlikely (status))
goto fail;
operand = cff_dict_get_operands (font->top_dict, FDARRAY_OP, &size);
decode_integer (operand, &offset);
status = cairo_cff_font_read_cid_fontdict (font, font->data + offset);
- if (status)
+ if (unlikely (status))
goto fail;
} else {
operand = cff_dict_get_operands (font->top_dict, PRIVATE_OP, &size);
@@ -924,7 +920,7 @@ cairo_cff_font_read_top_dict (cairo_cff_font_t *font)
&font->local_sub_index,
font->data + offset,
size);
- if (status)
+ if (unlikely (status))
goto fail;
}
@@ -932,22 +928,22 @@ cairo_cff_font_read_top_dict (cairo_cff_font_t *font)
end_buf = encode_integer_max (buf, 0);
status = cff_dict_set_operands (font->top_dict,
CHARSTRINGS_OP, buf, end_buf - buf);
- if (status)
+ if (unlikely (status))
goto fail;
status = cff_dict_set_operands (font->top_dict,
FDSELECT_OP, buf, end_buf - buf);
- if (status)
+ if (unlikely (status))
goto fail;
status = cff_dict_set_operands (font->top_dict,
FDARRAY_OP, buf, end_buf - buf);
- if (status)
+ if (unlikely (status))
goto fail;
status = cff_dict_set_operands (font->top_dict,
CHARSET_OP, buf, end_buf - buf);
- if (status)
+ if (unlikely (status))
goto fail;
cff_dict_remove (font->top_dict, ENCODING_OP);
@@ -995,7 +991,7 @@ cairo_cff_font_read_font (cairo_cff_font_t *font)
for (i = 0; i < ARRAY_LENGTH (font_read_funcs); i++) {
status = font_read_funcs[i] (font);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -1016,26 +1012,26 @@ cairo_cff_font_set_ros_strings (cairo_cff_font_t *font)
status = cff_index_append_copy (&font->strings_subset_index,
(unsigned char *)registry,
strlen(registry));
- if (status)
+ if (unlikely (status))
return status;
sid2 = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index);
status = cff_index_append_copy (&font->strings_subset_index,
(unsigned char *)ordering,
strlen(ordering));
- if (status)
+ if (unlikely (status))
return status;
p = encode_integer (buf, sid1);
p = encode_integer (p, sid2);
p = encode_integer (p, 0);
status = cff_dict_set_operands (font->top_dict, ROS_OP, buf, p - buf);
- if (status)
+ if (unlikely (status))
return status;
p = encode_integer (buf, font->scaled_font_subset->num_glyphs);
status = cff_dict_set_operands (font->top_dict, CIDCOUNT_OP, buf, p - buf);
- if (status)
+ if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
@@ -1064,12 +1060,12 @@ cairo_cff_font_subset_dict_string(cairo_cff_font_t *font,
element = _cairo_array_index (&font->strings_index, sid - NUM_STD_STRINGS);
sid = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index);
status = cff_index_append (&font->strings_subset_index, element->data, element->length);
- if (status)
+ if (unlikely (status))
return status;
p = encode_integer (buf, sid);
status = cff_dict_set_operands (dict, operator, buf, p - buf);
- if (status)
+ if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
@@ -1096,7 +1092,7 @@ cairo_cff_font_subset_dict_strings (cairo_cff_font_t *font,
for (i = 0; i < ARRAY_LENGTH (dict_strings); i++) {
status = cairo_cff_font_subset_dict_string (font, dict, dict_strings[i]);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -1116,7 +1112,7 @@ cairo_cff_font_subset_charstrings (cairo_cff_font_t *font)
status = cff_index_append (&font->charstrings_subset_index,
element->data,
element->length);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -1132,19 +1128,19 @@ cairo_cff_font_subset_fontdict (cairo_cff_font_t *font)
font->fdselect_subset = calloc (font->scaled_font_subset->num_glyphs,
sizeof (int));
- if (font->fdselect_subset == NULL)
+ if (unlikely (font->fdselect_subset == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font->fd_subset_map = calloc (font->num_fontdicts, sizeof (int));
- if (font->fd_subset_map == NULL)
+ if (unlikely (font->fd_subset_map == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font->private_dict_offset = calloc (font->num_fontdicts, sizeof (int));
- if (font->private_dict_offset == NULL)
+ if (unlikely (font->private_dict_offset == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
reverse_map = calloc (font->num_fontdicts, sizeof (int));
- if (reverse_map == NULL)
+ if (unlikely (reverse_map == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
for (i = 0; i < font->num_fontdicts; i++)
@@ -1174,7 +1170,7 @@ cairo_cff_font_create_cid_fontdict (cairo_cff_font_t *font)
font->num_fontdicts = 1;
font->fd_dict = malloc (sizeof (cairo_hash_table_t *));
- if (font->fd_dict == NULL)
+ if (unlikely (font->fd_dict == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (cff_dict_init (&font->fd_dict[0])) {
@@ -1185,11 +1181,11 @@ cairo_cff_font_create_cid_fontdict (cairo_cff_font_t *font)
}
font->fd_subset_map = malloc (sizeof (int));
- if (font->fd_subset_map == NULL)
+ if (unlikely (font->fd_subset_map == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font->private_dict_offset = malloc (sizeof (int));
- if (font->private_dict_offset == NULL)
+ if (unlikely (font->private_dict_offset == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font->fd_subset_map[0] = 0;
@@ -1200,7 +1196,7 @@ cairo_cff_font_create_cid_fontdict (cairo_cff_font_t *font)
end_buf = encode_integer_max (buf, 0);
end_buf = encode_integer_max (end_buf, 0);
status = cff_dict_set_operands (font->fd_dict[0], PRIVATE_OP, buf, end_buf - buf);
- if (status)
+ if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
@@ -1213,17 +1209,17 @@ cairo_cff_font_subset_strings (cairo_cff_font_t *font)
unsigned int i;
status = cairo_cff_font_subset_dict_strings (font, font->top_dict);
- if (status)
+ if (unlikely (status))
return status;
if (font->is_cid) {
for (i = 0; i < font->num_subset_fontdicts; i++) {
status = cairo_cff_font_subset_dict_strings (font, font->fd_dict[font->fd_subset_map[i]]);
- if (status)
+ if (unlikely (status))
return status;
status = cairo_cff_font_subset_dict_strings (font, font->fd_private_dict[font->fd_subset_map[i]]);
- if (status)
+ if (unlikely (status))
return status;
}
} else {
@@ -1239,22 +1235,22 @@ cairo_cff_font_subset_font (cairo_cff_font_t *font)
cairo_status_t status;
status = cairo_cff_font_set_ros_strings (font);
- if (status)
+ if (unlikely (status))
return status;
status = cairo_cff_font_subset_charstrings (font);
- if (status)
+ if (unlikely (status))
return status;
if (font->is_cid)
status = cairo_cff_font_subset_fontdict (font);
else
status = cairo_cff_font_create_cid_fontdict (font);
- if (status)
+ if (unlikely (status))
return status;
status = cairo_cff_font_subset_strings (font);
- if (status)
+ if (unlikely (status))
return status;
return status;
@@ -1302,11 +1298,11 @@ cairo_cff_font_write_name (cairo_cff_font_t *font)
status = cff_index_append_copy (&index,
(unsigned char *) font->subset_font_name,
strlen(font->subset_font_name));
- if (status)
+ if (unlikely (status))
goto FAIL;
status = cff_index_write (&index, &font->output);
- if (status)
+ if (unlikely (status))
goto FAIL;
FAIL:
@@ -1330,27 +1326,27 @@ cairo_cff_font_write_top_dict (cairo_cff_font_t *font)
count = cpu_to_be16 (1);
status = _cairo_array_append_multiple (&font->output, &count, 2);
- if (status)
+ if (unlikely (status))
return status;
buf[0] = offset_size;
status = _cairo_array_append (&font->output, buf);
- if (status)
+ if (unlikely (status))
return status;
encode_index_offset (buf, offset_size, 1);
status = _cairo_array_append_multiple (&font->output, buf, offset_size);
- if (status)
+ if (unlikely (status))
return status;
/* Reserve space for last element of offset array and update after
* dict is written */
offset_index = _cairo_array_num_elements (&font->output);
status = _cairo_array_append_multiple (&font->output, buf, offset_size);
- if (status)
+ if (unlikely (status))
return status;
dict_start = _cairo_array_num_elements (&font->output);
status = cff_dict_write (font->top_dict, &font->output);
- if (status)
+ if (unlikely (status))
return status;
dict_size = _cairo_array_num_elements (&font->output) - dict_start;
@@ -1385,13 +1381,13 @@ cairo_cff_font_write_fdselect (cairo_cff_font_t *font)
if (font->is_cid) {
data = 0;
status = _cairo_array_append (&font->output, &data);
- if (status)
+ if (unlikely (status))
return status;
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
data = font->fdselect_subset[i];
status = _cairo_array_append (&font->output, &data);
- if (status)
+ if (unlikely (status))
return status;
}
} else {
@@ -1399,7 +1395,7 @@ cairo_cff_font_write_fdselect (cairo_cff_font_t *font)
uint16_t word;
status = _cairo_array_grow_by (&font->output, 9);
- if (status)
+ if (unlikely (status))
return status;
byte = 3;
@@ -1435,7 +1431,7 @@ cairo_cff_font_write_charset (cairo_cff_font_t *font)
cairo_cff_font_set_topdict_operator_to_cur_pos (font, CHARSET_OP);
status = _cairo_array_grow_by (&font->output, 5);
- if (status)
+ if (unlikely (status))
return status;
byte = 2;
@@ -1474,22 +1470,22 @@ cairo_cff_font_write_cid_fontdict (cairo_cff_font_t *font)
cairo_cff_font_set_topdict_operator_to_cur_pos (font, FDARRAY_OP);
count = cpu_to_be16 (font->num_subset_fontdicts);
status = _cairo_array_append_multiple (&font->output, &count, sizeof (uint16_t));
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_array_append (&font->output, &offset_size);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_array_allocate (&font->output,
(font->num_subset_fontdicts + 1)*offset_size,
(void **) &offset_array);
- if (status)
+ if (unlikely (status))
return status;
offset_base = _cairo_array_num_elements (&font->output) - 1;
*offset_array++ = cpu_to_be32(1);
for (i = 0; i < font->num_subset_fontdicts; i++) {
status = cff_dict_write (font->fd_dict[font->fd_subset_map[i]],
&font->output);
- if (status)
+ if (unlikely (status))
return status;
*offset_array++ = cpu_to_be32(_cairo_array_num_elements (&font->output) - offset_base);
}
@@ -1513,7 +1509,7 @@ cairo_cff_font_write_private_dict (cairo_cff_font_t *font,
/* Write private dict and update offset and size in top dict */
font->private_dict_offset[dict_num] = _cairo_array_num_elements (&font->output);
status = cff_dict_write (private_dict, &font->output);
- if (status)
+ if (unlikely (status))
return status;
size = _cairo_array_num_elements (&font->output) - font->private_dict_offset[dict_num];
@@ -1552,7 +1548,7 @@ cairo_cff_font_write_local_sub (cairo_cff_font_t *font,
p = _cairo_array_index (&font->output, offset);
memcpy (p, buf, buf_end - buf);
status = cff_index_write (local_sub_index, &font->output);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -1573,7 +1569,7 @@ cairo_cff_font_write_cid_private_dict_and_local_sub (cairo_cff_font_t *font)
i,
font->fd_dict[font->fd_subset_map[i]],
font->fd_private_dict[font->fd_subset_map[i]]);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -1583,7 +1579,7 @@ cairo_cff_font_write_cid_private_dict_and_local_sub (cairo_cff_font_t *font)
i,
font->fd_private_dict[font->fd_subset_map[i]],
&font->fd_local_sub_index[font->fd_subset_map[i]]);
- if (status)
+ if (unlikely (status))
return status;
}
} else {
@@ -1591,14 +1587,14 @@ cairo_cff_font_write_cid_private_dict_and_local_sub (cairo_cff_font_t *font)
0,
font->fd_dict[0],
font->private_dict);
- if (status)
+ if (unlikely (status))
return status;
status = cairo_cff_font_write_local_sub (font,
0,
font->private_dict,
&font->local_sub_index);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -1629,7 +1625,7 @@ cairo_cff_font_write_subset (cairo_cff_font_t *font)
for (i = 0; i < ARRAY_LENGTH (font_write_funcs); i++) {
status = font_write_funcs[i] (font);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -1644,15 +1640,15 @@ cairo_cff_font_generate (cairo_cff_font_t *font,
cairo_int_status_t status;
status = cairo_cff_font_read_font (font);
- if (status)
+ if (unlikely (status))
return status;
status = cairo_cff_font_subset_font (font);
- if (status)
+ if (unlikely (status))
return status;
status = cairo_cff_font_write_subset (font);
- if (status)
+ if (unlikely (status))
return status;
*data = _cairo_array_index (&font->output, 0);
@@ -1678,7 +1674,7 @@ cairo_cff_font_create_set_widths (cairo_cff_font_t *font)
status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_hhea, 0,
(unsigned char*) &hhea, &size);
- if (status)
+ if (unlikely (status))
return status;
num_hmetrics = be16_to_cpu (hhea.num_hmetrics);
@@ -1691,7 +1687,7 @@ cairo_cff_font_create_set_widths (cairo_cff_font_t *font)
TT_TAG_hmtx,
glyph_index * long_entry_size,
buf, &short_entry_size);
- if (status)
+ if (unlikely (status))
return status;
}
else
@@ -1700,7 +1696,7 @@ cairo_cff_font_create_set_widths (cairo_cff_font_t *font)
TT_TAG_hmtx,
(num_hmetrics - 1) * long_entry_size,
buf, &short_entry_size);
- if (status)
+ if (unlikely (status))
return status;
}
font->widths[i] = be16_to_cpu (*((int16_t*)buf));
@@ -1731,47 +1727,47 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
data_length = 0;
status = backend->load_truetype_table( scaled_font_subset->scaled_font,
TT_TAG_CFF, 0, NULL, &data_length);
- if (status)
+ if (unlikely (status))
return status;
size = sizeof (tt_head_t);
status = backend->load_truetype_table (scaled_font_subset->scaled_font,
TT_TAG_head, 0,
(unsigned char *) &head, &size);
- if (status)
+ if (unlikely (status))
return status;
size = sizeof (tt_hhea_t);
status = backend->load_truetype_table (scaled_font_subset->scaled_font,
TT_TAG_hhea, 0,
(unsigned char *) &hhea, &size);
- if (status)
+ if (unlikely (status))
return status;
size = 0;
status = backend->load_truetype_table (scaled_font_subset->scaled_font,
TT_TAG_hmtx, 0, NULL, &size);
- if (status)
+ if (unlikely (status))
return status;
size = 0;
status = backend->load_truetype_table (scaled_font_subset->scaled_font,
TT_TAG_name, 0, NULL, &size);
- if (status)
+ if (unlikely (status))
return status;
name = malloc (size);
- if (name == NULL)
+ if (unlikely (name == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = backend->load_truetype_table (scaled_font_subset->scaled_font,
TT_TAG_name, 0,
(unsigned char *) name, &size);
- if (status)
+ if (unlikely (status))
goto fail1;
font = malloc (sizeof (cairo_cff_font_t));
- if (font == NULL) {
+ if (unlikely (font == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail1;
}
@@ -1781,11 +1777,11 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
_cairo_array_init (&font->output, sizeof (char));
status = _cairo_array_grow_by (&font->output, 4096);
- if (status)
+ if (unlikely (status))
goto fail2;
font->subset_font_name = strdup (subset_name);
- if (font->subset_font_name == NULL) {
+ if (unlikely (font->subset_font_name == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2;
}
@@ -1821,7 +1817,7 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
if (font->font_name == NULL) {
font->font_name = malloc (30);
- if (font->font_name == NULL) {
+ if (unlikely (font->font_name == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3;
}
@@ -1838,35 +1834,35 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
font->font_name[i] = '\0';
font->widths = calloc (font->scaled_font_subset->num_glyphs, sizeof (int));
- if (font->widths == NULL) {
+ if (unlikely (font->widths == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail4;
}
status = cairo_cff_font_create_set_widths (font);
- if (status)
+ if (unlikely (status))
goto fail5;
font->data_length = data_length;
font->data = malloc (data_length);
- if (font->data == NULL) {
+ if (unlikely (font->data == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail5;
}
status = font->backend->load_truetype_table ( font->scaled_font_subset->scaled_font,
TT_TAG_CFF, 0, font->data,
&font->data_length);
- if (status)
+ if (unlikely (status))
goto fail6;
font->data_end = font->data + font->data_length;
status = cff_dict_init (&font->top_dict);
- if (status)
+ if (unlikely (status))
goto fail6;
status = cff_dict_init (&font->private_dict);
- if (status)
+ if (unlikely (status))
goto fail7;
cff_index_init (&font->strings_index);
@@ -1975,21 +1971,21 @@ _cairo_cff_subset_init (cairo_cff_subset_t *cff_subset,
unsigned int i;
status = _cairo_cff_font_create (font_subset, &font, subset_name);
- if (status)
+ if (unlikely (status))
return status;
status = cairo_cff_font_generate (font, &data, &length);
- if (status)
+ if (unlikely (status))
goto fail1;
cff_subset->base_font = strdup (font->font_name);
- if (cff_subset->base_font == NULL) {
+ if (unlikely (cff_subset->base_font == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail1;
}
cff_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs);
- if (cff_subset->widths == NULL) {
+ if (unlikely (cff_subset->widths == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2;
}
@@ -2004,7 +2000,7 @@ _cairo_cff_subset_init (cairo_cff_subset_t *cff_subset,
cff_subset->descent = font->descent;
cff_subset->data = malloc (length);
- if (cff_subset->data == NULL) {
+ if (unlikely (cff_subset->data == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3;
}
@@ -2043,7 +2039,7 @@ _cairo_cff_font_fallback_create (cairo_scaled_font_subset_t *scaled_font_subset
cairo_cff_font_t *font;
font = malloc (sizeof (cairo_cff_font_t));
- if (font == NULL)
+ if (unlikely (font == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font->backend = NULL;
@@ -2051,17 +2047,17 @@ _cairo_cff_font_fallback_create (cairo_scaled_font_subset_t *scaled_font_subset
_cairo_array_init (&font->output, sizeof (char));
status = _cairo_array_grow_by (&font->output, 4096);
- if (status)
+ if (unlikely (status))
goto fail1;
font->subset_font_name = strdup (subset_name);
- if (font->subset_font_name == NULL) {
+ if (unlikely (font->subset_font_name == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail1;
}
font->font_name = strdup (subset_name);
- if (font->subset_font_name == NULL) {
+ if (unlikely (font->subset_font_name == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2;
}
@@ -2074,7 +2070,7 @@ _cairo_cff_font_fallback_create (cairo_scaled_font_subset_t *scaled_font_subset
font->descent = 0;
font->widths = calloc (font->scaled_font_subset->num_glyphs, sizeof (int));
- if (font->widths == NULL) {
+ if (unlikely (font->widths == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3;
}
@@ -2084,11 +2080,11 @@ _cairo_cff_font_fallback_create (cairo_scaled_font_subset_t *scaled_font_subset
font->data_end = NULL;
status = cff_dict_init (&font->top_dict);
- if (status)
+ if (unlikely (status))
goto fail4;
status = cff_dict_init (&font->private_dict);
- if (status)
+ if (unlikely (status))
goto fail5;
cff_index_init (&font->strings_index);
@@ -2151,37 +2147,37 @@ cairo_cff_font_fallback_generate (cairo_cff_font_t *font,
end_buf = encode_integer (end_buf, type2_subset->y_max);
status = cff_dict_set_operands (font->top_dict,
FONTBBOX_OP, buf, end_buf - buf);
- if (status)
+ if (unlikely (status))
return status;
end_buf = encode_integer_max (buf, 0);
status = cff_dict_set_operands (font->top_dict,
CHARSTRINGS_OP, buf, end_buf - buf);
- if (status)
+ if (unlikely (status))
return status;
status = cff_dict_set_operands (font->top_dict,
FDSELECT_OP, buf, end_buf - buf);
- if (status)
+ if (unlikely (status))
return status;
status = cff_dict_set_operands (font->top_dict,
FDARRAY_OP, buf, end_buf - buf);
- if (status)
+ if (unlikely (status))
return status;
status = cff_dict_set_operands (font->top_dict,
CHARSET_OP, buf, end_buf - buf);
- if (status)
+ if (unlikely (status))
return status;
status = cairo_cff_font_set_ros_strings (font);
- if (status)
+ if (unlikely (status))
return status;
/* Create CID FD dictionary */
status = cairo_cff_font_create_cid_fontdict (font);
- if (status)
+ if (unlikely (status))
return status;
/* Create charstrings */
@@ -2192,12 +2188,12 @@ cairo_cff_font_fallback_generate (cairo_cff_font_t *font,
_cairo_array_index (charstring, 0),
_cairo_array_num_elements (charstring));
- if (status)
+ if (unlikely (status))
return status;
}
status = cairo_cff_font_write_subset (font);
- if (status)
+ if (unlikely (status))
return status;
*data = _cairo_array_index (&font->output, 0);
@@ -2219,25 +2215,25 @@ _cairo_cff_fallback_init (cairo_cff_subset_t *cff_subset,
cairo_type2_charstrings_t type2_subset;
status = _cairo_cff_font_fallback_create (font_subset, &font, subset_name);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_type2_charstrings_init (&type2_subset, font_subset);
- if (status)
+ if (unlikely (status))
goto fail1;
status = cairo_cff_font_fallback_generate (font, &type2_subset, &data, &length);
- if (status)
+ if (unlikely (status))
goto fail2;
cff_subset->base_font = strdup (font->font_name);
- if (cff_subset->base_font == NULL) {
+ if (unlikely (cff_subset->base_font == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2;
}
cff_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs);
- if (cff_subset->widths == NULL) {
+ if (unlikely (cff_subset->widths == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3;
}
@@ -2252,7 +2248,7 @@ _cairo_cff_fallback_init (cairo_cff_subset_t *cff_subset,
cff_subset->descent = type2_subset.y_min;
cff_subset->data = malloc (length);
- if (cff_subset->data == NULL) {
+ if (unlikely (cff_subset->data == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail4;
}
diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 93bc151c..cd423a44 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -49,7 +49,7 @@ _cairo_clip_path_destroy (cairo_clip_path_t *clip_path);
void
_cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target)
{
- if (target)
+ if (target && target->backend)
clip->mode = _cairo_surface_get_clip_mode (target);
else
clip->mode = CAIRO_CLIP_MODE_MASK;
@@ -88,7 +88,7 @@ _cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other)
cairo_status_t status;
status = _cairo_region_copy (&clip->region, &other->region);
- if (status) {
+ if (unlikely (status)) {
_cairo_region_fini (&clip->region);
cairo_surface_destroy (clip->surface);
return status;
@@ -143,30 +143,11 @@ _cairo_clip_path_intersect_to_rectangle (cairo_clip_path_t *clip_path,
cairo_rectangle_int_t *rectangle)
{
while (clip_path) {
- cairo_status_t status;
- cairo_traps_t traps;
- cairo_box_t extents;
- cairo_rectangle_int_t extents_rect;
-
- _cairo_box_from_rectangle (&extents, rectangle);
-
- _cairo_traps_init (&traps);
- _cairo_traps_limit (&traps, &extents);
-
- status = _cairo_path_fixed_fill_to_traps (&clip_path->path,
- clip_path->fill_rule,
- clip_path->tolerance,
- &traps);
- if (status) {
- _cairo_traps_fini (&traps);
- return status;
- }
+ cairo_rectangle_int_t extents;
- _cairo_traps_extents (&traps, &extents);
- _cairo_traps_fini (&traps);
+ _cairo_path_fixed_approximate_extents (&clip_path->path, &extents);
- _cairo_box_round_to_rectangle (&extents, &extents_rect);
- if (! _cairo_rectangle_intersect (rectangle, &extents_rect))
+ if (! _cairo_rectangle_intersect (rectangle, &extents))
return CAIRO_STATUS_SUCCESS;
clip_path = clip_path->prev;
@@ -193,7 +174,7 @@ _cairo_clip_intersect_to_rectangle (cairo_clip_t *clip,
if (clip->path) {
status = _cairo_clip_path_intersect_to_rectangle (clip->path,
rectangle);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -210,7 +191,7 @@ _cairo_clip_intersect_to_rectangle (cairo_clip_t *clip,
_cairo_region_fini (&intersection);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -247,7 +228,7 @@ _cairo_clip_intersect_to_region (cairo_clip_t *clip,
if (clip->has_region) {
status = _cairo_region_intersect (region, &clip->region, region);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -260,7 +241,7 @@ _cairo_clip_intersect_to_region (cairo_clip_t *clip,
_cairo_region_fini (&clip_rect);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -317,11 +298,11 @@ _cairo_clip_intersect_path (cairo_clip_t *clip,
return CAIRO_INT_STATUS_UNSUPPORTED;
clip_path = malloc (sizeof (cairo_clip_path_t));
- if (clip_path == NULL)
+ if (unlikely (clip_path == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_path_fixed_init_copy (&clip_path->path, path);
- if (status) {
+ if (unlikely (status)) {
free (clip_path);
return status;
}
@@ -381,7 +362,6 @@ _cairo_clip_intersect_region (cairo_clip_t *clip,
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_traps_extract_region (traps, &region);
-
if (status)
return status;
@@ -423,7 +403,7 @@ _cairo_clip_intersect_mask (cairo_clip_t *clip,
cairo_box_t extents;
cairo_rectangle_int_t surface_rect, target_rect;
cairo_surface_t *surface = NULL;
- cairo_status_t status;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
if (clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
@@ -478,9 +458,10 @@ _cairo_clip_intersect_mask (cairo_clip_t *clip,
I believe the best possible operation would probably an unbounded SRC
operator. Using SRC we could potentially avoid having to initialize
the surface which would be ideal from an efficiency point of view.
- However, _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_SOURCE) is
- bounded by the mask.
-
+ However, CAIRO_OPERATOR_SOURCE is bounded by the trapezoid mask and
+ _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_SOURCE) will assert
+ because it assumes CAIRO_OPERATOR_SOURCE has been converted into other
+ operations.
*/
surface = _cairo_surface_create_similar_solid (target,
@@ -510,7 +491,7 @@ _cairo_clip_intersect_mask (cairo_clip_t *clip,
_cairo_pattern_fini (&pattern.base);
- if (status) {
+ if (unlikely (status)) {
cairo_surface_destroy (surface);
return status;
}
@@ -535,7 +516,7 @@ _cairo_clip_intersect_mask (cairo_clip_t *clip,
_cairo_pattern_fini (&pattern.base);
- if (status) {
+ if (unlikely (status)) {
cairo_surface_destroy (surface);
return status;
}
@@ -553,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,
@@ -564,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;
@@ -583,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
@@ -599,7 +720,7 @@ _cairo_clip_clip (cairo_clip_t *clip,
fill_rule,
tolerance,
&traps);
- if (status)
+ if (unlikely (status))
goto bail;
status = _cairo_clip_intersect_region (clip, &traps, target);
@@ -682,7 +803,7 @@ _cairo_clip_init_deep_copy (cairo_clip_t *clip,
} else {
if (other->has_region) {
status = _cairo_region_copy (&clip->region, &other->region);
- if (status)
+ if (unlikely (status))
goto BAIL;
clip->has_region = TRUE;
@@ -697,7 +818,7 @@ _cairo_clip_init_deep_copy (cairo_clip_t *clip,
other->surface_rect.height,
&dx, &dy,
&clip->surface);
- if (status)
+ if (unlikely (status))
goto BAIL;
clip->surface_rect = other->surface_rect;
@@ -778,7 +899,7 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
if (n_boxes) {
rectangles = _cairo_malloc_ab (n_boxes, sizeof (cairo_rectangle_t));
- if (rectangles == NULL) {
+ if (unlikely (rectangles == NULL)) {
_cairo_region_boxes_fini (&clip->region, boxes);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
@@ -808,7 +929,7 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
n_boxes = 1;
rectangles = malloc(sizeof (cairo_rectangle_t));
- if (rectangles == NULL) {
+ if (unlikely (rectangles == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
}
@@ -824,7 +945,7 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
DONE:
list = malloc (sizeof (cairo_rectangle_list_t));
- if (list == NULL) {
+ if (unlikely (list == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
free (rectangles);
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
diff --git a/src/cairo-compiler-private.h b/src/cairo-compiler-private.h
index b93fd829..44d9de30 100644
--- a/src/cairo-compiler-private.h
+++ b/src/cairo-compiler-private.h
@@ -139,6 +139,23 @@
#define cairo_const
#endif
+#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
+#define _CAIRO_BOOLEAN_EXPR(expr) \
+ __extension__ ({ \
+ int _cairo_boolean_var_; \
+ if (expr) \
+ _cairo_boolean_var_ = 1; \
+ else \
+ _cairo_boolean_var_ = 0; \
+ _cairo_boolean_var_; \
+})
+#define likely(expr) (__builtin_expect (_CAIRO_BOOLEAN_EXPR(expr), 1))
+#define unlikely(expr) (__builtin_expect (_CAIRO_BOOLEAN_EXPR(expr), 0))
+#else
+#define likely(expr) (expr)
+#define unlikely(expr) (expr)
+#endif
+
#ifndef __GNUC__
#undef __attribute__
#define __attribute__(x)
diff --git a/src/cairo-debug.c b/src/cairo-debug.c
index 61156f0d..6dd5787a 100644
--- a/src/cairo-debug.c
+++ b/src/cairo-debug.c
@@ -67,6 +67,8 @@ cairo_debug_reset_static_data (void)
_cairo_ft_font_reset_static_data ();
#endif
+ _cairo_intern_string_reset_static_data ();
+
_cairo_scaled_font_reset_static_data ();
_cairo_pattern_reset_static_data ();
diff --git a/src/cairo-deflate-stream.c b/src/cairo-deflate-stream.c
index bf2784a2..863189f4 100644
--- a/src/cairo-deflate-stream.c
+++ b/src/cairo-deflate-stream.c
@@ -121,13 +121,14 @@ _cairo_deflate_stream_create (cairo_output_stream_t *output)
return _cairo_output_stream_create_in_error (output->status);
stream = malloc (sizeof (cairo_deflate_stream_t));
- if (stream == NULL) {
+ if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base,
_cairo_deflate_stream_write,
+ NULL,
_cairo_deflate_stream_close);
stream->output = output;
diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c
index 351e00d8..c31cf62c 100644
--- a/src/cairo-directfb-surface.c
+++ b/src/cairo-directfb-surface.c
@@ -455,7 +455,7 @@ _cairo_directfb_surface_create_similar (void *abstract_src,
format = _cairo_format_from_content (content);
surface = calloc (1, sizeof (cairo_directfb_surface_t));
- if (surface == NULL)
+ if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
surface->dfb = source->dfb;
@@ -549,6 +549,7 @@ _cairo_directfb_surface_release_source_image (void *abstract_su
cairo_image_surface_t *image,
void *image_extra)
{
+ cairo_directfb_surface_t *surface = abstract_surface;
IDirectFBSurface *buffer = image_extra;
D_DEBUG_AT (CairoDFB_Acquire,
@@ -1305,12 +1306,14 @@ _cairo_directfb_surface_set_clip_region (void *abstract_surface,
surface->has_clip = TRUE;
+ n_boxes = 0;
status = _cairo_region_get_boxes (region, &n_boxes, &boxes);
- if (n_boxes == 0)
- return CAIRO_STATUS_SUCCESS;
if (status)
return status;
+ if (n_boxes == 0)
+ return CAIRO_STATUS_SUCCESS;
+
if (surface->n_clips != n_boxes) {
if (surface->clips)
free (surface->clips);
@@ -1687,7 +1690,8 @@ _cairo_directfb_surface_show_glyphs (void *abstract_dst,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs)
+ int *remaining_glyphs,
+ cairo_rectangle_int_t *extents)
{
cairo_directfb_surface_t *dst = abstract_dst;
cairo_directfb_font_cache_t *cache;
@@ -1812,6 +1816,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-font-face-twin.c b/src/cairo-font-face-twin.c
index d8e662f1..5ac2cd2f 100644
--- a/src/cairo-font-face-twin.c
+++ b/src/cairo-font-face-twin.c
@@ -119,7 +119,8 @@ twin_scaled_font_render_glyph (cairo_scaled_font_t *scaled_font,
int n_snap_y;
} info = {FALSE};
- cairo_set_line_width (cr, 0.06);
+ cairo_set_tolerance (cr, 0.01);
+ cairo_set_line_width (cr, 0.066);
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
diff --git a/src/cairo-font-face.c b/src/cairo-font-face.c
index 6cea3958..a78c2aab 100644
--- a/src/cairo-font-face.c
+++ b/src/cairo-font-face.c
@@ -398,7 +398,7 @@ _cairo_toy_font_face_init (cairo_toy_font_face_t *font_face,
char *family_copy;
family_copy = strdup (family);
- if (family_copy == NULL)
+ if (unlikely (family_copy == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_cairo_toy_font_face_init_key (font_face, family_copy,
@@ -467,10 +467,12 @@ cairo_toy_font_face_create (const char *family,
/* Make sure we've got valid UTF-8 for the family */
status = _cairo_utf8_to_ucs4 (family, -1, NULL, NULL);
- if (status == CAIRO_STATUS_INVALID_STRING)
- return (cairo_font_face_t*) &_cairo_font_face_invalid_string;
- else if (status)
+ if (unlikely (status)) {
+ if (status == CAIRO_STATUS_INVALID_STRING)
+ return (cairo_font_face_t*) &_cairo_font_face_invalid_string;
+
return (cairo_font_face_t*) &_cairo_font_face_nil;
+ }
switch (slant) {
case CAIRO_FONT_SLANT_NORMAL:
@@ -493,17 +495,16 @@ cairo_toy_font_face_create (const char *family,
family = CAIRO_FONT_FAMILY_DEFAULT;
hash_table = _cairo_toy_font_face_hash_table_lock ();
- if (hash_table == NULL)
+ if (unlikely (hash_table == NULL))
goto UNWIND;
_cairo_toy_font_face_init_key (&key, family, slant, weight);
/* Return existing font_face if it exists in the hash table. */
- if (_cairo_hash_table_lookup (hash_table,
- &key.base.hash_entry,
- (cairo_hash_entry_t **) &font_face))
- {
- if (! font_face->base.status) {
+ font_face = _cairo_hash_table_lookup (hash_table,
+ &key.base.hash_entry);
+ if (font_face != NULL) {
+ if (font_face->base.status == CAIRO_STATUS_SUCCESS) {
/* We increment the reference count here manually to avoid
double-locking. */
_cairo_reference_count_inc (&font_face->base.ref_count);
@@ -512,23 +513,23 @@ cairo_toy_font_face_create (const char *family,
}
/* remove the bad font from the hash table */
- _cairo_hash_table_remove (hash_table, &key.base.hash_entry);
+ _cairo_hash_table_remove (hash_table, &font_face->base.hash_entry);
font_face->base.hash_entry.hash = 0;
}
/* Otherwise create it and insert into hash table. */
font_face = malloc (sizeof (cairo_toy_font_face_t));
- if (font_face == NULL) {
+ if (unlikely (font_face == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto UNWIND_HASH_TABLE_LOCK;
}
status = _cairo_toy_font_face_init (font_face, family, slant, weight);
- if (status)
+ if (unlikely (status))
goto UNWIND_FONT_FACE_MALLOC;
status = _cairo_hash_table_insert (hash_table, &font_face->base.hash_entry);
- if (status)
+ if (unlikely (status))
goto UNWIND_FONT_FACE_INIT;
_cairo_toy_font_face_hash_table_unlock ();
@@ -615,7 +616,7 @@ _cairo_toy_font_face_scaled_font_create (void *abstract_font_face
return font_face->base.status;
status = cairo_font_options_status ((cairo_font_options_t *) options);
- if (status)
+ if (unlikely (status))
return status;
if (CAIRO_SCALED_FONT_BACKEND_DEFAULT != &_cairo_user_scaled_font_backend &&
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index cd112532..773f6ea0 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -182,7 +182,7 @@ _cairo_ft_unscaled_font_map_create (void)
assert (cairo_ft_unscaled_font_map == NULL);
font_map = malloc (sizeof (cairo_ft_unscaled_font_map_t));
- if (font_map == NULL) {
+ if (unlikely (font_map == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
goto FAIL;
}
@@ -190,7 +190,7 @@ _cairo_ft_unscaled_font_map_create (void)
font_map->hash_table =
_cairo_hash_table_create (_cairo_ft_unscaled_font_keys_equal);
- if (font_map->hash_table == NULL)
+ if (unlikely (font_map->hash_table == NULL))
goto FAIL;
if (FT_Init_FreeType (&font_map->ft_library))
@@ -261,7 +261,7 @@ _cairo_ft_unscaled_font_map_lock (void)
{
_cairo_ft_unscaled_font_map_create ();
- if (cairo_ft_unscaled_font_map == NULL) {
+ if (unlikely (cairo_ft_unscaled_font_map == NULL)) {
CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
@@ -340,8 +340,9 @@ _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled,
unscaled->face = NULL;
filename_copy = strdup (filename);
- if (filename_copy == NULL)
+ if (unlikely (filename_copy == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
_cairo_ft_unscaled_font_init_key (unscaled, FALSE, filename_copy, id, NULL);
}
@@ -416,15 +417,15 @@ _cairo_ft_unscaled_font_create_internal (cairo_bool_t from_face,
cairo_status_t status;
font_map = _cairo_ft_unscaled_font_map_lock ();
- if (font_map == NULL)
+ if (unlikely (font_map == NULL))
goto UNWIND;
_cairo_ft_unscaled_font_init_key (&key, from_face, filename, id, font_face);
/* Return existing unscaled font if it exists in the hash table. */
- if (_cairo_hash_table_lookup (font_map->hash_table, &key.base.hash_entry,
- (cairo_hash_entry_t **) &unscaled))
- {
+ unscaled = _cairo_hash_table_lookup (font_map->hash_table,
+ &key.base.hash_entry);
+ if (unscaled != NULL) {
_cairo_unscaled_font_reference (&unscaled->base);
_cairo_ft_unscaled_font_map_unlock ();
return unscaled;
@@ -432,18 +433,18 @@ _cairo_ft_unscaled_font_create_internal (cairo_bool_t from_face,
/* Otherwise create it and insert into hash table. */
unscaled = malloc (sizeof (cairo_ft_unscaled_font_t));
- if (unscaled == NULL) {
+ if (unlikely (unscaled == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
goto UNWIND_FONT_MAP_LOCK;
}
status = _cairo_ft_unscaled_font_init (unscaled, from_face, filename, id, font_face);
- if (status)
+ if (unlikely (status))
goto UNWIND_UNSCALED_MALLOC;
status = _cairo_hash_table_insert (font_map->hash_table,
&unscaled->base.hash_entry);
- if (status)
+ if (unlikely (status))
goto UNWIND_UNSCALED_FONT_INIT;
_cairo_ft_unscaled_font_map_unlock ();
@@ -621,7 +622,7 @@ _compute_transform (cairo_ft_font_transform_t *sf,
status = _cairo_matrix_compute_basis_scale_factors (scale,
&x_scale, &y_scale,
1);
- if (status)
+ if (unlikely (status))
return status;
/* FreeType docs say this about x_scale and y_scale:
@@ -671,7 +672,7 @@ _cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled,
unscaled->current_scale = *scale;
status = _compute_transform (&sf, scale);
- if (status)
+ if (unlikely (status))
return status;
unscaled->x_scale = sf.x_scale;
@@ -874,7 +875,7 @@ _get_bitmap_surface (FT_Bitmap *bitmap,
stride = bitmap->pitch;
stride_rgba = (width_rgba * 4 + 3) & ~3;
data_rgba = calloc (stride_rgba, height);
- if (data_rgba == NULL) {
+ if (unlikely (data_rgba == NULL)) {
if (own_buffer)
free (bitmap->buffer);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -1073,7 +1074,7 @@ _render_glyph_outline (FT_Face face,
bitmap.width = width * hmul;
bitmap.rows = height * vmul;
bitmap.buffer = calloc (stride, bitmap.rows);
- if (bitmap.buffer == NULL)
+ if (unlikely (bitmap.buffer == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
FT_Outline_Translate (outline, -cbox.xMin*hmul, -cbox.yMin*vmul);
@@ -1084,7 +1085,7 @@ _render_glyph_outline (FT_Face face,
}
status = _get_bitmap_surface (&bitmap, TRUE, font_options, surface);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -1125,7 +1126,7 @@ _render_glyph_bitmap (FT_Face face,
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _get_bitmap_surface (&glyphslot->bitmap, FALSE, font_options, surface);
- if (status)
+ if (unlikely (status))
return status;
/*
@@ -1212,13 +1213,13 @@ _transform_glyph_bitmap (cairo_matrix_t * shape,
transformed_to_original = original_to_transformed;
status = cairo_matrix_invert (&transformed_to_original);
- if (status)
+ if (unlikely (status))
return status;
/* We need to pad out the width to 32-bit intervals for cairo-xlib-surface.c */
width = (width + 3) & ~3;
image = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
- if (image->status)
+ if (unlikely (image->status))
return image->status;
/* Initialize it to empty
@@ -1227,7 +1228,7 @@ _transform_glyph_bitmap (cairo_matrix_t * shape,
CAIRO_COLOR_TRANSPARENT,
0, 0,
width, height);
- if (status) {
+ if (unlikely (status)) {
cairo_surface_destroy (image);
return status;
}
@@ -1245,7 +1246,7 @@ _transform_glyph_bitmap (cairo_matrix_t * shape,
_cairo_pattern_fini (&pattern.base);
- if (status) {
+ if (unlikely (status)) {
cairo_surface_destroy (image);
return status;
}
@@ -1512,7 +1513,7 @@ _cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled,
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
scaled_font = malloc (sizeof(cairo_ft_scaled_font_t));
- if (scaled_font == NULL) {
+ if (unlikely (scaled_font == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FAIL;
}
@@ -1527,7 +1528,7 @@ _cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled,
font_face,
font_matrix, ctm, options,
&_cairo_ft_scaled_font_backend);
- if (status) {
+ if (unlikely (status)) {
_cairo_unscaled_font_destroy (&unscaled->base);
free (scaled_font);
goto FAIL;
@@ -1535,7 +1536,7 @@ _cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled,
status = _cairo_ft_unscaled_font_set_scale (unscaled,
&scaled_font->base.scale);
- if (status) {
+ if (unlikely (status)) {
_cairo_unscaled_font_destroy (&unscaled->base);
free (scaled_font);
goto FAIL;
@@ -1626,7 +1627,7 @@ _cairo_ft_scaled_font_create_toy (cairo_toy_font_face_t *toy_face,
cairo_matrix_multiply (&scale, font_matrix, ctm);
status = _compute_transform (&sf, &scale);
- if (status)
+ if (unlikely (status))
return status;
pattern = FcPatternCreate ();
@@ -1686,7 +1687,7 @@ _cairo_ft_scaled_font_create_toy (cairo_toy_font_face_t *toy_face,
}
status = _cairo_ft_font_options_substitute (font_options, pattern);
- if (status)
+ if (unlikely (status))
goto FREE_PATTERN;
FcDefaultSubstitute (pattern);
@@ -1863,7 +1864,7 @@ _decompose_glyph_outline (FT_Face face,
}
status = _cairo_path_fixed_close_path (path);
- if (status) {
+ if (unlikely (status)) {
_cairo_path_fixed_destroy (path);
return status;
}
@@ -1918,7 +1919,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
status = _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled,
&scaled_font->base.scale);
- if (status)
+ if (unlikely (status))
goto FAIL;
/* Ignore global advance unconditionally */
@@ -2066,14 +2067,16 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
} else {
status = _render_glyph_bitmap (face, &scaled_font->ft_options.base,
&surface);
- if (status == CAIRO_STATUS_SUCCESS && unscaled->have_shape) {
+ if (likely (status == CAIRO_STATUS_SUCCESS) &&
+ unscaled->have_shape)
+ {
status = _transform_glyph_bitmap (&unscaled->current_shape,
&surface);
- if (status)
+ if (unlikely (status))
cairo_surface_destroy (&surface->base);
}
}
- if (status)
+ if (unlikely (status))
goto FAIL;
_cairo_scaled_glyph_set_surface (scaled_glyph,
@@ -2115,7 +2118,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
else
status = CAIRO_INT_STATUS_UNSUPPORTED;
- if (status)
+ if (unlikely (status))
goto FAIL;
_cairo_scaled_glyph_set_path (scaled_glyph,
@@ -2530,7 +2533,7 @@ cairo_ft_font_face_create_for_pattern (FcPattern *pattern)
cairo_ft_options_t ft_options;
unscaled = _cairo_ft_unscaled_font_create_for_pattern (pattern);
- if (unscaled == NULL) {
+ if (unlikely (unscaled == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_font_face_t *)&_cairo_font_face_nil;
}
@@ -2597,7 +2600,7 @@ cairo_ft_font_face_create_for_ft_face (FT_Face face,
cairo_ft_options_t ft_options;
unscaled = _cairo_ft_unscaled_font_create_from_face (face);
- if (unscaled == NULL) {
+ if (unlikely (unscaled == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_font_face_t *)&_cairo_font_face_nil;
}
@@ -2658,14 +2661,14 @@ cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font)
return NULL;
face = _cairo_ft_unscaled_font_lock_face (scaled_font->unscaled);
- if (face == NULL) {
+ if (unlikely (face == NULL)) {
status = _cairo_scaled_font_set_error (&scaled_font->base, CAIRO_STATUS_NO_MEMORY);
return NULL;
}
status = _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled,
&scaled_font->base.scale);
- if (status) {
+ if (unlikely (status)) {
_cairo_ft_unscaled_font_unlock_face (scaled_font->unscaled);
status = _cairo_scaled_font_set_error (&scaled_font->base, status);
return NULL;
@@ -2739,6 +2742,18 @@ _cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font)
return FALSE;
}
+unsigned int
+_cairo_ft_scaled_font_get_load_flags (cairo_scaled_font_t *scaled_font)
+{
+ cairo_ft_scaled_font_t *ft_scaled_font;
+
+ if (! _cairo_scaled_font_is_ft (scaled_font))
+ return 0;
+
+ ft_scaled_font = (cairo_ft_scaled_font_t *) scaled_font;
+ return ft_scaled_font->ft_options.load_flags;
+}
+
void
_cairo_ft_font_reset_static_data (void)
{
diff --git a/src/cairo-ft-private.h b/src/cairo-ft-private.h
index 3e7d3de0..00f7f77c 100644
--- a/src/cairo-ft-private.h
+++ b/src/cairo-ft-private.h
@@ -64,6 +64,9 @@ _cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled);
cairo_private cairo_bool_t
_cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font);
+cairo_private unsigned int
+_cairo_ft_scaled_font_get_load_flags (cairo_scaled_font_t *scaled_font);
+
CAIRO_END_DECLS
#endif /* CAIRO_HAS_FT_FONT */
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index 5bdfa700..f049f401 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -33,8 +33,10 @@ typedef struct _cairo_glitz_surface {
glitz_surface_t *surface;
glitz_format_t *format;
- cairo_bool_t has_clip;
- cairo_region_t clip;
+
+ cairo_bool_t has_clip;
+ glitz_box_t *clip_boxes;
+ int num_clip_boxes;
} cairo_glitz_surface_t;
static const cairo_surface_backend_t *
@@ -45,10 +47,8 @@ _cairo_glitz_surface_finish (void *abstract_surface)
{
cairo_glitz_surface_t *surface = abstract_surface;
- if (surface->has_clip) {
- glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0);
- _cairo_region_fini (&surface->clip);
- }
+ if (surface->clip_boxes)
+ free (surface->clip_boxes);
glitz_surface_destroy (surface->surface);
@@ -106,78 +106,40 @@ _cairo_glitz_surface_create_similar (void *abstract_src,
return crsurface;
}
-static cairo_bool_t
-_CAIRO_MASK_FORMAT (cairo_format_masks_t *masks, cairo_format_t *format)
-{
- switch (masks->bpp) {
- case 32:
- if (masks->alpha_mask == 0xff000000 &&
- masks->red_mask == 0x00ff0000 &&
- masks->green_mask == 0x0000ff00 &&
- masks->blue_mask == 0x000000ff)
- {
- *format = CAIRO_FORMAT_ARGB32;
- return TRUE;
- }
- if (masks->alpha_mask == 0x00000000 &&
- masks->red_mask == 0x00ff0000 &&
- masks->green_mask == 0x0000ff00 &&
- masks->blue_mask == 0x000000ff)
- {
- *format = CAIRO_FORMAT_RGB24;
- return TRUE;
- }
- break;
- case 8:
- if (masks->alpha_mask == 0xff)
- {
- *format = CAIRO_FORMAT_A8;
- return TRUE;
- }
- break;
- case 1:
- if (masks->alpha_mask == 0x1)
- {
- *format = CAIRO_FORMAT_A1;
- return TRUE;
- }
- break;
- }
- return FALSE;
-}
-
static cairo_status_t
-_cairo_glitz_get_boxes_from_region (cairo_region_t *region, glitz_box_t **boxes, int *nboxes)
+_cairo_glitz_get_boxes_from_region (cairo_region_t *region,
+ glitz_box_t **boxes,
+ int *nboxes)
{
- cairo_box_int_t *cboxes;
- cairo_status_t status;
- int n, i;
+ pixman_box32_t *pboxes;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
- status = _cairo_region_get_boxes (region, &n, &cboxes);
- if (status)
- return status;
+ int n, i;
+ n = 0;
+ pboxes = pixman_region32_rectangles (&region->rgn, &n);
if (n == 0) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto done;
+ *nboxes = 0;
+ return CAIRO_STATUS_SUCCESS;
}
- *boxes = _cairo_malloc_ab (n, sizeof(glitz_box_t));
- if (*boxes == NULL) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto done;
+ if (n > *nboxes) {
+ *boxes = _cairo_malloc_ab (n, sizeof (glitz_box_t));
+ if (*boxes == NULL) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto done;
+ }
}
for (i = 0; i < n; i++) {
- (*boxes)[i].x1 = cboxes[i].p1.x;
- (*boxes)[i].y1 = cboxes[i].p1.y;
- (*boxes)[i].x2 = cboxes[i].p2.x;
- (*boxes)[i].y2 = cboxes[i].p2.y;
+ (*boxes)[i].x1 = pboxes[i].x1;
+ (*boxes)[i].y1 = pboxes[i].y1;
+ (*boxes)[i].x2 = pboxes[i].x2;
+ (*boxes)[i].y2 = pboxes[i].y2;
}
*nboxes = n;
done:
- _cairo_region_boxes_fini (region, cboxes);
return status;
}
@@ -188,94 +150,62 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
cairo_rectangle_int_t *rect_out)
{
cairo_image_surface_t *image;
- int x1, y1, x2, y2;
- int width, height;
- unsigned char *pixels;
+ cairo_rectangle_int_t extents;
+ cairo_format_t format;
cairo_format_masks_t masks;
glitz_buffer_t *buffer;
glitz_pixel_format_t pf;
- cairo_format_t format;
- x1 = 0;
- y1 = 0;
- x2 = glitz_surface_get_width (surface->surface);
- y2 = glitz_surface_get_height (surface->surface);
+ extents.x = 0;
+ extents.y = 0;
+ extents.width = glitz_surface_get_width (surface->surface);
+ extents.height = glitz_surface_get_height (surface->surface);
- if (interest)
- {
- if (interest->x > x1)
- x1 = interest->x;
- if (interest->y > y1)
- y1 = interest->y;
- if (interest->x + interest->width < x2)
- x2 = interest->x + interest->width;
- if (interest->y + interest->height < y2)
- y2 = interest->y + interest->height;
-
- if (x1 >= x2 || y1 >= y2)
- {
+ if (interest != NULL) {
+ if (! _cairo_rectangle_intersect (&extents, interest)) {
*image_out = NULL;
return CAIRO_STATUS_SUCCESS;
}
}
- width = x2 - x1;
- height = y2 - y1;
-
- if (rect_out)
- {
- rect_out->x = x1;
- rect_out->y = y1;
- rect_out->width = width;
- rect_out->height = height;
- }
+ if (rect_out != NULL)
+ *rect_out = extents;
if (surface->format->color.fourcc == GLITZ_FOURCC_RGB) {
if (surface->format->color.red_size > 0) {
- masks.bpp = 32;
-
if (surface->format->color.alpha_size > 0)
- masks.alpha_mask = 0xff000000;
+ format = CAIRO_FORMAT_ARGB32;
else
- masks.alpha_mask = 0x0;
-
- masks.red_mask = 0xff0000;
- masks.green_mask = 0xff00;
- masks.blue_mask = 0xff;
+ format = CAIRO_FORMAT_RGB24;
} else {
- masks.bpp = 8;
- masks.blue_mask = masks.green_mask = masks.red_mask = 0x0;
- masks.alpha_mask = 0xff;
+ format = CAIRO_FORMAT_A8;
}
- } else {
- masks.bpp = 32;
- masks.alpha_mask = 0xff000000;
- masks.red_mask = 0xff0000;
- masks.green_mask = 0xff00;
- masks.blue_mask = 0xff;
- }
+ } else
+ format = CAIRO_FORMAT_ARGB32;
+
+ image = (cairo_image_surface_t*)
+ cairo_image_surface_create (format, extents.width, extents.height);
+ if (image->base.status)
+ return image->base.status;
+ _pixman_format_to_masks (image->pixman_format, &masks);
pf.fourcc = GLITZ_FOURCC_RGB;
pf.masks.bpp = masks.bpp;
pf.masks.alpha_mask = masks.alpha_mask;
- pf.masks.red_mask = masks.red_mask;
+ pf.masks.red_mask = masks.red_mask;
pf.masks.green_mask = masks.green_mask;
- pf.masks.blue_mask = masks.blue_mask;
+ pf.masks.blue_mask = masks.blue_mask;
pf.xoffset = 0;
pf.skip_lines = 0;
/* XXX: we should eventually return images with negative stride,
need to verify that libpixman have no problem with this first. */
- pf.bytes_per_line = (((width * masks.bpp) / 8) + 3) & -4;
+ pf.bytes_per_line = image->stride;
pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
- pixels = _cairo_malloc_ab (height, pf.bytes_per_line);
- if (!pixels)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- buffer = glitz_buffer_create_for_data (pixels);
- if (!buffer) {
- free (pixels);
+ buffer = glitz_buffer_create_for_data (image->data);
+ if (buffer == NULL) {
+ cairo_surface_destroy (&image->base);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -285,8 +215,8 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
0, 0, NULL, 0);
glitz_get_pixels (surface->surface,
- x1, y1,
- width, height,
+ extents.x, extents.y,
+ extents.width, extents.height,
&pf,
buffer);
@@ -294,97 +224,15 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
/* restore the clip, if any */
if (surface->has_clip) {
- glitz_box_t *box;
- cairo_status_t status;
- int n;
-
- status = _cairo_glitz_get_boxes_from_region (&surface->clip, &box, &n);
- if (status) {
- free (pixels);
- return status;
- }
-
- glitz_surface_set_clip_region (surface->surface, 0, 0, box, n);
-
- free (box);
- }
-
- /*
- * Prefer to use a standard pixman format instead of the
- * general masks case.
- */
- if (_CAIRO_MASK_FORMAT (&masks, &format)) {
- image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data (pixels,
- format,
- x2 - x1,
- y2 - y1,
- pf.bytes_per_line);
- if (image->base.status)
- goto FAIL;
- } else {
- /*
- * XXX This can't work. We must convert the data to one of the
- * supported pixman formats. Pixman needs another function
- * which takes data in an arbitrary format and converts it
- * to something supported by that library.
- */
- image = (cairo_image_surface_t *)
- _cairo_image_surface_create_with_masks (pixels,
- &masks,
- x2 - x1,
- y2 - y1,
- pf.bytes_per_line);
- if (image->base.status)
- goto FAIL;
+ glitz_surface_set_clip_region (surface->surface,
+ 0, 0,
+ surface->clip_boxes,
+ surface->num_clip_boxes);
}
- _cairo_image_surface_assume_ownership_of_data (image);
-
*image_out = image;
return CAIRO_STATUS_SUCCESS;
-
-FAIL:
- free (pixels);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-}
-
-static void
-cairo_format_get_masks (cairo_format_t format,
- uint32_t *bpp,
- uint32_t *alpha,
- uint32_t *red,
- uint32_t *green,
- uint32_t *blue)
-{
- *red = 0x0;
- *green = 0x0;
- *blue = 0x0;
- *alpha = 0x0;
-
- switch (format)
- {
- case CAIRO_FORMAT_ARGB32:
- *alpha = 0xff000000;
- case CAIRO_FORMAT_RGB24:
- default:
- *bpp = 32;
- *red = 0x00ff0000;
- *green = 0x0000ff00;
- *blue = 0x000000ff;
- break;
-
- case CAIRO_FORMAT_A8:
- *bpp = 8;
- *alpha = 0xff;
- break;
-
- case CAIRO_FORMAT_A1:
- *bpp = 1;
- *alpha = 0x1;
- break;
- }
}
static cairo_status_t
@@ -400,36 +248,33 @@ _cairo_glitz_surface_set_image (void *abstract_surface,
cairo_glitz_surface_t *surface = abstract_surface;
glitz_buffer_t *buffer;
glitz_pixel_format_t pf;
- uint32_t bpp, am, rm, gm, bm;
+ cairo_format_masks_t masks;
char *data;
- cairo_format_get_masks (image->format, &bpp, &am, &rm, &gm, &bm);
+ _pixman_format_to_masks (image->pixman_format, &masks);
pf.fourcc = GLITZ_FOURCC_RGB;
- pf.masks.bpp = bpp;
- pf.masks.alpha_mask = am;
- pf.masks.red_mask = rm;
- pf.masks.green_mask = gm;
- pf.masks.blue_mask = bm;
+ pf.masks.bpp = masks.bpp;
+ pf.masks.alpha_mask = masks.alpha_mask;
+ pf.masks.red_mask = masks.red_mask;
+ pf.masks.green_mask = masks.green_mask;
+ pf.masks.blue_mask = masks.blue_mask;
pf.xoffset = src_x;
pf.skip_lines = src_y;
/* check for negative stride */
- if (image->stride < 0)
- {
+ if (image->stride < 0) {
pf.bytes_per_line = -image->stride;
pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP;
data = (char *) image->data + image->stride * (image->height - 1);
- }
- else
- {
+ } else {
pf.bytes_per_line = image->stride;
pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_TOP_DOWN;
data = (char *) image->data;
}
buffer = glitz_buffer_create_for_data (data);
- if (!buffer)
+ if (buffer == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
glitz_set_pixels (surface->surface,
@@ -533,43 +378,27 @@ _cairo_glitz_surface_clone_similar (void *abstract_surface,
else if (_cairo_surface_is_image (src))
{
cairo_image_surface_t *image_src = (cairo_image_surface_t *) src;
- cairo_content_t content;
- cairo_rectangle_int_t image_extent;
- cairo_rectangle_int_t extent;
-
- content = _cairo_content_from_format (image_src->format);
clone = (cairo_glitz_surface_t *)
- _cairo_glitz_surface_create_similar (surface, content,
- image_src->width,
- image_src->height);
+ _cairo_glitz_surface_create_similar (surface, src->content,
+ width, height);
if (clone == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
if (clone->base.status)
return clone->base.status;
- image_extent.x = 0;
- image_extent.y = 0;
- image_extent.width = image_src->width;
- image_extent.height = image_src->height;
- extent.x = src_x;
- extent.y = src_y;
- extent.width = width;
- extent.height = height;
-
- _cairo_rectangle_intersect(&extent, &image_extent);
-
status = _cairo_glitz_surface_set_image (clone, image_src,
- extent.x, extent.y,
- extent.width, extent.height,
- extent.x, extent.y);
+ src_x, src_y,
+ width, height,
+ 0, 0);
if (status) {
cairo_surface_destroy (&clone->base);
return status;
}
*clone_out = &clone->base;
-
+ *clone_offset_x = src_x;
+ *clone_offset_y = src_y;
return CAIRO_STATUS_SUCCESS;
}
@@ -582,17 +411,17 @@ _cairo_glitz_surface_set_matrix (cairo_glitz_surface_t *surface,
{
glitz_transform_t transform;
- transform.matrix[0][0] = _cairo_fixed_from_double (matrix->xx);
- transform.matrix[0][1] = _cairo_fixed_from_double (matrix->xy);
- transform.matrix[0][2] = _cairo_fixed_from_double (matrix->x0);
+ transform.matrix[0][0] = _cairo_fixed_16_16_from_double (matrix->xx);
+ transform.matrix[0][1] = _cairo_fixed_16_16_from_double (matrix->xy);
+ transform.matrix[0][2] = _cairo_fixed_16_16_from_double (matrix->x0);
- transform.matrix[1][0] = _cairo_fixed_from_double (matrix->yx);
- transform.matrix[1][1] = _cairo_fixed_from_double (matrix->yy);
- transform.matrix[1][2] = _cairo_fixed_from_double (matrix->y0);
+ transform.matrix[1][0] = _cairo_fixed_16_16_from_double (matrix->yx);
+ transform.matrix[1][1] = _cairo_fixed_16_16_from_double (matrix->yy);
+ transform.matrix[1][2] = _cairo_fixed_16_16_from_double (matrix->y0);
transform.matrix[2][0] = 0;
transform.matrix[2][1] = 0;
- transform.matrix[2][2] = _cairo_fixed_from_double (1);
+ transform.matrix[2][2] = _cairo_fixed_16_16_from_double (1);
glitz_surface_set_transform (surface->surface, &transform);
}
@@ -836,22 +665,22 @@ _cairo_glitz_pattern_acquire_surface (const cairo_pattern_t *pattern,
{
cairo_linear_pattern_t *grad = (cairo_linear_pattern_t *) pattern;
- params[0] = grad->p1.x;
- params[1] = grad->p1.y;
- params[2] = grad->p2.x;
- params[3] = grad->p2.y;
+ params[0] = _cairo_fixed_to_16_16 (grad->p1.x);
+ params[1] = _cairo_fixed_to_16_16 (grad->p1.y);
+ params[2] = _cairo_fixed_to_16_16 (grad->p2.x);
+ params[3] = _cairo_fixed_to_16_16 (grad->p2.y);
attr->filter = GLITZ_FILTER_LINEAR_GRADIENT;
}
else
{
cairo_radial_pattern_t *grad = (cairo_radial_pattern_t *) pattern;
- params[0] = grad->c1.x;
- params[1] = grad->c1.y;
- params[2] = grad->r1;
- params[3] = grad->c2.x;
- params[4] = grad->c2.y;
- params[5] = grad->r2;
+ params[0] = _cairo_fixed_to_16_16 (grad->c1.x);
+ params[1] = _cairo_fixed_to_16_16 (grad->c1.y);
+ params[2] = _cairo_fixed_to_16_16 (grad->r1);
+ params[3] = _cairo_fixed_to_16_16 (grad->c2.x);
+ params[4] = _cairo_fixed_to_16_16 (grad->c2.y);
+ params[5] = _cairo_fixed_to_16_16 (grad->r2);
attr->filter = GLITZ_FILTER_RADIAL_GRADIENT;
}
@@ -1081,11 +910,6 @@ _cairo_glitz_surface_composite (cairo_operator_t op,
mask_y + mask_attr.base.y_offset,
dst_x, dst_y,
width, height);
-
- if (mask_attr.n_params)
- free (mask_attr.params);
-
- _cairo_glitz_pattern_release_surface (mask_pattern, mask, &mask_attr);
}
else
{
@@ -1100,14 +924,50 @@ _cairo_glitz_surface_composite (cairo_operator_t op,
width, height);
}
+ if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (status == CAIRO_STATUS_SUCCESS &&
+ ! _cairo_operator_bounded_by_source (op))
+ {
+ int src_width, src_height;
+ int mask_width, mask_height;
+
+ src_width = glitz_surface_get_width (src->surface);
+ src_height = glitz_surface_get_height (src->surface);
+ if (mask)
+ {
+ mask_width = glitz_surface_get_width (mask->surface);
+ mask_height = glitz_surface_get_height (mask->surface);
+ }
+ else
+ {
+ mask_width = 0;
+ mask_height = 0;
+ }
+ status = _cairo_surface_composite_fixup_unbounded (&dst->base,
+ &src_attr.base,
+ src_width, src_height,
+ mask ? &mask_attr.base : NULL,
+ mask_width, mask_height,
+ src_x, src_y,
+ mask_x, mask_y,
+ dst_x, dst_y, width, height);
+ }
+
+ if (mask)
+ {
+ if (mask_attr.n_params)
+ free (mask_attr.params);
+
+ _cairo_glitz_pattern_release_surface (mask_pattern, mask, &mask_attr);
+ }
+
if (src_attr.n_params)
free (src_attr.params);
_cairo_glitz_pattern_release_surface (src_pattern, src, &src_attr);
- if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
return CAIRO_STATUS_SUCCESS;
}
@@ -1120,24 +980,47 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
{
cairo_glitz_surface_t *dst = abstract_dst;
cairo_glitz_surface_t *src;
+ glitz_rectangle_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (glitz_rectangle_t)];
+ glitz_rectangle_t *glitz_rects = stack_rects;
+ glitz_rectangle_t *current_rect;
+ int i;
+
+ if (n_rects > ARRAY_LENGTH (stack_rects)) {
+ glitz_rects = _cairo_malloc_ab (n_rects, sizeof (glitz_rectangle_t));
+ if (glitz_rects == NULL)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ for (i = 0; i < n_rects; i++) {
+ glitz_rects[i].x = rects[i].x;
+ glitz_rects[i].y = rects[i].y;
+ glitz_rects[i].width = rects[i].width;
+ glitz_rects[i].height = rects[i].height;
+ }
switch (op) {
+ case CAIRO_OPERATOR_CLEAR:
case CAIRO_OPERATOR_SOURCE: {
glitz_color_t glitz_color;
+ glitz_format_t *format;
glitz_color.red = color->red_short;
glitz_color.green = color->green_short;
glitz_color.blue = color->blue_short;
glitz_color.alpha = color->alpha_short;
- glitz_set_rectangles (dst->surface, &glitz_color,
- (glitz_rectangle_t *) rects, n_rects);
- } break;
- case CAIRO_OPERATOR_CLEAR: {
- static const glitz_color_t glitz_color = { 0, 0, 0, 0 };
+ /*
+ * XXX even if the dst surface don't have an alpha channel, the
+ * above alpha still effect the dst surface because the
+ * underlying glitz drawable may have an alpha channel. So
+ * replacing the color with an opaque one is needed.
+ */
+ format = glitz_surface_get_format (dst->surface);
+ if (format->color.alpha_size == 0)
+ glitz_color.alpha = 0xffff;
- glitz_set_rectangles (dst->surface, &glitz_color,
- (glitz_rectangle_t *) rects, n_rects);
+ glitz_set_rectangles (dst->surface, &glitz_color,
+ glitz_rects, n_rects);
} break;
case CAIRO_OPERATOR_SATURATE:
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1154,7 +1037,11 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
case CAIRO_OPERATOR_ADD:
default:
if (_glitz_ensure_target (dst->surface))
+ {
+ if (glitz_rects != stack_rects)
+ free (glitz_rects);
return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
src = (cairo_glitz_surface_t *)
_cairo_surface_create_similar_solid (&dst->base,
@@ -1162,10 +1049,15 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
1, 1,
(cairo_color_t *) color);
if (src->base.status)
+ {
+ if (glitz_rects != stack_rects)
+ free (glitz_rects);
return src->base.status;
+ }
glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT);
+ current_rect = glitz_rects;
while (n_rects--)
{
glitz_composite (_glitz_operator (op),
@@ -1174,15 +1066,18 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
dst->surface,
0, 0,
0, 0,
- rects->x, rects->y,
- rects->width, rects->height);
- rects++;
+ current_rect->x, current_rect->y,
+ current_rect->width, current_rect->height);
+ current_rect++;
}
cairo_surface_destroy (&src->base);
break;
}
+ if (glitz_rects != stack_rects)
+ free (glitz_rects);
+
if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1203,8 +1098,6 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
cairo_trapezoid_t *traps,
int n_traps)
{
- cairo_pattern_union_t tmp_src_pattern;
- const cairo_pattern_t *src_pattern;
cairo_glitz_surface_attributes_t attributes;
cairo_glitz_surface_t *dst = abstract_dst;
cairo_glitz_surface_t *src;
@@ -1213,13 +1106,15 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
void *data = NULL;
cairo_int_status_t status;
unsigned short alpha;
+ pixman_trapezoid_t stack_traps[CAIRO_STACK_ARRAY_LENGTH (pixman_trapezoid_t)];
+ pixman_trapezoid_t *pixman_traps = stack_traps;
+ int i;
if (antialias != CAIRO_ANTIALIAS_DEFAULT &&
antialias != CAIRO_ANTIALIAS_GRAY)
+ {
return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (dst->base.status)
- return dst->base.status;
+ }
if (op == CAIRO_OPERATOR_SATURATE)
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -1227,34 +1122,36 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
if (_glitz_ensure_target (dst->surface))
return CAIRO_INT_STATUS_UNSUPPORTED;
- if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
- {
- status = _cairo_pattern_init_copy (&tmp_src_pattern.base, pattern);
- if (status)
- return status;
-
- status = _cairo_glitz_pattern_acquire_surface (&tmp_src_pattern.base,
- dst,
- src_x, src_y,
- width, height,
- &src, &attributes);
- src_pattern = &tmp_src_pattern.base;
+ /* Convert traps to pixman traps */
+ if (n_traps > ARRAY_LENGTH (stack_traps)) {
+ pixman_traps = _cairo_malloc_ab (n_traps, sizeof (pixman_trapezoid_t));
+ if (pixman_traps == NULL)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
- else
- {
- status = _cairo_glitz_pattern_acquire_surface (pattern, dst,
- src_x, src_y,
- width, height,
- &src, &attributes);
- src_pattern = pattern;
+
+ for (i = 0; i < n_traps; i++) {
+ pixman_traps[i].top = _cairo_fixed_to_16_16 (traps[i].top);
+ pixman_traps[i].bottom = _cairo_fixed_to_16_16 (traps[i].bottom);
+ pixman_traps[i].left.p1.x = _cairo_fixed_to_16_16 (traps[i].left.p1.x);
+ pixman_traps[i].left.p1.y = _cairo_fixed_to_16_16 (traps[i].left.p1.y);
+ pixman_traps[i].left.p2.x = _cairo_fixed_to_16_16 (traps[i].left.p2.x);
+ pixman_traps[i].left.p2.y = _cairo_fixed_to_16_16 (traps[i].left.p2.y);
+ pixman_traps[i].right.p1.x = _cairo_fixed_to_16_16 (traps[i].right.p1.x);
+ pixman_traps[i].right.p1.y = _cairo_fixed_to_16_16 (traps[i].right.p1.y);
+ pixman_traps[i].right.p2.x = _cairo_fixed_to_16_16 (traps[i].right.p2.x);
+ pixman_traps[i].right.p2.y = _cairo_fixed_to_16_16 (traps[i].right.p2.y);
}
- alpha = 0xffff;
+ status = _cairo_glitz_pattern_acquire_surface (pattern, dst,
+ src_x, src_y,
+ width, height,
+ &src, &attributes);
if (status)
- return status;
+ goto FAIL;
- if (op == CAIRO_OPERATOR_ADD || n_traps <= 1)
- {
+ alpha = 0xffff;
+
+ if (op == CAIRO_OPERATOR_ADD || n_traps <= 1) {
static const glitz_color_t clear_black = { 0, 0, 0, 0 };
glitz_color_t color;
glitz_geometry_format_t format;
@@ -1276,17 +1173,12 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
CAIRO_CONTENT_ALPHA,
2, 1);
if (mask == NULL) {
- _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes);
- if (src_pattern == &tmp_src_pattern.base)
- _cairo_pattern_fini (&tmp_src_pattern.base);
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto FAIL;
}
if (mask->base.status) {
- _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes);
- if (src_pattern == &tmp_src_pattern.base)
- _cairo_pattern_fini (&tmp_src_pattern.base);
-
- return mask->base.status;
+ status = mask->base.status;
+ goto FAIL;
}
color.red = color.green = color.blue = color.alpha = 0xffff;
@@ -1301,20 +1193,15 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
size *= format.vertex.bytes_per_vertex;
- while (n_traps)
- {
- if (data_size < size)
- {
+ while (n_traps) {
+ if (data_size < size) {
void *p;
+
data_size = size;
p = realloc (data, data_size);
- if (!p)
- {
- _cairo_glitz_pattern_release_surface (src_pattern, src,
- &attributes);
- if (src_pattern == &tmp_src_pattern.base)
- _cairo_pattern_fini (&tmp_src_pattern.base);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ if (p == NULL) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto FAIL;
}
data = p;
@@ -1322,13 +1209,10 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
glitz_buffer_destroy (buffer);
buffer = glitz_buffer_create_for_data (data);
- if (!buffer) {
+ if (buffer == NULL) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
free (data);
- _cairo_glitz_pattern_release_surface (src_pattern, src,
- &attributes);
- if (src_pattern == &tmp_src_pattern.base)
- _cairo_pattern_fini (&tmp_src_pattern.base);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto FAIL;
}
}
@@ -1336,7 +1220,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
glitz_add_trapezoids (buffer,
offset, size - offset,
format.vertex.type, mask->surface,
- (glitz_trapezoid_t *) traps, n_traps,
+ (glitz_trapezoid_t *) pixman_traps, n_traps,
&n_trap_added);
n_traps -= n_trap_added;
@@ -1350,21 +1234,16 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
glitz_set_array (dst->surface, 0, 3,
offset / format.vertex.bytes_per_vertex,
0, 0);
- }
- else
- {
+ } else {
cairo_image_surface_t *image;
unsigned char *ptr;
int stride;
stride = (width + 3) & -4;
data = calloc (stride, height);
- if (!data)
- {
- _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes);
- if (src_pattern == &tmp_src_pattern.base)
- _cairo_pattern_fini (&tmp_src_pattern.base);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ if (data == NULL) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto FAIL;
}
/* using negative stride */
@@ -1375,34 +1254,33 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
CAIRO_FORMAT_A8,
width, height,
-stride);
- if (image->base.status)
- {
- cairo_surface_destroy (&src->base);
+ status = image->base.status;
+ if (status) {
free (data);
- return image->base.status;
+ goto FAIL;
}
pixman_add_trapezoids (image->pixman_image, -dst_x, -dst_y,
- n_traps, (pixman_trapezoid_t *) traps);
+ n_traps, (pixman_trapezoid_t *) pixman_traps);
mask = (cairo_glitz_surface_t *)
_cairo_surface_create_similar_scratch (&dst->base,
CAIRO_CONTENT_ALPHA,
width, height);
- if (mask->base.status) {
- _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes);
+ status = mask->base.status;
+ if (status) {
free (data);
cairo_surface_destroy (&image->base);
- return mask->base.status;
+ goto FAIL;
}
status = _cairo_glitz_surface_set_image (mask, image,
0, 0, width, height, 0, 0);
- cairo_surface_destroy(&image->base);
+ cairo_surface_destroy (&image->base);
if (status)
- return status;
+ goto FAIL;
}
_cairo_glitz_surface_set_attributes (src, &attributes);
@@ -1429,17 +1307,33 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
free (data);
- _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes);
- if (src_pattern == &tmp_src_pattern.base)
- _cairo_pattern_fini (&tmp_src_pattern.base);
+ if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto FAIL;
+ }
- if (mask)
+ if (! _cairo_operator_bounded_by_mask (op)) {
+ status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
+ &attributes.base,
+ glitz_surface_get_width (src->surface),
+ glitz_surface_get_height (src->surface),
+ width, height,
+ src_x, src_y,
+ 0, 0,
+ dst_x, dst_y,
+ width, height);
+ }
+
+FAIL:
+ _cairo_glitz_pattern_release_surface (pattern, src, &attributes);
+
+ if (mask != NULL)
cairo_surface_destroy (&mask->base);
- if (glitz_surface_get_status (dst->surface) == GLITZ_STATUS_NOT_SUPPORTED)
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (pixman_traps != stack_traps)
+ free (pixman_traps);
- return CAIRO_STATUS_SUCCESS;
+ return status;
}
static cairo_int_status_t
@@ -1448,43 +1342,23 @@ _cairo_glitz_surface_set_clip_region (void *abstract_surface,
{
cairo_glitz_surface_t *surface = abstract_surface;
- if (region)
- {
- glitz_box_t *box;
- int n;
+ if (region != NULL) {
cairo_status_t status;
- if (!surface->has_clip) {
- _cairo_region_init (&surface->clip);
- surface->has_clip = TRUE;
- }
-
- status = _cairo_region_copy (&surface->clip, region);
- if (status) {
- _cairo_region_fini (&surface->clip);
- surface->has_clip = FALSE;
- return status;
- }
-
- status = _cairo_glitz_get_boxes_from_region (&surface->clip, &box, &n);
- if (status) {
- _cairo_region_fini (&surface->clip);
- surface->has_clip = FALSE;
+ status = _cairo_glitz_get_boxes_from_region (region,
+ &surface->clip_boxes,
+ &surface->num_clip_boxes);
+ if (status)
return status;
- }
-
- glitz_surface_set_clip_region (surface->surface, 0, 0, box, n);
- free (box);
- }
- else
- {
+ glitz_surface_set_clip_region (surface->surface,
+ 0, 0,
+ surface->clip_boxes,
+ surface->num_clip_boxes);
+ surface->has_clip = TRUE;
+ } else {
glitz_surface_set_clip_region (surface->surface, 0, 0, NULL, 0);
-
- if (surface->has_clip) {
- _cairo_region_fini (&surface->clip);
- surface->has_clip = FALSE;
- }
+ surface->has_clip = FALSE;
}
return CAIRO_STATUS_SUCCESS;
@@ -1498,7 +1372,7 @@ _cairo_glitz_surface_get_extents (void *abstract_surface,
rectangle->x = 0;
rectangle->y = 0;
- rectangle->width = glitz_surface_get_width (surface->surface);
+ rectangle->width = glitz_surface_get_width (surface->surface);
rectangle->height = glitz_surface_get_height (surface->surface);
return CAIRO_STATUS_SUCCESS;
@@ -1996,7 +1870,7 @@ _cairo_glitz_surface_add_glyph (cairo_glitz_surface_t *surface,
glitz_point_fixed_t p1, p2;
glitz_pixel_format_t pf;
glitz_buffer_t *buffer;
- unsigned int bpp, am, rm, gm, bm;
+ cairo_format_masks_t masks;
cairo_int_status_t status;
glyph_private = scaled_glyph->surface_private;
@@ -2051,14 +1925,14 @@ _cairo_glitz_surface_add_glyph (cairo_glitz_surface_t *surface,
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
- cairo_format_get_masks (glyph_surface->format, &bpp, &am, &rm, &gm, &bm);
+ _pixman_format_to_masks (glyph_surface->pixman_format, &masks);
pf.fourcc = GLITZ_FOURCC_RGB;
- pf.masks.bpp = bpp;
- pf.masks.alpha_mask = am;
- pf.masks.red_mask = rm;
- pf.masks.green_mask = gm;
- pf.masks.blue_mask = bm;
+ pf.masks.bpp = masks.bpp;
+ pf.masks.alpha_mask = masks.alpha_mask;
+ pf.masks.red_mask = masks.red_mask;
+ pf.masks.green_mask = masks.green_mask;
+ pf.masks.blue_mask = masks.blue_mask;
pf.bytes_per_line = glyph_surface->stride;
pf.scanline_order = GLITZ_PIXEL_SCANLINE_ORDER_BOTTOM_UP;
@@ -2140,6 +2014,10 @@ _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
if (op == CAIRO_OPERATOR_SATURATE)
return CAIRO_INT_STATUS_UNSUPPORTED;
+ /* XXX Unbounded operators are not handled correctly */
+ if (! _cairo_operator_bounded_by_mask (op))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
if (_glitz_ensure_target (dst->surface))
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -2415,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,
@@ -2476,14 +2356,17 @@ cairo_glitz_surface_create (glitz_surface_t *surface)
format = glitz_surface_get_format (surface);
_cairo_surface_init (&crsurface->base, &cairo_glitz_surface_backend,
- _glitz_format_to_content(format));
+ _glitz_format_to_content (format));
glitz_surface_reference (surface);
crsurface->surface = surface;
crsurface->format = format;
- crsurface->has_clip = FALSE;
- return (cairo_surface_t *) crsurface;
+ crsurface->has_clip = FALSE;
+ crsurface->clip_boxes = NULL;
+ crsurface->num_clip_boxes = 0;
+
+ return &crsurface->base;
}
slim_hidden_def (cairo_glitz_surface_create);
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 75e1a63f..4cf3c87a 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -113,11 +113,11 @@ _cairo_gstate_init (cairo_gstate_t *gstate,
return _cairo_error (CAIRO_STATUS_NULL_POINTER);
status = target->status;
- if (status)
+ if (unlikely (status))
return status;
status = gstate->source->status;
- if (status)
+ if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
@@ -142,7 +142,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
status = _cairo_stroke_style_init_copy (&gstate->stroke_style,
&other->stroke_style);
- if (status)
+ if (unlikely (status))
return status;
gstate->fill_rule = other->fill_rule;
@@ -155,7 +155,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
_cairo_font_options_init_copy (&gstate->font_options , &other->font_options);
status = _cairo_clip_init_copy (&gstate->clip, &other->clip);
- if (status) {
+ if (unlikely (status)) {
_cairo_stroke_style_fini (&gstate->stroke_style);
cairo_font_face_destroy (gstate->font_face);
cairo_scaled_font_destroy (gstate->scaled_font);
@@ -221,13 +221,13 @@ _cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist)
top = *freelist;
if (top == NULL) {
top = malloc (sizeof (cairo_gstate_t));
- if (top == NULL)
+ if (unlikely (top == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} else
*freelist = top->next;
status = _cairo_gstate_init_copy (top, *gstate);
- if (status) {
+ if (unlikely (status)) {
top->next = *freelist;
*freelist = top;
return status;
@@ -297,7 +297,7 @@ _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child)
_cairo_clip_reset (&gstate->clip);
status = _cairo_clip_init_deep_copy (&gstate->clip, &gstate->next->clip, child);
- if (status)
+ if (unlikely (status))
return status;
/* The clip is in surface backend coordinates for the previous target;
@@ -512,7 +512,7 @@ _cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dash
}
gstate->stroke_style.dash = _cairo_malloc_ab (gstate->stroke_style.num_dashes, sizeof (double));
- if (gstate->stroke_style.dash == NULL) {
+ if (unlikely (gstate->stroke_style.dash == NULL)) {
gstate->stroke_style.num_dashes = 0;
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -668,7 +668,7 @@ _cairo_gstate_transform (cairo_gstate_t *gstate,
tmp = *matrix;
status = cairo_matrix_invert (&tmp);
- if (status)
+ if (unlikely (status))
return status;
_cairo_gstate_unset_scaled_font (gstate);
@@ -783,20 +783,17 @@ _cairo_gstate_stroke_to_path (cairo_gstate_t *gstate)
}
*/
-cairo_status_t
+void
_cairo_gstate_path_extents (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2)
{
- cairo_status_t status;
double px1, py1, px2, py2;
- status = _cairo_path_fixed_bounds (path,
- &px1, &py1, &px2, &py2,
- gstate->tolerance);
- if (status)
- return status;
+ _cairo_path_fixed_bounds (path,
+ &px1, &py1, &px2, &py2,
+ gstate->tolerance);
_cairo_gstate_backend_to_user_rectangle (gstate,
&px1, &py1, &px2, &py2,
@@ -809,8 +806,6 @@ _cairo_gstate_path_extents (cairo_gstate_t *gstate,
*x2 = px2;
if (y2)
*y2 = py2;
-
- return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
@@ -832,7 +827,7 @@ _cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate,
if (_cairo_surface_has_device_transform (surface)) {
status = _cairo_pattern_init_copy (*pattern, original);
- if (status)
+ if (unlikely (status))
return status;
have_copy = TRUE;
@@ -844,7 +839,7 @@ _cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate,
if (! _cairo_matrix_is_identity (ctm_inverse)) {
if (! have_copy) {
status = _cairo_pattern_init_copy (*pattern, original);
- if (status)
+ if (unlikely (status))
return status;
have_copy = TRUE;
@@ -889,17 +884,17 @@ _cairo_gstate_paint (cairo_gstate_t *gstate)
return gstate->source->status;
status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
- if (status)
+ if (unlikely (status))
return status;
pattern = &pattern_stack.base;
status = _cairo_gstate_copy_transformed_source (gstate, &pattern);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_surface_paint (gstate->target,
gstate->op,
- pattern);
+ pattern, NULL);
if (pattern == &pattern_stack.base)
_cairo_pattern_fini (pattern);
@@ -922,23 +917,23 @@ _cairo_gstate_mask (cairo_gstate_t *gstate,
return gstate->source->status;
status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
- if (status)
+ if (unlikely (status))
return status;
source_pattern = &source_pattern_stack.base;
status = _cairo_gstate_copy_transformed_source (gstate, &source_pattern);
- if (status)
+ if (unlikely (status))
return status;
mask_pattern = &mask_pattern_stack.base;
status = _cairo_gstate_copy_transformed_mask (gstate, &mask_pattern, mask);
- if (status)
+ if (unlikely (status))
goto CLEANUP_SOURCE;
status = _cairo_surface_mask (gstate->target,
gstate->op,
source_pattern,
- mask_pattern);
+ mask_pattern, NULL);
if (mask_pattern == &mask_pattern_stack.base)
_cairo_pattern_fini (&mask_pattern_stack.base);
@@ -963,13 +958,13 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
return CAIRO_STATUS_SUCCESS;
status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
- if (status)
+ if (unlikely (status))
return status;
source_pattern = &source_pattern_stack.base;
status = _cairo_gstate_copy_transformed_source (gstate,
&source_pattern);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_surface_stroke (gstate->target,
@@ -980,7 +975,7 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
&gstate->ctm,
&gstate->ctm_inverse,
gstate->tolerance,
- gstate->antialias);
+ gstate->antialias, NULL);
if (source_pattern == &source_pattern_stack.base)
_cairo_pattern_fini (&source_pattern_stack.base);
@@ -1020,7 +1015,7 @@ _cairo_gstate_in_stroke (cairo_gstate_t *gstate,
&gstate->ctm_inverse,
gstate->tolerance,
&traps);
- if (status)
+ if (unlikely (status))
goto BAIL;
*inside_ret = _cairo_traps_contain (&traps, x, y);
@@ -1042,12 +1037,12 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
return gstate->source->status;
status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
- if (status)
+ if (unlikely (status))
return status;
pattern = &pattern_stack.base;
status = _cairo_gstate_copy_transformed_source (gstate, &pattern);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_surface_fill (gstate->target,
@@ -1056,7 +1051,8 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
path,
gstate->fill_rule,
gstate->tolerance,
- gstate->antialias);
+ gstate->antialias,
+ NULL);
if (pattern == &pattern_stack.base)
_cairo_pattern_fini (&pattern_stack.base);
@@ -1064,40 +1060,20 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
return status;
}
-cairo_status_t
+void
_cairo_gstate_in_fill (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double x,
double y,
cairo_bool_t *inside_ret)
{
- cairo_status_t status;
- cairo_box_t limit;
- cairo_traps_t traps;
-
_cairo_gstate_user_to_backend (gstate, &x, &y);
- limit.p1.x = _cairo_fixed_from_double (x) - 1;
- limit.p1.y = _cairo_fixed_from_double (y) - 1;
- limit.p2.x = limit.p1.x + 2;
- limit.p2.y = limit.p1.y + 2;
-
- _cairo_traps_init (&traps);
- _cairo_traps_limit (&traps, &limit);
-
- status = _cairo_path_fixed_fill_to_traps (path,
- gstate->fill_rule,
- gstate->tolerance,
- &traps);
- if (status)
- goto BAIL;
-
- *inside_ret = _cairo_traps_contain (&traps, x, y);
-
-BAIL:
- _cairo_traps_fini (&traps);
-
- return status;
+ _cairo_path_fixed_in_fill (path,
+ gstate->fill_rule,
+ gstate->tolerance,
+ x, y,
+ inside_ret);
}
cairo_status_t
@@ -1347,7 +1323,7 @@ _cairo_gstate_int_clip_extents (cairo_gstate_t *gstate,
cairo_status_t status;
status = _cairo_surface_get_extents (gstate->target, extents);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_clip_intersect_to_rectangle (&gstate->clip, extents);
@@ -1367,7 +1343,7 @@ _cairo_gstate_clip_extents (cairo_gstate_t *gstate,
cairo_status_t status;
status = _cairo_gstate_int_clip_extents (gstate, &extents);
- if (status)
+ if (unlikely (status))
return status;
px1 = extents.x;
@@ -1486,7 +1462,7 @@ _cairo_gstate_get_font_face (cairo_gstate_t *gstate,
cairo_status_t status;
status = _cairo_gstate_ensure_font_face (gstate);
- if (status)
+ if (unlikely (status))
return status;
*font_face = gstate->font_face;
@@ -1501,7 +1477,7 @@ _cairo_gstate_get_scaled_font (cairo_gstate_t *gstate,
cairo_status_t status;
status = _cairo_gstate_ensure_scaled_font (gstate);
- if (status)
+ if (unlikely (status))
return status;
*scaled_font = gstate->scaled_font;
@@ -1617,7 +1593,7 @@ _cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate)
return gstate->scaled_font->status;
status = _cairo_gstate_ensure_font_face (gstate);
- if (status)
+ if (unlikely (status))
return status;
cairo_surface_get_font_options (gstate->target, &options);
@@ -1629,7 +1605,7 @@ _cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate)
&options);
status = cairo_scaled_font_status (scaled_font);
- if (status)
+ if (unlikely (status))
return status;
gstate->scaled_font = scaled_font;
@@ -1642,7 +1618,7 @@ _cairo_gstate_get_font_extents (cairo_gstate_t *gstate,
cairo_font_extents_t *extents)
{
cairo_status_t status = _cairo_gstate_ensure_scaled_font (gstate);
- if (status)
+ if (unlikely (status))
return status;
cairo_scaled_font_extents (gstate->scaled_font, extents);
@@ -1665,7 +1641,7 @@ _cairo_gstate_text_to_glyphs (cairo_gstate_t *gstate,
cairo_status_t status;
status = _cairo_gstate_ensure_scaled_font (gstate);
- if (status)
+ if (unlikely (status))
return status;
return cairo_scaled_font_text_to_glyphs (gstate->scaled_font, x, y,
@@ -1702,7 +1678,7 @@ _cairo_gstate_glyph_extents (cairo_gstate_t *gstate,
cairo_status_t status;
status = _cairo_gstate_ensure_scaled_font (gstate);
- if (status)
+ if (unlikely (status))
return status;
cairo_scaled_font_glyph_extents (gstate->scaled_font,
@@ -1732,18 +1708,18 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
return gstate->source->status;
status = _cairo_surface_set_clip (gstate->target, &gstate->clip);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_gstate_ensure_scaled_font (gstate);
- if (status)
+ if (unlikely (status))
return status;
if (num_glyphs <= ARRAY_LENGTH (stack_transformed_glyphs)) {
transformed_glyphs = stack_transformed_glyphs;
} else {
transformed_glyphs = cairo_glyph_allocate (num_glyphs);
- if (transformed_glyphs == NULL)
+ if (unlikely (transformed_glyphs == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -1757,7 +1733,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
source_pattern = &source_pattern_stack.base;
status = _cairo_gstate_copy_transformed_source (gstate, &source_pattern);
- if (status)
+ if (unlikely (status))
goto CLEANUP_GLYPHS;
/* Just in case */
@@ -1783,7 +1759,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
transformed_glyphs, num_glyphs,
clusters, num_clusters,
cluster_flags,
- gstate->scaled_font);
+ gstate->scaled_font, NULL);
} else {
cairo_path_fixed_t path;
@@ -1800,7 +1776,7 @@ _cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate,
&path,
CAIRO_FILL_RULE_WINDING,
gstate->tolerance,
- gstate->scaled_font->options.antialias);
+ gstate->scaled_font->options.antialias, NULL);
_cairo_path_fixed_fini (&path);
}
@@ -1826,21 +1802,22 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
status = _cairo_gstate_ensure_scaled_font (gstate);
- if (status)
+ if (unlikely (status))
return status;
- if (num_glyphs < ARRAY_LENGTH (stack_transformed_glyphs))
+ if (num_glyphs < ARRAY_LENGTH (stack_transformed_glyphs)) {
transformed_glyphs = stack_transformed_glyphs;
- else
- transformed_glyphs = cairo_glyph_allocate (num_glyphs);
- if (transformed_glyphs == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ } else {
+ transformed_glyphs = cairo_glyph_allocate (num_glyphs);
+ if (unlikely (transformed_glyphs == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
status = _cairo_gstate_transform_glyphs_to_backend (gstate,
glyphs, num_glyphs,
transformed_glyphs,
NULL);
- if (status)
+ if (unlikely (status))
goto CLEANUP_GLYPHS;
status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
diff --git a/src/cairo-hash-private.h b/src/cairo-hash-private.h
index 9101f2ed..a0be097a 100644
--- a/src/cairo-hash-private.h
+++ b/src/cairo-hash-private.h
@@ -63,10 +63,9 @@ _cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal);
cairo_private void
_cairo_hash_table_destroy (cairo_hash_table_t *hash_table);
-cairo_private cairo_bool_t
+cairo_private void *
_cairo_hash_table_lookup (cairo_hash_table_t *hash_table,
- cairo_hash_entry_t *key,
- cairo_hash_entry_t **entry_return);
+ cairo_hash_entry_t *key);
cairo_private void *
_cairo_hash_table_random_entry (cairo_hash_table_t *hash_table,
@@ -81,7 +80,7 @@ _cairo_hash_table_remove (cairo_hash_table_t *hash_table,
cairo_hash_entry_t *key);
cairo_private void
-_cairo_hash_table_foreach (cairo_hash_table_t *hash_table,
+_cairo_hash_table_foreach (cairo_hash_table_t *hash_table,
cairo_hash_callback_func_t hash_callback,
void *closure);
diff --git a/src/cairo-hash.c b/src/cairo-hash.c
index 2317eb17..973281d4 100644
--- a/src/cairo-hash.c
+++ b/src/cairo-hash.c
@@ -52,12 +52,11 @@
* Appears in the table as any non-%NULL, non-DEAD_ENTRY pointer.
*/
-static cairo_hash_entry_t dead_entry = { 0 };
-#define DEAD_ENTRY (&dead_entry)
+#define DEAD_ENTRY ((cairo_hash_entry_t *) 0x1)
#define ENTRY_IS_FREE(entry) ((entry) == NULL)
#define ENTRY_IS_DEAD(entry) ((entry) == DEAD_ENTRY)
-#define ENTRY_IS_LIVE(entry) ((entry) && ! ENTRY_IS_DEAD(entry))
+#define ENTRY_IS_LIVE(entry) ((entry) > DEAD_ENTRY)
/* We expect keys will not be destroyed frequently, so our table does not
* contain any explicit shrinking code nor any chain-coalescing code for
@@ -109,7 +108,7 @@ static const cairo_hash_table_arrangement_t hash_table_arrangements [] = {
{ 4194304, 9227641, 9227639 },
{ 8388608, 18455029, 18455027 },
{ 16777216, 36911011, 36911009 },
- { 33554432, 73819861, 73819859 },
+ { 33554432, 73819861, 73819859 },
{ 67108864, 147639589, 147639587 },
{ 134217728, 295279081, 295279079 },
{ 268435456, 590559793, 590559791 }
@@ -149,7 +148,7 @@ _cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal)
cairo_hash_table_t *hash_table;
hash_table = malloc (sizeof (cairo_hash_table_t));
- if (hash_table == NULL) {
+ if (unlikely (hash_table == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
@@ -160,7 +159,7 @@ _cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal)
hash_table->entries = calloc (hash_table->arrangement->size,
sizeof(cairo_hash_entry_t *));
- if (hash_table->entries == NULL) {
+ if (unlikely (hash_table->entries == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
free (hash_table);
return NULL;
@@ -206,85 +205,36 @@ _cairo_hash_table_destroy (cairo_hash_table_t *hash_table)
free (hash_table);
}
-/**
- * _cairo_hash_table_lookup_internal:
- *
- * @hash_table: a #cairo_hash_table_t to search
- * @key: the key to search on
- * @hash_code: the hash_code for @key
- * @key_unique: If %TRUE, then caller asserts that no key already
- * exists that will compare equal to #key, so search can be
- * optimized. If unsure, set to %FALSE and the code will always work.
- *
- * Search the hashtable for a live entry for which
- * hash_table->keys_equal returns true. If no such entry exists then
- * return the first available (free or dead entry).
- *
- * If the key_unique flag is set, then the search will never call
- * hash_table->keys_equal and will act as if it always returned
- * false. This is useful as a performance optimization in special
- * circumstances where the caller knows that there is no existing
- * entry in the hash table with a matching key.
- *
- * Return value: The matching entry in the hash table (if
- * any). Otherwise, the first available entry. The caller should check
- * entry->state to check whether a match was found or not.
- **/
static cairo_hash_entry_t **
-_cairo_hash_table_lookup_internal (cairo_hash_table_t *hash_table,
- cairo_hash_entry_t *key,
- cairo_bool_t key_is_unique)
+_cairo_hash_table_lookup_unique_key (cairo_hash_table_t *hash_table,
+ cairo_hash_entry_t *key)
{
- cairo_hash_entry_t **entry, **first_available = NULL;
unsigned long table_size, i, idx, step;
+ cairo_hash_entry_t **entry;
table_size = hash_table->arrangement->size;
-
idx = key->hash % table_size;
- step = 0;
-
- for (i = 0; i < table_size; ++i)
- {
- entry = &hash_table->entries[idx];
- if (ENTRY_IS_FREE(*entry))
- {
- return entry;
- }
- else if (ENTRY_IS_DEAD(*entry))
- {
- if (key_is_unique) {
- return entry;
- } else {
- if (! first_available)
- first_available = entry;
- }
- }
- else /* ENTRY_IS_LIVE(*entry) */
- {
- if (! key_is_unique)
- if (hash_table->keys_equal (key, *entry))
- return entry;
- }
-
- if (step == 0) {
- step = key->hash % hash_table->arrangement->rehash;
- if (step == 0)
- step = 1;
- }
+ entry = &hash_table->entries[idx];
+ if (! ENTRY_IS_LIVE (*entry))
+ return entry;
+ i = 1;
+ step = key->hash % hash_table->arrangement->rehash;
+ if (step == 0)
+ step = 1;
+ do {
idx += step;
if (idx >= table_size)
idx -= table_size;
- }
- /*
- * The table should not have permitted you to get here if you were just
- * looking for a free slot: there should have been room.
- */
- assert (key_is_unique == 0);
+ entry = &hash_table->entries[idx];
+ if (! ENTRY_IS_LIVE (*entry))
+ return entry;
+ } while (++i < table_size);
- return first_available;
+ ASSERT_NOT_REACHED;
+ return NULL;
}
/**
@@ -299,10 +249,9 @@ _cairo_hash_table_lookup_internal (cairo_hash_table_t *hash_table,
* %CAIRO_STATUS_NO_MEMORY if out of memory.
**/
static cairo_status_t
-_cairo_hash_table_resize (cairo_hash_table_t *hash_table)
+_cairo_hash_table_resize (cairo_hash_table_t *hash_table)
{
cairo_hash_table_t tmp;
- cairo_hash_entry_t **entry;
unsigned long new_size, i;
/* This keeps the hash table between 25% and 50% full. */
@@ -331,16 +280,13 @@ _cairo_hash_table_resize (cairo_hash_table_t *hash_table)
new_size = tmp.arrangement->size;
tmp.entries = calloc (new_size, sizeof (cairo_hash_entry_t*));
- if (tmp.entries == NULL)
+ if (unlikely (tmp.entries == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
for (i = 0; i < hash_table->arrangement->size; ++i) {
if (ENTRY_IS_LIVE (hash_table->entries[i])) {
- entry = _cairo_hash_table_lookup_internal (&tmp,
- hash_table->entries[i],
- TRUE);
- assert (ENTRY_IS_FREE(*entry));
- *entry = hash_table->entries[i];
+ *_cairo_hash_table_lookup_unique_key (&tmp, hash_table->entries[i])
+ = hash_table->entries[i];
}
}
@@ -355,32 +301,48 @@ _cairo_hash_table_resize (cairo_hash_table_t *hash_table)
* _cairo_hash_table_lookup:
* @hash_table: a hash table
* @key: the key of interest
- * @entry_return: pointer for return value.
*
* Performs a lookup in @hash_table looking for an entry which has a
* key that matches @key, (as determined by the keys_equal() function
* passed to _cairo_hash_table_create).
*
- * Return value: %TRUE if there is an entry in the hash table that
- * matches the given key, (which will now be in *entry_return). %FALSE
- * otherwise, (in which case *entry_return will be %NULL).
+ * Return value: the matching entry, of %NULL if no match was found.
**/
-cairo_bool_t
+void *
_cairo_hash_table_lookup (cairo_hash_table_t *hash_table,
- cairo_hash_entry_t *key,
- cairo_hash_entry_t **entry_return)
+ cairo_hash_entry_t *key)
{
cairo_hash_entry_t **entry;
+ unsigned long table_size, i, idx, step;
- /* See if we have an entry in the table already. */
- entry = _cairo_hash_table_lookup_internal (hash_table, key, FALSE);
- if (ENTRY_IS_LIVE(*entry)) {
- *entry_return = *entry;
- return TRUE;
- }
+ table_size = hash_table->arrangement->size;
+ idx = key->hash % table_size;
+ entry = &hash_table->entries[idx];
+
+ if (ENTRY_IS_LIVE (*entry)) {
+ if (hash_table->keys_equal (key, *entry))
+ return *entry;
+ } else if (ENTRY_IS_FREE (*entry))
+ return NULL;
- *entry_return = NULL;
- return FALSE;
+ i = 1;
+ step = key->hash % hash_table->arrangement->rehash;
+ if (step == 0)
+ step = 1;
+ do {
+ idx += step;
+ if (idx >= table_size)
+ idx -= table_size;
+
+ entry = &hash_table->entries[idx];
+ if (ENTRY_IS_LIVE (*entry)) {
+ if (hash_table->keys_equal (key, *entry))
+ return *entry;
+ } else if (ENTRY_IS_FREE (*entry))
+ return NULL;
+ } while (++i < table_size);
+
+ return NULL;
}
/**
@@ -448,8 +410,8 @@ _cairo_hash_table_random_entry (cairo_hash_table_t *hash_table,
*
* Insert the entry #key_and_value into the hash table.
*
- * WARNING: It is a fatal error if an entry exists in the hash table
- * with a matching key, (this function will halt).
+ * WARNING: There must not be an existing entry in the hash table
+ * with a matching key.
*
* WARNING: It is a fatal error to insert an element while
* an iterator is running
@@ -466,42 +428,61 @@ _cairo_hash_table_insert (cairo_hash_table_t *hash_table,
cairo_hash_entry_t *key_and_value)
{
cairo_status_t status;
- cairo_hash_entry_t **entry;
/* Insert is illegal while an iterator is running. */
assert (hash_table->iterating == 0);
- entry = _cairo_hash_table_lookup_internal (hash_table,
- key_and_value, FALSE);
-
- if (ENTRY_IS_LIVE(*entry))
- {
- /* User is being bad, let's crash. */
- ASSERT_NOT_REACHED;
- }
-
- *entry = key_and_value;
hash_table->live_entries++;
-
status = _cairo_hash_table_resize (hash_table);
- if (status) {
+ if (unlikely (status)) {
/* abort the insert... */
- *entry = DEAD_ENTRY;
hash_table->live_entries--;
return status;
}
+ *_cairo_hash_table_lookup_unique_key (hash_table,
+ key_and_value) = key_and_value;
+
return CAIRO_STATUS_SUCCESS;
}
+static cairo_hash_entry_t **
+_cairo_hash_table_lookup_exact_key (cairo_hash_table_t *hash_table,
+ cairo_hash_entry_t *key)
+{
+ unsigned long table_size, i, idx, step;
+ cairo_hash_entry_t **entry;
+
+ table_size = hash_table->arrangement->size;
+ idx = key->hash % table_size;
+
+ entry = &hash_table->entries[idx];
+ if (*entry == key)
+ return entry;
+
+ i = 1;
+ step = key->hash % hash_table->arrangement->rehash;
+ if (step == 0)
+ step = 1;
+ do {
+ idx += step;
+ if (idx >= table_size)
+ idx -= table_size;
+
+ entry = &hash_table->entries[idx];
+ if (*entry == key)
+ return entry;
+ } while (++i < table_size);
+
+ ASSERT_NOT_REACHED;
+ return NULL;
+}
/**
* _cairo_hash_table_remove:
* @hash_table: a hash table
* @key: key of entry to be removed
*
- * Remove an entry from the hash table which has a key that matches
- * @key, if any (as determined by the keys_equal() function passed to
- * _cairo_hash_table_create).
+ * Remove an entry from the hash table which points to @key.
*
* Return value: %CAIRO_STATUS_SUCCESS if successful or
* %CAIRO_STATUS_NO_MEMORY if out of memory.
@@ -510,13 +491,7 @@ void
_cairo_hash_table_remove (cairo_hash_table_t *hash_table,
cairo_hash_entry_t *key)
{
- cairo_hash_entry_t **entry;
-
- entry = _cairo_hash_table_lookup_internal (hash_table, key, FALSE);
- if (! ENTRY_IS_LIVE(*entry))
- return;
-
- *entry = DEAD_ENTRY;
+ *_cairo_hash_table_lookup_exact_key (hash_table, key) = DEAD_ENTRY;
hash_table->live_entries--;
/* Check for table resize. Don't do this when iterating as this will
diff --git a/src/cairo-hull.c b/src/cairo-hull.c
index 008ba7fd..a699a524 100644
--- a/src/cairo-hull.c
+++ b/src/cairo-hull.c
@@ -200,7 +200,7 @@ _cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices)
if (num_hull > ARRAY_LENGTH (hull_stack)) {
hull = _cairo_malloc_ab (num_hull, sizeof (cairo_hull_t));
- if (hull == NULL)
+ if (unlikely (hull == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} else {
hull = hull_stack;
diff --git a/src/cairo-image-info-private.h b/src/cairo-image-info-private.h
new file mode 100644
index 00000000..6e1c4ad7
--- /dev/null
+++ b/src/cairo-image-info-private.h
@@ -0,0 +1,63 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2008 Adrian Johnson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Adrian Johnson.
+ *
+ * Contributor(s):
+ * Adrian Johnson <ajohnson@redneon.com>
+ */
+
+#ifndef CAIRO_IMAGE_INFO_PRIVATE_H
+#define CAIRO_IMAGE_INFO_PRIVATE_H
+
+#include "cairoint.h"
+
+typedef struct _cairo_image_info {
+ int width;
+ int height;
+ int num_components;
+ int bits_per_component;
+} cairo_image_info_t;
+
+cairo_private cairo_int_status_t
+_cairo_image_info_get_jpeg_info (cairo_image_info_t *info,
+ const unsigned char *data,
+ long length);
+
+cairo_private cairo_int_status_t
+_cairo_image_info_get_jpx_info (cairo_image_info_t *info,
+ const unsigned char *data,
+ long length);
+
+cairo_private cairo_int_status_t
+_cairo_image_info_get_png_info (cairo_image_info_t *info,
+ const unsigned char *data,
+ long length);
+
+#endif /* CAIRO_IMAGE_INFO_PRIVATE_H */
diff --git a/src/cairo-image-info.c b/src/cairo-image-info.c
new file mode 100644
index 00000000..8fc77055
--- /dev/null
+++ b/src/cairo-image-info.c
@@ -0,0 +1,290 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2008 Adrian Johnson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Adrian Johnson.
+ *
+ * Contributor(s):
+ * Adrian Johnson <ajohnson@redneon.com>
+ */
+
+#include "cairoint.h"
+#include "cairo-image-info-private.h"
+
+static uint32_t
+_get_be32 (const unsigned char *p)
+{
+ return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
+}
+
+/* JPEG (image/jpeg)
+ *
+ * http://www.w3.org/Graphics/JPEG/itu-t81.pdf
+ */
+
+/* Markers with no parameters. All other markers are followed by a two
+ * byte length of the parameters. */
+#define TEM 0x01
+#define RST_begin 0xd0
+#define RST_end 0xd7
+#define SOI 0xd8
+#define EOI 0xd9
+
+/* Start of frame markers. */
+#define SOF0 0xc0
+#define SOF1 0xc1
+#define SOF2 0xc2
+#define SOF3 0xc3
+#define SOF5 0xc5
+#define SOF6 0xc6
+#define SOF7 0xc7
+#define SOF9 0xc9
+#define SOF10 0xca
+#define SOF11 0xcb
+#define SOF13 0xcd
+#define SOF14 0xce
+#define SOF15 0xcf
+
+static const unsigned char *
+_jpeg_skip_segment (const unsigned char *p)
+{
+ int len;
+
+ p++;
+ len = (p[0] << 8) | p[1];
+
+ return p + len;
+}
+
+static void
+_jpeg_extract_info (cairo_image_info_t *info, const unsigned char *p)
+{
+ info->width = (p[6] << 8) + p[7];
+ info->height = (p[4] << 8) + p[5];
+ info->num_components = p[8];
+ info->bits_per_component = p[3];
+}
+
+cairo_int_status_t
+_cairo_image_info_get_jpeg_info (cairo_image_info_t *info,
+ const unsigned char *data,
+ long length)
+{
+ const unsigned char *p = data;
+
+ while (p + 1 < data + length) {
+ if (*p != 0xff)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ p++;
+
+ switch (*p) {
+ /* skip fill bytes */
+ case 0xff:
+ p++;
+ break;
+
+ case TEM:
+ case SOI:
+ case EOI:
+ p++;
+ break;
+
+ case SOF0:
+ case SOF1:
+ case SOF2:
+ case SOF3:
+ case SOF5:
+ case SOF6:
+ case SOF7:
+ case SOF9:
+ case SOF10:
+ case SOF11:
+ case SOF13:
+ case SOF14:
+ case SOF15:
+ /* Start of frame found. Extract the image parameters. */
+ if (p + 8 > data + length)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ _jpeg_extract_info (info, p);
+ return CAIRO_STATUS_SUCCESS;
+
+ default:
+ if (*p >= RST_begin && *p <= RST_end) {
+ p++;
+ break;
+ }
+
+ if (p + 2 > data + length)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ p = _jpeg_skip_segment (p);
+ break;
+ }
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* JPEG 2000 (image/jp2)
+ *
+ * http://www.jpeg.org/public/15444-1annexi.pdf
+ */
+
+#define JPX_FILETYPE 0x66747970
+#define JPX_JP2_HEADER 0x6A703268
+#define JPX_IMAGE_HEADER 0x69686472
+
+static const unsigned char _jpx_signature[] = {
+ 0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a
+};
+
+static const unsigned char *
+_jpx_next_box (const unsigned char *p)
+{
+ return p + _get_be32 (p);
+}
+
+static const unsigned char *
+_jpx_get_box_contents (const unsigned char *p)
+{
+ return p + 8;
+}
+
+static cairo_bool_t
+_jpx_match_box (const unsigned char *p, const unsigned char *end, uint32_t type)
+{
+ uint32_t length;
+
+ if (p + 8 < end) {
+ length = _get_be32 (p);
+ if (_get_be32 (p + 4) == type && p + length < end)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static const unsigned char *
+_jpx_find_box (const unsigned char *p, const unsigned char *end, uint32_t type)
+{
+ while (p < end) {
+ if (_jpx_match_box (p, end, type))
+ return p;
+ p = _jpx_next_box (p);
+ }
+
+ return NULL;
+}
+
+static void
+_jpx_extract_info (const unsigned char *p, cairo_image_info_t *info)
+{
+ info->height = _get_be32 (p);
+ info->width = _get_be32 (p + 4);
+ info->num_components = (p[8] << 8) + p[9];
+ info->bits_per_component = p[10];
+}
+
+cairo_int_status_t
+_cairo_image_info_get_jpx_info (cairo_image_info_t *info,
+ const unsigned char *data,
+ long length)
+{
+ const unsigned char *p = data;
+ const unsigned char *end = data + length;
+
+ /* First 12 bytes must be the JPEG 2000 signature box. */
+ if (length < ARRAY_LENGTH(_jpx_signature) ||
+ memcmp(p, _jpx_signature, ARRAY_LENGTH(_jpx_signature)) != 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ p += ARRAY_LENGTH(_jpx_signature);
+
+ /* Next box must be a File Type Box */
+ if (! _jpx_match_box (p, end, JPX_FILETYPE))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ p = _jpx_next_box (p);
+
+ /* Locate the JP2 header box. */
+ p = _jpx_find_box (p, end, JPX_JP2_HEADER);
+ if (!p)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* Step into the JP2 header box. First box must be the Image
+ * Header */
+ p = _jpx_get_box_contents (p);
+ if (! _jpx_match_box (p, end, JPX_IMAGE_HEADER))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* Get the image info */
+ p = _jpx_get_box_contents (p);
+ _jpx_extract_info (p, info);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* PNG (image/png)
+ *
+ * http://www.w3.org/TR/2003/REC-PNG-20031110/
+ */
+
+#define PNG_IHDR 0x49484452
+
+static const unsigned char _png_magic[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
+
+cairo_int_status_t
+_cairo_image_info_get_png_info (cairo_image_info_t *info,
+ const unsigned char *data,
+ long length)
+{
+ const unsigned char *p = data;
+ const unsigned char *end = data + length;
+
+ if (length < 8 || memcmp (data, _png_magic, 8) != 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ p += 8;
+
+ /* The first chunk must be IDHR. IDHR has 13 bytes of data plus
+ * the 12 bytes of overhead for the chunk. */
+ if (p + 13 + 12 > end)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ p += 4;
+ if (_get_be32 (p) != PNG_IHDR)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ p += 4;
+ info->width = _get_be32 (p);
+ p += 4;
+ info->height = _get_be32 (p);
+
+ return CAIRO_STATUS_SUCCESS;
+}
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 12614c1a..f484466a 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -131,7 +131,7 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
cairo_image_surface_t *surface;
surface = malloc (sizeof (cairo_image_surface_t));
- if (surface == NULL)
+ if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_surface_init (&surface->base, &_cairo_image_surface_backend,
@@ -203,7 +203,7 @@ _pixman_format_from_masks (cairo_format_masks_t *masks,
}
/* A mask consisting of N bits set to 1. */
-#define MASK(N) ((1 << (N))-1)
+#define MASK(N) ((1UL << (N))-1)
void
_pixman_format_to_masks (pixman_format_code_t format,
@@ -327,7 +327,7 @@ _cairo_image_surface_create_with_pixman_format (unsigned char *data,
pixman_image = pixman_image_create_bits (pixman_format, width, height,
(uint32_t *) data, stride);
- if (pixman_image == NULL)
+ if (unlikely (pixman_image == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
surface = _cairo_image_surface_create_for_pixman_image (pixman_image,
@@ -731,7 +731,7 @@ _cairo_image_surface_finish (void *abstract_surface)
void
_cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface)
{
- surface->owns_data = 1;
+ surface->owns_data = TRUE;
}
static cairo_status_t
@@ -806,11 +806,12 @@ _cairo_image_surface_clone_similar (void *abstract_surface,
static cairo_status_t
_cairo_image_surface_set_matrix (cairo_image_surface_t *surface,
- const cairo_matrix_t *matrix)
+ const cairo_matrix_t *matrix,
+ double xc, double yc)
{
pixman_transform_t pixman_transform;
- _cairo_matrix_to_pixman_matrix (matrix, &pixman_transform);
+ _cairo_matrix_to_pixman_matrix (matrix, &pixman_transform, xc, yc);
if (! pixman_image_set_transform (surface->pixman_image, &pixman_transform))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -862,12 +863,14 @@ _cairo_image_surface_set_filter (cairo_image_surface_t *surface,
static cairo_status_t
_cairo_image_surface_set_attributes (cairo_image_surface_t *surface,
- cairo_surface_attributes_t *attributes)
+ cairo_surface_attributes_t *attributes,
+ double xc, double yc)
{
cairo_int_status_t status;
- status = _cairo_image_surface_set_matrix (surface, &attributes->matrix);
- if (status)
+ status = _cairo_image_surface_set_matrix (surface, &attributes->matrix,
+ xc, yc);
+ if (unlikely (status))
return status;
switch (attributes->extend) {
@@ -886,7 +889,7 @@ _cairo_image_surface_set_attributes (cairo_image_surface_t *surface,
}
status = _cairo_image_surface_set_filter (surface, attributes->filter);
- if (status)
+ if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
@@ -965,17 +968,21 @@ _cairo_image_surface_composite (cairo_operator_t op,
(cairo_surface_t **) &src,
(cairo_surface_t **) &mask,
&src_attr, &mask_attr);
- if (status)
+ if (unlikely (status))
return status;
- status = _cairo_image_surface_set_attributes (src, &src_attr);
- if (status)
- goto CLEANUP_SURFACES;
+ status = _cairo_image_surface_set_attributes (src, &src_attr,
+ dst_x + width / 2.,
+ dst_y + height / 2.);
+ if (unlikely (status))
+ goto CLEANUP_SURFACES;
if (mask)
{
- status = _cairo_image_surface_set_attributes (mask, &mask_attr);
- if (status)
+ status = _cairo_image_surface_set_attributes (mask, &mask_attr,
+ dst_x + width / 2.,
+ dst_y + height / 2.);
+ if (unlikely (status))
goto CLEANUP_SURFACES;
pixman_image_composite (_pixman_operator (op),
@@ -1044,7 +1051,7 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
if (num_rects > ARRAY_LENGTH (stack_rects)) {
pixman_rects = _cairo_malloc_ab (num_rects, sizeof (pixman_rectangle16_t));
- if (pixman_rects == NULL)
+ if (unlikely (pixman_rects == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -1057,10 +1064,11 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
/* XXX: pixman_fill_rectangles() should be implemented */
if (! pixman_image_fill_rectangles (_pixman_operator (op),
- surface->pixman_image,
- &pixman_color,
- num_rects,
- pixman_rects)) {
+ surface->pixman_image,
+ &pixman_color,
+ num_rects,
+ pixman_rects))
+ {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -1070,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,
@@ -1087,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)
@@ -1102,7 +1116,7 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op,
/* Convert traps to pixman traps */
if (num_traps > ARRAY_LENGTH (stack_traps)) {
pixman_traps = _cairo_malloc_ab (num_traps, sizeof (pixman_trapezoid_t));
- if (pixman_traps == NULL)
+ if (unlikely (pixman_traps == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -1148,47 +1162,28 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op,
src_x, src_y, width, height,
(cairo_surface_t **) &src,
&attributes);
- if (status)
+ if (unlikely (status))
goto finish;
- status = _cairo_image_surface_set_attributes (src, &attributes);
- if (status)
+ status = _cairo_image_surface_set_attributes (src, &attributes,
+ dst_x + width / 2.,
+ dst_y + height / 2.);
+ 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 (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 (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,
@@ -1198,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);
@@ -1218,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)
@@ -1293,6 +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,
+ _cairo_image_surface_create_span_renderer,
+ _cairo_image_surface_check_span_renderer,
NULL, /* copy_page */
NULL, /* show_page */
_cairo_image_surface_set_clip_region,
@@ -1343,7 +1548,7 @@ _cairo_image_surface_clone (cairo_image_surface_t *surface,
status = cairo_status (cr);
cairo_destroy (cr);
- if (status) {
+ if (unlikely (status)) {
cairo_surface_destroy (&clone->base);
return (cairo_image_surface_t *) _cairo_surface_create_in_error (status);
}
diff --git a/src/cairo-lzw.c b/src/cairo-lzw.c
index 1241225d..a4fdf738 100644
--- a/src/cairo-lzw.c
+++ b/src/cairo-lzw.c
@@ -73,7 +73,7 @@ _lzw_buf_init (lzw_buf_t *buf, int size)
buf->pending_bits = 0;
buf->data = malloc (size);
- if (buf->data == NULL) {
+ if (unlikely (buf->data == NULL)) {
buf->data_size = 0;
buf->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return;
@@ -98,7 +98,7 @@ _lzw_buf_grow (lzw_buf_t *buf)
if (new_size / 2 == buf->data_size)
new_data = realloc (buf->data, new_size);
- if (new_data == NULL) {
+ if (unlikely (new_data == NULL)) {
free (buf->data);
buf->data_size = 0;
buf->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -137,7 +137,7 @@ _lzw_buf_store_bits (lzw_buf_t *buf, uint16_t value, int num_bits)
while (buf->pending_bits >= 8) {
if (buf->num_data >= buf->data_size) {
status = _lzw_buf_grow (buf);
- if (status)
+ if (unlikely (status))
return;
}
buf->data[buf->num_data++] = buf->pending >> (buf->pending_bits - 8);
@@ -167,7 +167,7 @@ _lzw_buf_store_pending (lzw_buf_t *buf)
if (buf->num_data >= buf->data_size) {
status = _lzw_buf_grow (buf);
- if (status)
+ if (unlikely (status))
return;
}
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index b644dec8..6dfe537f 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -865,7 +865,9 @@ _cairo_matrix_transformed_circle_major_axis (cairo_matrix_t *matrix, double radi
void
_cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix,
- pixman_transform_t *pixman_transform)
+ pixman_transform_t *pixman_transform,
+ double xc,
+ double yc)
{
static const pixman_transform_t pixman_identity_transform = {{
{1 << 16, 0, 0},
@@ -875,11 +877,9 @@ _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix,
if (_cairo_matrix_is_identity (matrix)) {
*pixman_transform = pixman_identity_transform;
- }
- else {
+ } else {
cairo_matrix_t inv;
- double x,y;
- pixman_vector_t vector;
+ unsigned max_iterations;
pixman_transform->matrix[0][0] = _cairo_fixed_16_16_from_double (matrix->xx);
pixman_transform->matrix[0][1] = _cairo_fixed_16_16_from_double (matrix->xy);
@@ -899,9 +899,10 @@ _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix,
* for cairo, while pixman uses rounded versions of xx ... yy.
* This error increases as a and b get larger.
*
- * To compensate for this, we fix the point (0, 0) in pattern
+ * To compensate for this, we fix the point (xc, yc) in pattern
* space and adjust pixman's transform to agree with cairo's at
- * that point. */
+ * that point.
+ */
if (_cairo_matrix_is_translation (matrix))
return;
@@ -911,22 +912,38 @@ _cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix,
if (cairo_matrix_invert (&inv) != CAIRO_STATUS_SUCCESS)
return;
- /* find the device space coordinate that maps to (0, 0) */
- x = 0, y = 0;
- cairo_matrix_transform_point (&inv, &x, &y);
-
- /* transform the resulting device space coordinate back
- * to the pattern space, using pixman's transform */
- vector.vector[0] = _cairo_fixed_16_16_from_double (x);
- vector.vector[1] = _cairo_fixed_16_16_from_double (y);
- vector.vector[2] = 1 << 16;
-
- if (! pixman_transform_point_3d (pixman_transform, &vector))
- return;
-
- /* Ideally, the vector should now be (0, 0). We can now compensate
- * for the resulting error */
- pixman_transform->matrix[0][2] -= vector.vector[0];
- pixman_transform->matrix[1][2] -= vector.vector[1];
+ /* find the pattern space coordinate that maps to (xc, yc) */
+ xc += .5; yc += .5; /* offset for the pixel centre */
+ max_iterations = 5;
+ do {
+ double x,y;
+ pixman_vector_t vector;
+ cairo_fixed_16_16_t dx, dy;
+
+ vector.vector[0] = _cairo_fixed_16_16_from_double (xc);
+ vector.vector[1] = _cairo_fixed_16_16_from_double (yc);
+ vector.vector[2] = 1 << 16;
+
+ if (! pixman_transform_point_3d (pixman_transform, &vector))
+ return;
+
+ x = pixman_fixed_to_double (vector.vector[0]);
+ y = pixman_fixed_to_double (vector.vector[1]);
+ cairo_matrix_transform_point (&inv, &x, &y);
+
+ /* Ideally, the vector should now be (xc, yc).
+ * We can now compensate for the resulting error.
+ */
+ x -= xc;
+ y -= yc;
+ cairo_matrix_transform_distance (matrix, &x, &y);
+ dx = _cairo_fixed_16_16_from_double (x);
+ dy = _cairo_fixed_16_16_from_double (y);
+ pixman_transform->matrix[0][2] -= dx;
+ pixman_transform->matrix[1][2] -= dy;
+
+ if (dx == 0 && dy == 0)
+ break;
+ } while (--max_iterations);
}
}
diff --git a/src/cairo-meta-surface-private.h b/src/cairo-meta-surface-private.h
index 9a1b169c..8d5e096e 100644
--- a/src/cairo-meta-surface-private.h
+++ b/src/cairo-meta-surface-private.h
@@ -67,6 +67,7 @@ typedef enum {
typedef struct _cairo_command_header {
cairo_command_type_t type;
cairo_meta_region_type_t region;
+ cairo_rectangle_int_t extents;
} cairo_command_header_t;
typedef struct _cairo_command_paint {
diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c
index faf48558..0f6e6324 100644
--- a/src/cairo-meta-surface.c
+++ b/src/cairo-meta-surface.c
@@ -84,7 +84,7 @@ _cairo_meta_surface_create (cairo_content_t content,
cairo_meta_surface_t *meta;
meta = malloc (sizeof (cairo_meta_surface_t));
- if (meta == NULL)
+ if (unlikely (meta == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_surface_init (&meta->base, &cairo_meta_surface_backend,
@@ -197,7 +197,7 @@ _cairo_meta_surface_acquire_source_image (void *abstract_surface,
surface->height_pixels);
status = _cairo_meta_surface_replay (&surface->base, image);
- if (status) {
+ if (unlikely (status)) {
cairo_surface_destroy (image);
return status;
}
@@ -219,26 +219,31 @@ _cairo_meta_surface_release_source_image (void *abstract_surface,
static cairo_int_status_t
_cairo_meta_surface_paint (void *abstract_surface,
cairo_operator_t op,
- const cairo_pattern_t *source)
+ const cairo_pattern_t *source,
+ cairo_rectangle_int_t *extents)
{
cairo_status_t status;
cairo_meta_surface_t *meta = abstract_surface;
cairo_command_paint_t *command;
command = malloc (sizeof (cairo_command_paint_t));
- if (command == NULL)
+ if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
command->header.type = CAIRO_COMMAND_PAINT;
command->header.region = CAIRO_META_REGION_ALL;
+ command->header.extents.x = 0;
+ command->header.extents.y = 0;
+ command->header.extents.width = meta->width_pixels;
+ command->header.extents.height = meta->height_pixels;
command->op = op;
status = _cairo_pattern_init_snapshot (&command->source.base, source);
- if (status)
+ if (unlikely (status))
goto CLEANUP_COMMAND;
status = _cairo_array_append (&meta->commands, &command);
- if (status)
+ if (unlikely (status))
goto CLEANUP_SOURCE;
/* An optimisation that takes care to not replay what was done
@@ -260,30 +265,35 @@ static cairo_int_status_t
_cairo_meta_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- const cairo_pattern_t *mask)
+ const cairo_pattern_t *mask,
+ cairo_rectangle_int_t *extents)
{
cairo_status_t status;
cairo_meta_surface_t *meta = abstract_surface;
cairo_command_mask_t *command;
command = malloc (sizeof (cairo_command_mask_t));
- if (command == NULL)
+ if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
command->header.type = CAIRO_COMMAND_MASK;
command->header.region = CAIRO_META_REGION_ALL;
+ command->header.extents.x = 0;
+ command->header.extents.y = 0;
+ command->header.extents.width = meta->width_pixels;
+ command->header.extents.height = meta->height_pixels;
command->op = op;
status = _cairo_pattern_init_snapshot (&command->source.base, source);
- if (status)
+ if (unlikely (status))
goto CLEANUP_COMMAND;
status = _cairo_pattern_init_snapshot (&command->mask.base, mask);
- if (status)
+ if (unlikely (status))
goto CLEANUP_SOURCE;
status = _cairo_array_append (&meta->commands, &command);
- if (status)
+ if (unlikely (status))
goto CLEANUP_MASK;
return CAIRO_STATUS_SUCCESS;
@@ -306,30 +316,35 @@ _cairo_meta_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
cairo_status_t status;
cairo_meta_surface_t *meta = abstract_surface;
cairo_command_stroke_t *command;
command = malloc (sizeof (cairo_command_stroke_t));
- if (command == NULL)
+ if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
command->header.type = CAIRO_COMMAND_STROKE;
command->header.region = CAIRO_META_REGION_ALL;
+ command->header.extents.x = 0;
+ command->header.extents.y = 0;
+ command->header.extents.width = meta->width_pixels;
+ command->header.extents.height = meta->height_pixels;
command->op = op;
status = _cairo_pattern_init_snapshot (&command->source.base, source);
- if (status)
+ if (unlikely (status))
goto CLEANUP_COMMAND;
status = _cairo_path_fixed_init_copy (&command->path, path);
- if (status)
+ if (unlikely (status))
goto CLEANUP_SOURCE;
status = _cairo_stroke_style_init_copy (&command->style, style);
- if (status)
+ if (unlikely (status))
goto CLEANUP_PATH;
command->ctm = *ctm;
@@ -338,7 +353,7 @@ _cairo_meta_surface_stroke (void *abstract_surface,
command->antialias = antialias;
status = _cairo_array_append (&meta->commands, &command);
- if (status)
+ if (unlikely (status))
goto CLEANUP_STYLE;
return CAIRO_STATUS_SUCCESS;
@@ -361,26 +376,31 @@ _cairo_meta_surface_fill (void *abstract_surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
cairo_status_t status;
cairo_meta_surface_t *meta = abstract_surface;
cairo_command_fill_t *command;
command = malloc (sizeof (cairo_command_fill_t));
- if (command == NULL)
+ if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
command->header.type = CAIRO_COMMAND_FILL;
command->header.region = CAIRO_META_REGION_ALL;
+ command->header.extents.x = 0;
+ command->header.extents.y = 0;
+ command->header.extents.width = meta->width_pixels;
+ command->header.extents.height = meta->height_pixels;
command->op = op;
status = _cairo_pattern_init_snapshot (&command->source.base, source);
- if (status)
+ if (unlikely (status))
goto CLEANUP_COMMAND;
status = _cairo_path_fixed_init_copy (&command->path, path);
- if (status)
+ if (unlikely (status))
goto CLEANUP_SOURCE;
command->fill_rule = fill_rule;
@@ -388,7 +408,7 @@ _cairo_meta_surface_fill (void *abstract_surface,
command->antialias = antialias;
status = _cairo_array_append (&meta->commands, &command);
- if (status)
+ if (unlikely (status))
goto CLEANUP_PATH;
return CAIRO_STATUS_SUCCESS;
@@ -419,22 +439,27 @@ _cairo_meta_surface_show_text_glyphs (void *abstract_surface,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
- cairo_scaled_font_t *scaled_font)
+ cairo_scaled_font_t *scaled_font,
+ cairo_rectangle_int_t *extents)
{
cairo_status_t status;
cairo_meta_surface_t *meta = abstract_surface;
cairo_command_show_text_glyphs_t *command;
command = malloc (sizeof (cairo_command_show_text_glyphs_t));
- if (command == NULL)
+ if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
command->header.type = CAIRO_COMMAND_SHOW_TEXT_GLYPHS;
command->header.region = CAIRO_META_REGION_ALL;
+ command->header.extents.x = 0;
+ command->header.extents.y = 0;
+ command->header.extents.width = meta->width_pixels;
+ command->header.extents.height = meta->height_pixels;
command->op = op;
status = _cairo_pattern_init_snapshot (&command->source.base, source);
- if (status)
+ if (unlikely (status))
goto CLEANUP_COMMAND;
command->utf8 = NULL;
@@ -446,7 +471,7 @@ _cairo_meta_surface_show_text_glyphs (void *abstract_surface,
if (utf8_len) {
command->utf8 = malloc (utf8_len);
- if (command->utf8 == NULL) {
+ if (unlikely (command->utf8 == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_ARRAYS;
}
@@ -454,7 +479,7 @@ _cairo_meta_surface_show_text_glyphs (void *abstract_surface,
}
if (num_glyphs) {
command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (glyphs[0]));
- if (command->glyphs == NULL) {
+ if (unlikely (command->glyphs == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_ARRAYS;
}
@@ -462,7 +487,7 @@ _cairo_meta_surface_show_text_glyphs (void *abstract_surface,
}
if (num_clusters) {
command->clusters = _cairo_malloc_ab (num_clusters, sizeof (clusters[0]));
- if (command->clusters == NULL) {
+ if (unlikely (command->clusters == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_ARRAYS;
}
@@ -474,7 +499,7 @@ _cairo_meta_surface_show_text_glyphs (void *abstract_surface,
command->scaled_font = cairo_scaled_font_reference (scaled_font);
status = _cairo_array_append (&meta->commands, &command);
- if (status)
+ if (unlikely (status))
goto CLEANUP_SCALED_FONT;
return CAIRO_STATUS_SUCCESS;
@@ -512,7 +537,7 @@ _cairo_meta_surface_snapshot (void *abstract_other)
cairo_meta_surface_t *meta;
meta = malloc (sizeof (cairo_meta_surface_t));
- if (meta == NULL)
+ if (unlikely (meta == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_surface_init (&meta->base, &cairo_meta_surface_backend,
@@ -542,7 +567,7 @@ _cairo_meta_surface_intersect_clip_path (void *dst,
cairo_status_t status;
command = malloc (sizeof (cairo_command_intersect_clip_path_t));
- if (command == NULL)
+ if (unlikely (command == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
command->header.type = CAIRO_COMMAND_INTERSECT_CLIP_PATH;
@@ -550,7 +575,7 @@ _cairo_meta_surface_intersect_clip_path (void *dst,
if (path) {
status = _cairo_path_fixed_init_copy (&command->path, path);
- if (status) {
+ if (unlikely (status)) {
free (command);
return status;
}
@@ -565,7 +590,7 @@ _cairo_meta_surface_intersect_clip_path (void *dst,
command->antialias = antialias;
status = _cairo_array_append (&meta->commands, &command);
- if (status) {
+ if (unlikely (status)) {
if (path)
_cairo_path_fixed_fini (&command->path);
free (command);
@@ -622,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 */
@@ -741,7 +768,7 @@ _cairo_meta_surface_get_path (cairo_surface_t *surface,
ASSERT_NOT_REACHED;
}
- if (status)
+ if (unlikely (status))
break;
}
@@ -789,14 +816,14 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
* ensure the current clip gets set on the surface. */
if (command->header.type != CAIRO_COMMAND_INTERSECT_CLIP_PATH) {
status = _cairo_surface_set_clip (target, &clip);
- if (status)
+ if (unlikely (status))
break;
}
dev_path = _cairo_command_get_path (command);
if (dev_path && has_device_transform) {
status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
- if (status)
+ if (unlikely (status))
break;
_cairo_path_fixed_transform (&path_copy, device_transform);
dev_path = &path_copy;
@@ -806,13 +833,13 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
case CAIRO_COMMAND_PAINT:
status = _cairo_surface_paint (target,
command->paint.op,
- &command->paint.source.base);
+ &command->paint.source.base, &command->header.extents);
break;
case CAIRO_COMMAND_MASK:
status = _cairo_surface_mask (target,
command->mask.op,
&command->mask.source.base,
- &command->mask.mask.base);
+ &command->mask.mask.base, &command->header.extents);
break;
case CAIRO_COMMAND_STROKE:
{
@@ -834,7 +861,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
&dev_ctm,
&dev_ctm_inverse,
command->stroke.tolerance,
- command->stroke.antialias);
+ command->stroke.antialias, &command->header.extents);
break;
}
case CAIRO_COMMAND_FILL:
@@ -881,7 +908,8 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
&dev_ctm,
&dev_ctm_inverse,
stroke_command->stroke.tolerance,
- stroke_command->stroke.antialias);
+ stroke_command->stroke.antialias,
+ &stroke_command->header.extents);
i++;
} else
status = _cairo_surface_fill (target,
@@ -890,7 +918,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
dev_path,
command->fill.fill_rule,
command->fill.tolerance,
- command->fill.antialias);
+ command->fill.antialias, &command->header.extents);
break;
}
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
@@ -904,7 +932,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
* copy the array before handing it to the backend.
*/
dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
- if (dev_glyphs == NULL) {
+ if (unlikely (dev_glyphs == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
break;
}
@@ -927,7 +955,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
dev_glyphs, num_glyphs,
command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
command->show_text_glyphs.cluster_flags,
- command->show_text_glyphs.scaled_font);
+ command->show_text_glyphs.scaled_font, &command->header.extents);
free (dev_glyphs);
break;
@@ -960,7 +988,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
}
}
- if (status)
+ if (unlikely (status))
break;
}
diff --git a/src/cairo-misc.c b/src/cairo-misc.c
index 27050a24..6f707a66 100644
--- a/src/cairo-misc.c
+++ b/src/cairo-misc.c
@@ -287,7 +287,7 @@ _cairo_validate_text_clusters (const char *utf8,
/* Make sure we've got valid UTF-8 for the cluster */
status = _cairo_utf8_to_ucs4 (utf8+n_bytes, cluster_bytes, NULL, NULL);
- if (status)
+ if (unlikely (status))
return CAIRO_STATUS_INVALID_CLUSTERS;
n_bytes += cluster_bytes ;
@@ -617,7 +617,7 @@ _cairo_lround (double d)
#include <windows.h>
#include <io.h>
-/* tmpfile() replacment for Windows.
+/* tmpfile() replacement for Windows.
*
* On Windows tmpfile() creates the file in the root directory. This
* may fail due to unsufficient privileges.
@@ -667,3 +667,108 @@ _cairo_win32_tmpfile (void)
}
#endif /* _WIN32 */
+
+typedef struct _cairo_intern_string {
+ cairo_hash_entry_t hash_entry;
+ int len;
+ char *string;
+} cairo_intern_string_t;
+
+static cairo_hash_table_t *_cairo_intern_string_ht;
+
+static unsigned long
+_intern_string_hash (const char *str, int len)
+{
+ const signed char *p = (const signed char *) str;
+ unsigned int h = *p;
+
+ for (p += 1; --len; p++)
+ h = (h << 5) - h + *p;
+
+ return h;
+}
+
+static cairo_bool_t
+_intern_string_equal (const void *_a, const void *_b)
+{
+ const cairo_intern_string_t *a = _a;
+ const cairo_intern_string_t *b = _b;
+
+ if (a->len != b->len)
+ return FALSE;
+
+ return memcmp (a->string, b->string, a->len) == 0;
+}
+
+cairo_status_t
+_cairo_intern_string (const char **str_inout, int len)
+{
+ char *str = (char *) *str_inout;
+ cairo_intern_string_t tmpl, *istring;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+ if (len < 0)
+ len = strlen (str);
+ tmpl.hash_entry.hash = _intern_string_hash (str, len);
+ tmpl.len = len;
+ tmpl.string = (char *) str;
+
+ CAIRO_MUTEX_LOCK (_cairo_intern_string_mutex);
+ if (_cairo_intern_string_ht == NULL) {
+ _cairo_intern_string_ht = _cairo_hash_table_create (_intern_string_equal);
+ if (unlikely (_cairo_intern_string_ht == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto BAIL;
+ }
+ }
+
+ istring = _cairo_hash_table_lookup (_cairo_intern_string_ht,
+ &tmpl.hash_entry);
+ if (istring == NULL) {
+ istring = malloc (sizeof (cairo_intern_string_t) + len + 1);
+ if (likely (istring != NULL)) {
+ istring->hash_entry.hash = tmpl.hash_entry.hash;
+ istring->len = tmpl.len;
+ istring->string = (char *) (istring + 1);
+ memcpy (istring->string, str, len);
+ istring->string[len] = '\0';
+
+ status = _cairo_hash_table_insert (_cairo_intern_string_ht,
+ &istring->hash_entry);
+ if (unlikely (status)) {
+ free (istring);
+ goto BAIL;
+ }
+ } else {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto BAIL;
+ }
+ }
+
+ *str_inout = istring->string;
+
+ BAIL:
+ CAIRO_MUTEX_UNLOCK (_cairo_intern_string_mutex);
+ return status;
+}
+
+static void
+_intern_string_pluck (void *entry, void *closure)
+{
+ _cairo_hash_table_remove (closure, entry);
+ free (entry);
+}
+
+void
+_cairo_intern_string_reset_static_data (void)
+{
+ CAIRO_MUTEX_LOCK (_cairo_intern_string_mutex);
+ if (_cairo_intern_string_ht != NULL) {
+ _cairo_hash_table_foreach (_cairo_intern_string_ht,
+ _intern_string_pluck,
+ _cairo_intern_string_ht);
+ _cairo_hash_table_destroy(_cairo_intern_string_ht);
+ _cairo_intern_string_ht = NULL;
+ }
+ CAIRO_MUTEX_UNLOCK (_cairo_intern_string_mutex);
+}
diff --git a/src/cairo-mutex-list-private.h b/src/cairo-mutex-list-private.h
index 6fdb389a..f5f654d5 100644
--- a/src/cairo-mutex-list-private.h
+++ b/src/cairo-mutex-list-private.h
@@ -40,6 +40,7 @@ CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_pattern_cache_lock)
CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_surface_cache_lock)
CAIRO_MUTEX_DECLARE (_cairo_font_face_mutex)
+CAIRO_MUTEX_DECLARE (_cairo_intern_string_mutex)
CAIRO_MUTEX_DECLARE (_cairo_scaled_font_map_mutex)
CAIRO_MUTEX_DECLARE (_cairo_scaled_font_error_mutex)
diff --git a/src/cairo-os2-private.h b/src/cairo-os2-private.h
index 5fa28295..e71a6dc9 100644
--- a/src/cairo-os2-private.h
+++ b/src/cairo-os2-private.h
@@ -41,17 +41,6 @@
#include "cairo-os2.h"
#include "cairoint.h"
-#define INCL_DOS
-#define INCL_DOSSEMAPHORES
-#define INCL_DOSERRORS
-#define INCL_WIN
-#define INCL_GPI
-#ifdef __WATCOMC__
-# include <os2.h>
-#else
-# include <os2emx.h>
-#endif
-
typedef struct _cairo_os2_surface
{
cairo_surface_t base;
diff --git a/src/cairo-os2-surface.c b/src/cairo-os2-surface.c
index bff649ae..02840e33 100644
--- a/src/cairo-os2-surface.c
+++ b/src/cairo-os2-surface.c
@@ -43,11 +43,6 @@
#include <float.h>
#ifdef BUILD_CAIRO_DLL
-# define INCL_WIN
-# define INCL_GPI
-# define INCL_DOS
-# define INCL_DOSERRORS
-# include <os2emx.h>
# include "cairo-os2.h"
# ifndef __WATCOMC__
# include <emx/startup.h>
@@ -1331,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-os2.h b/src/cairo-os2.h
index d0a13e47..0d18674b 100644
--- a/src/cairo-os2.h
+++ b/src/cairo-os2.h
@@ -38,8 +38,16 @@
#ifndef _CAIRO_OS2_H_
#define _CAIRO_OS2_H_
+#define INCL_DOS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSERRORS
+#define INCL_WIN
+#define INCL_GPI
+
#include "cairo.h"
+#include <os2.h>
+
CAIRO_BEGIN_DECLS
/* The OS/2 Specific Cairo API */
diff --git a/src/cairo-output-stream-private.h b/src/cairo-output-stream-private.h
index 787d0616..2b3d584e 100644
--- a/src/cairo-output-stream-private.h
+++ b/src/cairo-output-stream-private.h
@@ -43,14 +43,20 @@
#include <stdio.h>
#include <stdarg.h>
-typedef cairo_status_t (*cairo_output_stream_write_func_t) (cairo_output_stream_t *output_stream,
- const unsigned char *data,
- unsigned int length);
+typedef cairo_status_t
+(*cairo_output_stream_write_func_t) (cairo_output_stream_t *output_stream,
+ const unsigned char *data,
+ unsigned int length);
-typedef cairo_status_t (*cairo_output_stream_close_func_t) (cairo_output_stream_t *output_stream);
+typedef cairo_status_t
+(*cairo_output_stream_flush_func_t) (cairo_output_stream_t *output_stream);
+
+typedef cairo_status_t
+(*cairo_output_stream_close_func_t) (cairo_output_stream_t *output_stream);
struct _cairo_output_stream {
cairo_output_stream_write_func_t write_func;
+ cairo_output_stream_flush_func_t flush_func;
cairo_output_stream_close_func_t close_func;
unsigned long position;
cairo_status_t status;
@@ -62,6 +68,7 @@ extern const cairo_private cairo_output_stream_t _cairo_output_stream_nil;
cairo_private void
_cairo_output_stream_init (cairo_output_stream_t *stream,
cairo_output_stream_write_func_t write_func,
+ cairo_output_stream_flush_func_t flush_func,
cairo_output_stream_close_func_t close_func);
cairo_private cairo_status_t
@@ -93,6 +100,10 @@ _cairo_output_stream_create (cairo_write_func_t write_func,
cairo_private cairo_output_stream_t *
_cairo_output_stream_create_in_error (cairo_status_t status);
+/* Tries to flush any buffer maintained by the stream or its delegates. */
+cairo_private cairo_status_t
+_cairo_output_stream_flush (cairo_output_stream_t *stream);
+
/* Returns the final status value associated with this object, just
* before its last gasp. This final status value will capture any
* status failure returned by the stream's close_func as well. */
@@ -161,6 +172,11 @@ _cairo_memory_stream_copy (cairo_output_stream_t *base,
cairo_private int
_cairo_memory_stream_length (cairo_output_stream_t *stream);
+cairo_private cairo_status_t
+_cairo_memory_stream_destroy (cairo_output_stream_t *abstract_stream,
+ unsigned char **data_out,
+ unsigned int *length_out);
+
cairo_private cairo_output_stream_t *
_cairo_null_stream_create (void);
diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c
index bae6ac4f..71154339 100644
--- a/src/cairo-output-stream.c
+++ b/src/cairo-output-stream.c
@@ -70,9 +70,11 @@
void
_cairo_output_stream_init (cairo_output_stream_t *stream,
cairo_output_stream_write_func_t write_func,
+ cairo_output_stream_flush_func_t flush_func,
cairo_output_stream_close_func_t close_func)
{
stream->write_func = write_func;
+ stream->flush_func = flush_func;
stream->close_func = close_func;
stream->position = 0;
stream->status = CAIRO_STATUS_SUCCESS;
@@ -87,6 +89,7 @@ _cairo_output_stream_fini (cairo_output_stream_t *stream)
const cairo_output_stream_t _cairo_output_stream_nil = {
NULL, /* write_func */
+ NULL, /* flush_func */
NULL, /* close_func */
0, /* position */
CAIRO_STATUS_NO_MEMORY,
@@ -95,6 +98,7 @@ const cairo_output_stream_t _cairo_output_stream_nil = {
static const cairo_output_stream_t _cairo_output_stream_nil_write_error = {
NULL, /* write_func */
+ NULL, /* flush_func */
NULL, /* close_func */
0, /* position */
CAIRO_STATUS_WRITE_ERROR,
@@ -143,12 +147,13 @@ _cairo_output_stream_create (cairo_write_func_t write_func,
cairo_output_stream_with_closure_t *stream;
stream = malloc (sizeof (cairo_output_stream_with_closure_t));
- if (stream == NULL) {
+ if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
- _cairo_output_stream_init (&stream->base, closure_write, closure_close);
+ _cairo_output_stream_init (&stream->base,
+ closure_write, NULL, closure_close);
stream->write_func = write_func;
stream->close_func = close_func;
stream->closure = closure;
@@ -168,18 +173,42 @@ _cairo_output_stream_create_in_error (cairo_status_t status)
return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
stream = malloc (sizeof (cairo_output_stream_t));
- if (stream == NULL) {
+ if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
- _cairo_output_stream_init (stream, NULL, NULL);
+ _cairo_output_stream_init (stream, NULL, NULL, NULL);
stream->status = status;
return stream;
}
cairo_status_t
+_cairo_output_stream_flush (cairo_output_stream_t *stream)
+{
+ cairo_status_t status;
+
+ if (stream->closed)
+ return stream->status;
+
+ if (stream == &_cairo_output_stream_nil ||
+ stream == &_cairo_output_stream_nil_write_error)
+ {
+ return stream->status;
+ }
+
+ if (stream->flush_func) {
+ status = stream->flush_func (stream);
+ /* Don't overwrite a pre-existing status failure. */
+ if (stream->status == CAIRO_STATUS_SUCCESS)
+ stream->status = status;
+ }
+
+ return stream->status;
+}
+
+cairo_status_t
_cairo_output_stream_close (cairo_output_stream_t *stream)
{
cairo_status_t status;
@@ -569,12 +598,13 @@ _cairo_output_stream_create_for_file (FILE *file)
}
stream = malloc (sizeof *stream);
- if (stream == NULL) {
+ if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
- _cairo_output_stream_init (&stream->base, stdio_write, stdio_flush);
+ _cairo_output_stream_init (&stream->base,
+ stdio_write, stdio_flush, stdio_flush);
stream->file = file;
return &stream->base;
@@ -602,13 +632,14 @@ _cairo_output_stream_create_for_filename (const char *filename)
}
stream = malloc (sizeof *stream);
- if (stream == NULL) {
+ if (unlikely (stream == NULL)) {
fclose (file);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
- _cairo_output_stream_init (&stream->base, stdio_write, stdio_close);
+ _cairo_output_stream_init (&stream->base,
+ stdio_write, stdio_flush, stdio_close);
stream->file = file;
return &stream->base;
@@ -645,17 +676,43 @@ _cairo_memory_stream_create (void)
memory_stream_t *stream;
stream = malloc (sizeof *stream);
- if (stream == NULL) {
+ if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
- _cairo_output_stream_init (&stream->base, memory_write, memory_close);
+ _cairo_output_stream_init (&stream->base, memory_write, NULL, memory_close);
_cairo_array_init (&stream->array, 1);
return &stream->base;
}
+cairo_status_t
+_cairo_memory_stream_destroy (cairo_output_stream_t *abstract_stream,
+ unsigned char **data_out,
+ unsigned int *length_out)
+{
+ memory_stream_t *stream;
+ cairo_status_t status;
+
+ status = abstract_stream->status;
+ if (unlikely (status))
+ return _cairo_output_stream_destroy (abstract_stream);
+
+ stream = (memory_stream_t *) abstract_stream;
+
+ *length_out = _cairo_array_num_elements (&stream->array);
+ *data_out = malloc (*length_out);
+ if (unlikely (*data_out == NULL)) {
+ status = _cairo_output_stream_destroy (abstract_stream);
+ assert (status == CAIRO_STATUS_SUCCESS);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+ memcpy (*data_out, _cairo_array_index (&stream->array, 0), *length_out);
+
+ return _cairo_output_stream_destroy (abstract_stream);
+}
+
void
_cairo_memory_stream_copy (cairo_output_stream_t *base,
cairo_output_stream_t *dest)
@@ -670,7 +727,7 @@ _cairo_memory_stream_copy (cairo_output_stream_t *base,
return;
}
- _cairo_output_stream_write (dest,
+ _cairo_output_stream_write (dest,
_cairo_array_index (&stream->array, 0),
_cairo_array_num_elements (&stream->array));
}
@@ -696,12 +753,12 @@ _cairo_null_stream_create (void)
cairo_output_stream_t *stream;
stream = malloc (sizeof *stream);
- if (stream == NULL) {
+ if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
- _cairo_output_stream_init (stream, null_write, NULL);
+ _cairo_output_stream_init (stream, null_write, NULL, NULL);
return stream;
}
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index ec9419bb..ce4e4def 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -77,7 +77,7 @@ _cairo_paginated_surface_create (cairo_surface_t *target,
cairo_status_t status;
surface = malloc (sizeof (cairo_paginated_surface_t));
- if (surface == NULL) {
+ if (unlikely (surface == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FAIL;
}
@@ -99,7 +99,7 @@ _cairo_paginated_surface_create (cairo_surface_t *target,
surface->meta = _cairo_meta_surface_create (content, width, height);
status = cairo_surface_status (surface->meta);
- if (status)
+ if (unlikely (status))
goto FAIL_CLEANUP_SURFACE;
surface->page_num = 1;
@@ -151,7 +151,7 @@ _cairo_paginated_surface_set_size (cairo_surface_t *surface,
paginated_surface->meta = _cairo_meta_surface_create (paginated_surface->content,
width, height);
status = cairo_surface_status (paginated_surface->meta);
- if (status)
+ if (unlikely (status))
return _cairo_surface_set_error (surface, status);
return CAIRO_STATUS_SUCCESS;
@@ -215,7 +215,7 @@ _cairo_paginated_surface_acquire_source_image (void *abstract_surface,
cairo_rectangle_int_t extents;
status = _cairo_surface_get_extents (surface->target, &extents);
- if (status)
+ if (unlikely (status))
return status;
image = _cairo_paginated_surface_create_image_surface (surface,
@@ -223,7 +223,7 @@ _cairo_paginated_surface_acquire_source_image (void *abstract_surface,
extents.height);
status = _cairo_meta_surface_replay (surface->meta, image);
- if (status) {
+ if (unlikely (status)) {
cairo_surface_destroy (image);
return status;
}
@@ -267,7 +267,7 @@ _paint_fallback_image (cairo_paginated_surface_t *surface,
cairo_surface_set_device_offset (image, -x*x_scale, -y*y_scale);
status = _cairo_meta_surface_replay (surface->meta, image);
- if (status)
+ if (unlikely (status))
goto CLEANUP_IMAGE;
_cairo_pattern_init_for_surface (&pattern, image);
@@ -279,7 +279,7 @@ _paint_fallback_image (cairo_paginated_surface_t *surface,
status = _cairo_surface_paint (surface->target,
CAIRO_OPERATOR_SOURCE,
- &pattern.base);
+ &pattern.base, NULL);
_cairo_pattern_fini (&pattern.base);
CLEANUP_IMAGE:
@@ -318,7 +318,7 @@ _paint_page (cairo_paginated_surface_t *surface)
_cairo_analysis_surface_get_bounding_box (analysis, &bbox);
status = surface->backend->set_bounding_box (surface->target, &bbox);
- if (status)
+ if (unlikely (status))
goto FAIL;
}
@@ -327,7 +327,7 @@ _paint_page (cairo_paginated_surface_t *surface)
status = surface->backend->set_fallback_images_required (surface->target,
has_fallbacks);
- if (status)
+ if (unlikely (status))
goto FAIL;
}
@@ -360,7 +360,7 @@ _paint_page (cairo_paginated_surface_t *surface)
surface->target,
CAIRO_META_REGION_NATIVE);
assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
- if (status)
+ if (unlikely (status))
goto FAIL;
}
@@ -375,7 +375,7 @@ _paint_page (cairo_paginated_surface_t *surface)
box.p2.x = surface->width;
box.p2.y = surface->height;
status = _paint_fallback_image (surface, &box);
- if (status)
+ if (unlikely (status))
goto FAIL;
}
@@ -393,16 +393,19 @@ _paint_page (cairo_paginated_surface_t *surface)
CAIRO_FILL_RULE_WINDING,
CAIRO_GSTATE_TOLERANCE_DEFAULT,
CAIRO_ANTIALIAS_DEFAULT);
- if (status)
+ if (unlikely (status))
goto FAIL;
region = _cairo_analysis_surface_get_unsupported (analysis);
+
+ num_boxes = 0;
status = _cairo_region_get_boxes (region, &num_boxes, &boxes);
- if (status)
+ if (unlikely (status))
goto FAIL;
+
for (i = 0; i < num_boxes; i++) {
status = _paint_fallback_image (surface, &boxes[i]);
- if (status) {
+ if (unlikely (status)) {
_cairo_region_boxes_fini (region, boxes);
goto FAIL;
}
@@ -436,11 +439,11 @@ _cairo_paginated_surface_copy_page (void *abstract_surface)
cairo_paginated_surface_t *surface = abstract_surface;
status = _start_page (surface);
- if (status)
+ if (unlikely (status))
return status;
status = _paint_page (surface);
- if (status)
+ if (unlikely (status))
return status;
surface->page_num++;
@@ -463,20 +466,20 @@ _cairo_paginated_surface_show_page (void *abstract_surface)
cairo_paginated_surface_t *surface = abstract_surface;
status = _start_page (surface);
- if (status)
+ if (unlikely (status))
return status;
status = _paint_page (surface);
- if (status)
+ if (unlikely (status))
return status;
cairo_surface_show_page (surface->target);
status = cairo_surface_status (surface->target);
- if (status)
+ if (unlikely (status))
return status;
status = cairo_surface_status (surface->meta);
- if (status)
+ if (unlikely (status))
return status;
cairo_surface_destroy (surface->meta);
@@ -485,7 +488,7 @@ _cairo_paginated_surface_show_page (void *abstract_surface)
surface->width,
surface->height);
status = cairo_surface_status (surface->meta);
- if (status)
+ if (unlikely (status))
return status;
surface->page_num++;
@@ -529,7 +532,8 @@ _cairo_paginated_surface_get_font_options (void *abstract_surfa
static cairo_int_status_t
_cairo_paginated_surface_paint (void *abstract_surface,
cairo_operator_t op,
- const cairo_pattern_t *source)
+ const cairo_pattern_t *source,
+ cairo_rectangle_int_t *extents)
{
cairo_paginated_surface_t *surface = abstract_surface;
@@ -539,18 +543,19 @@ _cairo_paginated_surface_paint (void *abstract_surface,
surface->page_is_blank = FALSE;
- return _cairo_surface_paint (surface->meta, op, source);
+ return _cairo_surface_paint (surface->meta, op, source, NULL);
}
static cairo_int_status_t
_cairo_paginated_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- const cairo_pattern_t *mask)
+ const cairo_pattern_t *mask,
+ cairo_rectangle_int_t *extents)
{
cairo_paginated_surface_t *surface = abstract_surface;
- return _cairo_surface_mask (surface->meta, op, source, mask);
+ return _cairo_surface_mask (surface->meta, op, source, mask, NULL);
}
static cairo_int_status_t
@@ -562,7 +567,8 @@ _cairo_paginated_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
cairo_paginated_surface_t *surface = abstract_surface;
@@ -575,7 +581,7 @@ _cairo_paginated_surface_stroke (void *abstract_surface,
return _cairo_surface_stroke (surface->meta, op, source,
path, style,
ctm, ctm_inverse,
- tolerance, antialias);
+ tolerance, antialias, NULL);
}
static cairo_int_status_t
@@ -585,7 +591,8 @@ _cairo_paginated_surface_fill (void *abstract_surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
cairo_paginated_surface_t *surface = abstract_surface;
@@ -597,7 +604,7 @@ _cairo_paginated_surface_fill (void *abstract_surface,
return _cairo_surface_fill (surface->meta, op, source,
path, fill_rule,
- tolerance, antialias);
+ tolerance, antialias, NULL);
}
static cairo_bool_t
@@ -619,7 +626,8 @@ _cairo_paginated_surface_show_text_glyphs (void *abstract_surface,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
- cairo_scaled_font_t *scaled_font)
+ cairo_scaled_font_t *scaled_font,
+ cairo_rectangle_int_t *extents)
{
cairo_paginated_surface_t *surface = abstract_surface;
cairo_int_status_t status;
@@ -645,7 +653,7 @@ _cairo_paginated_surface_show_text_glyphs (void *abstract_surface,
glyphs, num_glyphs,
clusters, num_clusters,
cluster_flags,
- scaled_font);
+ scaled_font, NULL);
return status;
}
@@ -670,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-path-bounds.c b/src/cairo-path-bounds.c
index 70867e31..6245cd26 100644
--- a/src/cairo-path-bounds.c
+++ b/src/cairo-path-bounds.c
@@ -132,13 +132,69 @@ _cairo_path_bounder_line_to (void *closure, cairo_point_t *point)
}
static cairo_status_t
+_cairo_path_bounder_curve_to (void *closure,
+ cairo_point_t *b,
+ cairo_point_t *c,
+ cairo_point_t *d)
+{
+ cairo_path_bounder_t *bounder = closure;
+
+ if (bounder->has_move_to_point) {
+ _cairo_path_bounder_add_point (bounder,
+ &bounder->move_to_point);
+ bounder->has_move_to_point = FALSE;
+ }
+
+ _cairo_path_bounder_add_point (bounder, b);
+ _cairo_path_bounder_add_point (bounder, c);
+ _cairo_path_bounder_add_point (bounder, d);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
_cairo_path_bounder_close_path (void *closure)
{
return CAIRO_STATUS_SUCCESS;
}
-/* XXX: Perhaps this should compute a PixRegion rather than 4 doubles */
-cairo_status_t
+/* This computes the extents of all the points in the path, not those of
+ * the damage area (i.e it does not consider winding and it only inspects
+ * the control points of the curves, not the flattened path).
+ */
+void
+_cairo_path_fixed_approximate_extents (cairo_path_fixed_t *path,
+ cairo_rectangle_int_t *extents)
+{
+ cairo_path_bounder_t bounder;
+ cairo_status_t status;
+
+ _cairo_path_bounder_init (&bounder);
+
+ status = _cairo_path_fixed_interpret (path, CAIRO_DIRECTION_FORWARD,
+ _cairo_path_bounder_move_to,
+ _cairo_path_bounder_line_to,
+ _cairo_path_bounder_curve_to,
+ _cairo_path_bounder_close_path,
+ &bounder);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ if (bounder.has_point) {
+ extents->x = _cairo_fixed_integer_floor (bounder.min_x);
+ extents->y = _cairo_fixed_integer_floor (bounder.min_y);
+ extents->width =
+ _cairo_fixed_integer_ceil (bounder.max_x) - extents->x;
+ extents->height =
+ _cairo_fixed_integer_ceil (bounder.max_y) - extents->y;
+ } else {
+ extents->x = extents->y = 0;
+ extents->width = extents->height = 0;
+ }
+
+ _cairo_path_bounder_fini (&bounder);
+}
+
+void
_cairo_path_fixed_bounds (cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2,
@@ -155,8 +211,9 @@ _cairo_path_fixed_bounds (cairo_path_fixed_t *path,
_cairo_path_bounder_close_path,
&bounder,
tolerance);
+ assert (status == CAIRO_STATUS_SUCCESS);
- if (status == CAIRO_STATUS_SUCCESS && bounder.has_point) {
+ if (bounder.has_point) {
*x1 = _cairo_fixed_to_double (bounder.min_x);
*y1 = _cairo_fixed_to_double (bounder.min_y);
*x2 = _cairo_fixed_to_double (bounder.max_x);
@@ -169,6 +226,4 @@ _cairo_path_fixed_bounds (cairo_path_fixed_t *path,
}
_cairo_path_bounder_fini (&bounder);
-
- return status;
}
diff --git a/src/cairo-path-fill.c b/src/cairo-path-fill.c
index 1cef20e4..7af91d20 100644
--- a/src/cairo-path-fill.c
+++ b/src/cairo-path-fill.c
@@ -118,30 +118,23 @@ _cairo_filler_curve_to (void *closure,
cairo_point_t *c,
cairo_point_t *d)
{
- int i;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_filler_t *filler = closure;
- cairo_polygon_t *polygon = &filler->polygon;
cairo_spline_t spline;
- status = _cairo_spline_init (&spline, &filler->current_point, b, c, d);
-
- if (status == CAIRO_INT_STATUS_DEGENERATE)
+ if (! _cairo_spline_init (&spline,
+ (cairo_add_point_func_t) _cairo_polygon_line_to,
+ &filler->polygon,
+ &filler->current_point, b, c, d))
+ {
return CAIRO_STATUS_SUCCESS;
+ }
- status = _cairo_spline_decompose (&spline, filler->tolerance);
- if (status)
- goto CLEANUP_SPLINE;
-
- for (i = 1; i < spline.num_points; i++)
- _cairo_polygon_line_to (polygon, &spline.points[i]);
-
- CLEANUP_SPLINE:
+ _cairo_spline_decompose (&spline, filler->tolerance);
_cairo_spline_fini (&spline);
filler->current_point = *d;
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
@@ -157,6 +150,7 @@ _cairo_filler_close_path (void *closure)
static cairo_int_status_t
_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
cairo_traps_t *traps);
cairo_status_t
@@ -170,7 +164,7 @@ _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
/* Before we do anything else, we use a special-case filler for
* a device-axis aligned rectangle if possible. */
- status = _cairo_path_fixed_fill_rectangle (path, traps);
+ status = _cairo_path_fixed_fill_rectangle (path, fill_rule, traps);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status;
@@ -183,18 +177,18 @@ _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
_cairo_filler_curve_to,
_cairo_filler_close_path,
&filler);
- if (status)
+ if (unlikely (status))
goto BAIL;
_cairo_polygon_close (&filler.polygon);
status = _cairo_polygon_status (&filler.polygon);
- if (status)
+ if (unlikely (status))
goto BAIL;
status = _cairo_bentley_ottmann_tessellate_polygon (filler.traps,
&filler.polygon,
fill_rule);
- if (status)
+ if (unlikely (status))
goto BAIL;
BAIL:
@@ -212,27 +206,77 @@ BAIL:
*/
static cairo_int_status_t
_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
cairo_traps_t *traps)
{
- if (_cairo_path_fixed_is_box (path, NULL)) {
- cairo_point_t *p = path->buf_head.base.points;
- cairo_point_t *top_left, *bot_right;
-
- top_left = &p[0];
- bot_right = &p[2];
- if (top_left->x > bot_right->x || top_left->y > bot_right->y) {
- int n;
-
- /* not a simple cairo_rectangle() */
- for (n = 0; n < 4; n++) {
- if (p[n].x <= top_left->x && p[n].y <= top_left->y)
- top_left = &p[n];
- if (p[n].x >= bot_right->x && p[n].y >= bot_right->y)
- bot_right = &p[n];
+ cairo_box_t box;
+
+ if (_cairo_path_fixed_is_box (path, &box)) {
+ if (box.p1.x > box.p2.x) {
+ cairo_fixed_t t;
+
+ t = box.p1.x;
+ box.p1.x = box.p2.x;
+ box.p2.x = t;
+ }
+
+ if (box.p1.y > box.p2.y) {
+ cairo_fixed_t t;
+
+ t = box.p1.y;
+ box.p1.y = box.p2.y;
+ box.p2.y = t;
+ }
+
+ return _cairo_traps_tessellate_rectangle (traps, &box.p1, &box.p2);
+ } else if (fill_rule == CAIRO_FILL_RULE_WINDING) {
+ cairo_path_fixed_iter_t iter;
+ int last_cw = -1;
+
+ /* Support a series of rectangles as can be expected to describe a
+ * GdkRegion clip region during exposes.
+ */
+ _cairo_path_fixed_iter_init (&iter, path);
+ while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
+ cairo_status_t status;
+ int cw = 0;
+
+ if (box.p1.x > box.p2.x) {
+ cairo_fixed_t t;
+
+ t = box.p1.x;
+ box.p1.x = box.p2.x;
+ box.p2.x = t;
+
+ cw = ! cw;
+ }
+
+ if (box.p1.y > box.p2.y) {
+ cairo_fixed_t t;
+
+ t = box.p1.y;
+ box.p1.y = box.p2.y;
+ box.p2.y = t;
+
+ cw = ! cw;
}
+
+ if (last_cw < 0) {
+ last_cw = cw;
+ } else if (last_cw != cw) {
+ _cairo_traps_clear (traps);
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
+ status = _cairo_traps_tessellate_rectangle (traps,
+ &box.p1, &box.p2);
+ if (unlikely (status))
+ return status;
}
+ if (_cairo_path_fixed_iter_at_end (&iter))
+ return CAIRO_STATUS_SUCCESS;
- return _cairo_traps_tessellate_rectangle (traps, top_left, bot_right);
+ _cairo_traps_clear (traps);
}
return CAIRO_INT_STATUS_UNSUPPORTED;
diff --git a/src/cairo-path-fixed-private.h b/src/cairo-path-fixed-private.h
index 4a5990d4..0ade9880 100644
--- a/src/cairo-path-fixed-private.h
+++ b/src/cairo-path-fixed-private.h
@@ -37,6 +37,7 @@
#define CAIRO_PATH_FIXED_PRIVATE_H
#include "cairo-types-private.h"
+#include "cairo-compiler-private.h"
enum cairo_path_op {
CAIRO_PATH_OP_MOVE_TO = 0,
@@ -53,9 +54,9 @@ typedef char cairo_path_op_t;
typedef struct _cairo_path_buf {
struct _cairo_path_buf *next, *prev;
- int buf_size;
- int num_ops;
- int num_points;
+ unsigned int buf_size;
+ unsigned int num_ops;
+ unsigned int num_points;
cairo_path_op_t *op;
cairo_point_t *points;
@@ -77,4 +78,31 @@ struct _cairo_path_fixed {
cairo_path_buf_fixed_t buf_head;
};
+cairo_private unsigned long
+_cairo_path_fixed_hash (const cairo_path_fixed_t *path);
+
+cairo_private unsigned long
+_cairo_path_fixed_size (const cairo_path_fixed_t *path);
+
+cairo_private cairo_bool_t
+_cairo_path_fixed_equal (const cairo_path_fixed_t *a,
+ const cairo_path_fixed_t *b);
+
+typedef struct _cairo_path_fixed_iter {
+ cairo_path_buf_t *buf;
+ unsigned int n_op;
+ unsigned int n_point;
+} cairo_path_fixed_iter_t;
+
+cairo_private void
+_cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter,
+ cairo_path_fixed_t *path);
+
+cairo_private cairo_bool_t
+_cairo_path_fixed_iter_is_fill_box (cairo_path_fixed_iter_t *_iter,
+ cairo_box_t *box);
+
+cairo_private cairo_bool_t
+_cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter);
+
#endif /* CAIRO_PATH_FIXED_PRIVATE_H */
diff --git a/src/cairo-path-fixed.c b/src/cairo-path-fixed.c
index 90861198..dd25bb88 100644
--- a/src/cairo-path-fixed.c
+++ b/src/cairo-path-fixed.c
@@ -120,7 +120,7 @@ _cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
buf_size = MAX (num_ops, (num_points + 1) / 2);
if (buf_size) {
buf = _cairo_path_buf_create (buf_size);
- if (buf == NULL) {
+ if (unlikely (buf == NULL)) {
_cairo_path_fixed_fini (path);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -144,6 +144,170 @@ _cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
return CAIRO_STATUS_SUCCESS;
}
+unsigned long
+_cairo_path_fixed_hash (const cairo_path_fixed_t *path)
+{
+ unsigned long hash = 0;
+ const cairo_path_buf_t *buf;
+ int num_points, num_ops;
+
+ hash = _cairo_hash_bytes (hash,
+ &path->current_point,
+ sizeof (path->current_point));
+ hash = _cairo_hash_bytes (hash,
+ &path->last_move_point,
+ sizeof (path->last_move_point));
+
+ num_ops = path->buf_head.base.num_ops;
+ num_points = path->buf_head.base.num_points;
+ for (buf = path->buf_head.base.next;
+ buf != NULL;
+ buf = buf->next)
+ {
+ hash = _cairo_hash_bytes (hash, buf->op,
+ buf->num_ops * sizeof (buf->op[0]));
+ hash = _cairo_hash_bytes (hash, buf->points,
+ buf->num_points * sizeof (buf->points[0]));
+
+ num_ops += buf->num_ops;
+ num_points += buf->num_points;
+ }
+
+ hash = _cairo_hash_bytes (hash, &num_ops, sizeof (num_ops));
+ hash = _cairo_hash_bytes (hash, &num_points, sizeof (num_points));
+
+ return hash;
+}
+
+unsigned long
+_cairo_path_fixed_size (const cairo_path_fixed_t *path)
+{
+ const cairo_path_buf_t *buf;
+ int num_points, num_ops;
+
+ num_ops = path->buf_head.base.num_ops;
+ num_points = path->buf_head.base.num_points;
+ for (buf = path->buf_head.base.next;
+ buf != NULL;
+ buf = buf->next)
+ {
+ num_ops += buf->num_ops;
+ num_points += buf->num_points;
+ }
+
+ return num_ops * sizeof (buf->op[0]) +
+ num_points * sizeof (buf->points[0]);
+}
+
+cairo_bool_t
+_cairo_path_fixed_equal (const cairo_path_fixed_t *a,
+ const cairo_path_fixed_t *b)
+{
+ const cairo_path_buf_t *buf_a, *buf_b;
+ const cairo_path_op_t *ops_a, *ops_b;
+ const cairo_point_t *points_a, *points_b;
+ int num_points_a, num_ops_a;
+ int num_points_b, num_ops_b;
+
+ if (a == b)
+ return TRUE;
+
+ if (a != NULL) {
+ num_ops_a = a->buf_head.base.num_ops;
+ num_points_a = a->buf_head.base.num_points;
+ for (buf_a = a->buf_head.base.next;
+ buf_a != NULL;
+ buf_a = buf_a->next)
+ {
+ num_ops_a += buf_a->num_ops;
+ num_points_a += buf_a->num_points;
+ }
+ } else
+ num_ops_a = num_points_a = 0;
+
+ if (b != NULL) {
+ num_ops_b = b->buf_head.base.num_ops;
+ num_points_b = b->buf_head.base.num_points;
+ for (buf_b = b->buf_head.base.next;
+ buf_b != NULL;
+ buf_b = buf_b->next)
+ {
+ num_ops_b += buf_b->num_ops;
+ num_points_b += buf_b->num_points;
+ }
+ } else
+ num_ops_b = num_points_b = 0;
+
+ if (num_ops_a == 0 && num_ops_b == 0)
+ return TRUE;
+
+ if (num_ops_a != num_ops_b || num_points_a != num_points_b)
+ return FALSE;
+
+ assert (a != NULL && b != NULL);
+
+ buf_a = &a->buf_head.base;
+ num_points_a = buf_a->num_points;
+ num_ops_a = buf_a->num_ops;
+ ops_a = buf_a->op;
+ points_a = buf_a->points;
+
+ buf_b = &b->buf_head.base;
+ num_points_b = buf_b->num_points;
+ num_ops_b = buf_b->num_ops;
+ ops_b = buf_b->op;
+ points_b = buf_b->points;
+
+ while (TRUE) {
+ int num_ops = MIN (num_ops_a, num_ops_b);
+ int num_points = MIN (num_points_a, num_points_b);
+
+ if (memcmp (ops_a, ops_b, num_ops * sizeof (cairo_path_op_t)))
+ return FALSE;
+ if (memcmp (points_a, points_b, num_points * sizeof (cairo_point_t)))
+ return FALSE;
+
+ num_ops_a -= num_ops;
+ ops_a += num_ops;
+ num_points_a -= num_points;
+ points_a += num_points;
+ if (num_ops_a == 0 || num_points_a == 0) {
+ if (num_ops_a || num_points_a)
+ return FALSE;
+
+ buf_a = buf_a->next;
+ if (buf_a == NULL)
+ break;
+
+ num_points_a = buf_a->num_points;
+ num_ops_a = buf_a->num_ops;
+ ops_a = buf_a->op;
+ points_a = buf_a->points;
+ }
+
+ num_ops_b -= num_ops;
+ ops_b += num_ops;
+ num_points_b -= num_points;
+ points_b += num_points;
+ if (num_ops_b == 0 || num_points_b == 0) {
+ if (num_ops_b || num_points_b)
+ return FALSE;
+
+ buf_b = buf_b->next;
+ if (buf_b == NULL)
+ break;
+
+ num_points_b = buf_b->num_points;
+ num_ops_b = buf_b->num_ops;
+ ops_b = buf_b->op;
+ points_b = buf_b->points;
+ }
+ }
+
+ return TRUE;
+}
+
+
cairo_path_fixed_t *
_cairo_path_fixed_create (void)
{
@@ -208,7 +372,7 @@ _cairo_path_fixed_move_to (cairo_path_fixed_t *path,
*last_move_to_point = point;
} else {
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &point, 1);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -262,7 +426,7 @@ _cairo_path_fixed_line_to (cairo_path_fixed_t *path,
else
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1);
- if (status)
+ if (unlikely (status))
return status;
path->current_point = point;
@@ -303,12 +467,12 @@ _cairo_path_fixed_curve_to (cairo_path_fixed_t *path,
if (! path->has_current_point) {
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO,
&point[0], 1);
- if (status)
+ if (unlikely (status))
return status;
}
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3);
- if (status)
+ if (unlikely (status))
return status;
path->current_point = point[2];
@@ -355,13 +519,13 @@ _cairo_path_fixed_close_path (cairo_path_fixed_t *path)
return CAIRO_STATUS_SUCCESS;
status = _cairo_path_fixed_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_path_fixed_move_to (path,
path->last_move_point.x,
path->last_move_point.y);
- if (status)
+ if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
@@ -393,7 +557,7 @@ _cairo_path_fixed_add (cairo_path_fixed_t *path,
buf->num_points + num_points > 2 * buf->buf_size)
{
buf = _cairo_path_buf_create (buf->buf_size * 2);
- if (buf == NULL)
+ if (unlikely (buf == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_cairo_path_fixed_add_buf (path, buf);
@@ -528,7 +692,7 @@ _cairo_path_fixed_interpret (const cairo_path_fixed_t *path,
status = (*close_path) (closure);
break;
}
- if (status)
+ if (unlikely (status))
return status;
if (forward) {
@@ -595,7 +759,7 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
cairo_fixed_t scaley)
{
cairo_path_buf_t *buf = &path->buf_head.base;
- int i;
+ unsigned int i;
while (buf) {
for (i = 0; i < buf->num_points; i++) {
@@ -626,7 +790,7 @@ _cairo_path_fixed_transform (cairo_path_fixed_t *path,
cairo_matrix_t *matrix)
{
cairo_path_buf_t *buf;
- int i;
+ unsigned int i;
double dx, dy;
if (matrix->yx == 0.0 && matrix->xy == 0.0) {
@@ -726,33 +890,24 @@ _cpf_curve_to (void *closure,
cairo_point_t *p3)
{
cpf_t *cpf = closure;
- cairo_status_t status;
cairo_spline_t spline;
- int i;
cairo_point_t *p0 = &cpf->current_point;
- status = _cairo_spline_init (&spline, p0, p1, p2, p3);
- if (status == CAIRO_INT_STATUS_DEGENERATE)
+ if (! _cairo_spline_init (&spline,
+ (cairo_add_point_func_t) cpf->line_to,
+ cpf->closure,
+ p0, p1, p2, p3))
+ {
return CAIRO_STATUS_SUCCESS;
-
- status = _cairo_spline_decompose (&spline, cpf->tolerance);
- if (status)
- goto out;
-
- for (i=1; i < spline.num_points; i++) {
- status = cpf->line_to (cpf->closure, &spline.points[i]);
- if (status)
- goto out;
}
- cpf->current_point = *p3;
+ _cairo_spline_decompose (&spline, cpf->tolerance);
+ _cairo_spline_fini (&spline);
- status = CAIRO_STATUS_SUCCESS;
+ cpf->current_point = *p3;
- out:
- _cairo_spline_fini (&spline);
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
@@ -775,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;
@@ -847,10 +1011,8 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path,
buf->points[2].y == buf->points[3].y &&
buf->points[3].x == buf->points[0].x)
{
- if (box) {
- box->p1 = buf->points[0];
- box->p2 = buf->points[2];
- }
+ box->p1 = buf->points[0];
+ box->p2 = buf->points[2];
return TRUE;
}
@@ -859,10 +1021,8 @@ _cairo_path_fixed_is_box (cairo_path_fixed_t *path,
buf->points[2].x == buf->points[3].x &&
buf->points[3].y == buf->points[0].y)
{
- if (box) {
- box->p1 = buf->points[0];
- box->p2 = buf->points[2];
- }
+ box->p1 = buf->points[0];
+ box->p2 = buf->points[2];
return TRUE;
}
@@ -894,3 +1054,224 @@ _cairo_path_fixed_is_rectangle (cairo_path_fixed_t *path,
return FALSE;
}
+
+void
+_cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter,
+ cairo_path_fixed_t *path)
+{
+ iter->buf = &path->buf_head.base;
+ iter->n_op = 0;
+ iter->n_point = 0;
+}
+
+static cairo_bool_t
+_cairo_path_fixed_iter_next_op (cairo_path_fixed_iter_t *iter)
+{
+ if (++iter->n_op >= iter->buf->num_ops) {
+ iter->buf = iter->buf->next;
+ iter->n_op = 0;
+ iter->n_point = 0;
+ }
+
+ return iter->buf != NULL;
+}
+
+cairo_bool_t
+_cairo_path_fixed_iter_is_fill_box (cairo_path_fixed_iter_t *_iter,
+ cairo_box_t *box)
+{
+ cairo_point_t points[5];
+ cairo_path_fixed_iter_t iter;
+
+ if (_iter->buf == NULL)
+ return FALSE;
+
+ iter = *_iter;
+
+ if (iter.n_op == iter.buf->num_ops &&
+ ! _cairo_path_fixed_iter_next_op (&iter))
+ {
+ return FALSE;
+ }
+
+ /* Check whether the ops are those that would be used for a rectangle */
+ if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_MOVE_TO)
+ return FALSE;
+ points[0] = iter.buf->points[iter.n_point++];
+ if (! _cairo_path_fixed_iter_next_op (&iter))
+ return FALSE;
+
+ if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO)
+ return FALSE;
+ points[1] = iter.buf->points[iter.n_point++];
+ if (! _cairo_path_fixed_iter_next_op (&iter))
+ return FALSE;
+
+ if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO)
+ return FALSE;
+ points[2] = iter.buf->points[iter.n_point++];
+ if (! _cairo_path_fixed_iter_next_op (&iter))
+ return FALSE;
+
+ if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO)
+ return FALSE;
+ points[3] = iter.buf->points[iter.n_point++];
+ if (! _cairo_path_fixed_iter_next_op (&iter))
+ return FALSE;
+
+ /* Now, there are choices. The rectangle might end with a LINE_TO
+ * (to the original point), but this isn't required. If it
+ * doesn't, then it must end with a CLOSE_PATH (which may be implicit). */
+ if (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_LINE_TO)
+ {
+ points[4] = iter.buf->points[iter.n_point++];
+ if (points[4].x != points[0].x || points[4].y != points[0].y)
+ return FALSE;
+ }
+ else if (! (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_CLOSE_PATH ||
+ iter.buf->op[iter.n_op] == CAIRO_PATH_OP_MOVE_TO))
+ {
+ return FALSE;
+ }
+ if (! _cairo_path_fixed_iter_next_op (&iter))
+ return FALSE;
+
+ /* Ok, we may have a box, if the points line up */
+ if (points[0].y == points[1].y &&
+ points[1].x == points[2].x &&
+ points[2].y == points[3].y &&
+ points[3].x == points[0].x)
+ {
+ box->p1 = points[0];
+ box->p2 = points[2];
+ *_iter = iter;
+ return TRUE;
+ }
+
+ if (points[0].x == points[1].x &&
+ points[1].y == points[2].y &&
+ points[2].x == points[3].x &&
+ points[3].y == points[0].y)
+ {
+ box->p1 = points[0];
+ box->p2 = points[2];
+ *_iter = iter;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+cairo_bool_t
+_cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter)
+{
+ if (iter->buf == NULL)
+ return TRUE;
+
+ if (iter->n_op == iter->buf->num_ops)
+ return TRUE;
+
+ if (iter->buf->op[iter->n_op] == CAIRO_PATH_OP_MOVE_TO &&
+ iter->buf->num_ops == iter->n_op + 1)
+ {
+ return TRUE;
+ }
+
+ 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/cairo-path-in-fill.c b/src/cairo-path-in-fill.c
new file mode 100644
index 00000000..0362bfb6
--- /dev/null
+++ b/src/cairo-path-in-fill.c
@@ -0,0 +1,262 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2008 Chris Wilson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Chris Wilson.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+#include "cairo-path-fixed-private.h"
+
+typedef struct cairo_in_fill {
+ double tolerance;
+ int winding;
+
+ cairo_fixed_t x, y;
+
+ cairo_bool_t has_current_point;
+ cairo_point_t current_point;
+ cairo_point_t first_point;
+} cairo_in_fill_t;
+
+static void
+_cairo_in_fill_init (cairo_in_fill_t *in_fill,
+ double tolerance,
+ double x,
+ double y)
+{
+ in_fill->winding = 0;
+ in_fill->tolerance = tolerance;
+
+ in_fill->x = _cairo_fixed_from_double (x);
+ in_fill->y = _cairo_fixed_from_double (y);
+
+ in_fill->has_current_point = FALSE;
+ in_fill->current_point.x = 0;
+ in_fill->current_point.y = 0;
+}
+
+static void
+_cairo_in_fill_fini (cairo_in_fill_t *in_fill)
+{
+}
+
+static int
+edge_compare_for_y_against_x (const cairo_point_t *p1,
+ const cairo_point_t *p2,
+ cairo_fixed_t y,
+ cairo_fixed_t x)
+{
+ cairo_fixed_t adx, ady;
+ cairo_fixed_t dx, dy;
+ cairo_int64_t L, R;
+
+ adx = p2->x - p1->x;
+ dx = x - p1->x;
+
+ if (adx == 0)
+ return -dx;
+ if ((adx ^ dx) < 0)
+ return adx;
+
+ dy = y - p1->y;
+ ady = p2->y - p1->y;
+
+ L = _cairo_int32x32_64_mul (dy, adx);
+ R = _cairo_int32x32_64_mul (dx, ady);
+
+ return _cairo_int64_cmp (L, R);
+}
+
+static void
+_cairo_in_fill_add_edge (cairo_in_fill_t *in_fill,
+ const cairo_point_t *p1,
+ const cairo_point_t *p2)
+{
+ int dir;
+
+ /* count the number of edge crossing to -∞ */
+
+ dir = 1;
+ if (p2->y < p1->y) {
+ const cairo_point_t *tmp;
+
+ tmp = p1;
+ p1 = p2;
+ p2 = tmp;
+
+ dir = -1;
+ }
+
+ /* edge is entirely above or below, note the shortening rule */
+ if (p2->y <= in_fill->y || p1->y > in_fill->y)
+ return;
+
+ /* edge lies wholly to the right */
+ if (p1->x >= in_fill->x && p2->x >= in_fill->x)
+ return;
+
+ if ((p1->x <= in_fill->x && p2->x <= in_fill->x) ||
+ edge_compare_for_y_against_x (p1, p2, in_fill->y, in_fill->x) <= 0)
+ {
+ in_fill->winding += dir;
+ }
+}
+
+static cairo_status_t
+_cairo_in_fill_move_to (void *closure, cairo_point_t *point)
+{
+ cairo_in_fill_t *in_fill = closure;
+
+ /* implicit close path */
+ if (in_fill->has_current_point) {
+ _cairo_in_fill_add_edge (in_fill,
+ &in_fill->current_point,
+ &in_fill->first_point);
+ }
+
+ in_fill->first_point = *point;
+ in_fill->current_point = *point;
+ in_fill->has_current_point = TRUE;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_in_fill_line_to (void *closure, cairo_point_t *point)
+{
+ cairo_in_fill_t *in_fill = closure;
+
+ if (in_fill->has_current_point)
+ _cairo_in_fill_add_edge (in_fill, &in_fill->current_point, point);
+
+ in_fill->current_point = *point;
+ in_fill->has_current_point = TRUE;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_in_fill_curve_to (void *closure,
+ cairo_point_t *b,
+ cairo_point_t *c,
+ cairo_point_t *d)
+{
+ cairo_in_fill_t *in_fill = closure;
+ cairo_spline_t spline;
+ cairo_fixed_t top, bot, left;
+
+ /* first reject based on bbox */
+ bot = top = in_fill->current_point.y;
+ if (b->y < top) top = b->y;
+ if (b->y > bot) bot = b->y;
+ if (c->y < top) top = c->y;
+ if (c->y > bot) bot = c->y;
+ if (d->y < top) top = d->y;
+ if (d->y > bot) bot = d->y;
+ if (bot < in_fill->y || top > in_fill->y)
+ return CAIRO_STATUS_SUCCESS;
+
+ left = in_fill->current_point.x;
+ if (b->x < left) left = b->x;
+ if (c->x < left) left = c->x;
+ if (d->x < left) left = d->x;
+ if (left > in_fill->x)
+ return CAIRO_STATUS_SUCCESS;
+
+ /* XXX Investigate direct inspection of the inflections? */
+ if (! _cairo_spline_init (&spline,
+ (cairo_add_point_func_t) _cairo_in_fill_line_to,
+ in_fill,
+ &in_fill->current_point, b, c, d))
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ _cairo_spline_decompose (&spline, in_fill->tolerance);
+ _cairo_spline_fini (&spline);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_in_fill_close_path (void *closure)
+{
+ cairo_in_fill_t *in_fill = closure;
+
+ if (in_fill->has_current_point) {
+ _cairo_in_fill_add_edge (in_fill,
+ &in_fill->current_point,
+ &in_fill->first_point);
+
+ in_fill->has_current_point = FALSE;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_path_fixed_in_fill (cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ double x,
+ double y,
+ cairo_bool_t *is_inside)
+{
+ cairo_in_fill_t in_fill;
+ cairo_status_t status;
+
+ _cairo_in_fill_init (&in_fill, tolerance, x, y);
+
+ status = _cairo_path_fixed_interpret (path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_in_fill_move_to,
+ _cairo_in_fill_line_to,
+ _cairo_in_fill_curve_to,
+ _cairo_in_fill_close_path,
+ &in_fill);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ switch (fill_rule) {
+ case CAIRO_FILL_RULE_EVEN_ODD:
+ *is_inside = in_fill.winding & 1;
+ break;
+ case CAIRO_FILL_RULE_WINDING:
+ *is_inside = in_fill.winding != 0;
+ break;
+ default:
+ ASSERT_NOT_REACHED;
+ *is_inside = FALSE;
+ break;
+ }
+
+ _cairo_in_fill_fini (&in_fill);
+}
diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index efccbcfe..8c3064ea 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -175,7 +175,7 @@ _cairo_stroker_init (cairo_stroker_t *stroker,
status = _cairo_pen_init (&stroker->pen,
stroke_style->line_width / 2.0,
tolerance, ctm);
- if (status)
+ if (unlikely (status))
return status;
stroker->has_current_face = FALSE;
@@ -283,13 +283,17 @@ _cairo_stroker_join (cairo_stroker_t *stroker, cairo_stroke_face_t *in, cairo_st
tri[0] = in->point;
if (clockwise) {
- _cairo_pen_find_active_ccw_vertex_index (pen, &in->dev_vector, &start);
+ start =
+ _cairo_pen_find_active_ccw_vertex_index (pen, &in->dev_vector);
+ stop =
+ _cairo_pen_find_active_ccw_vertex_index (pen, &out->dev_vector);
step = -1;
- _cairo_pen_find_active_ccw_vertex_index (pen, &out->dev_vector, &stop);
} else {
- _cairo_pen_find_active_cw_vertex_index (pen, &in->dev_vector, &start);
+ start =
+ _cairo_pen_find_active_cw_vertex_index (pen, &in->dev_vector);
+ stop =
+ _cairo_pen_find_active_cw_vertex_index (pen, &out->dev_vector);
step = +1;
- _cairo_pen_find_active_cw_vertex_index (pen, &out->dev_vector, &stop);
}
i = start;
@@ -494,10 +498,10 @@ _cairo_stroker_add_cap (cairo_stroker_t *stroker, cairo_stroke_face_t *f)
cairo_pen_t *pen = &stroker->pen;
slope = f->dev_vector;
- _cairo_pen_find_active_cw_vertex_index (pen, &slope, &start);
+ start = _cairo_pen_find_active_cw_vertex_index (pen, &slope);
slope.dx = -slope.dx;
slope.dy = -slope.dy;
- _cairo_pen_find_active_cw_vertex_index (pen, &slope, &stop);
+ stop = _cairo_pen_find_active_cw_vertex_index (pen, &slope);
tri[0] = f->point;
tri[1] = f->cw;
@@ -654,22 +658,22 @@ _cairo_stroker_add_caps (cairo_stroker_t *stroker)
_compute_face (&stroker->first_point, &slope, dx, dy, stroker, &face);
status = _cairo_stroker_add_leading_cap (stroker, &face);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_stroker_add_trailing_cap (stroker, &face);
- if (status)
+ if (unlikely (status))
return status;
}
if (stroker->has_first_face) {
status = _cairo_stroker_add_leading_cap (stroker, &stroker->first_face);
- if (status)
+ if (unlikely (status))
return status;
}
if (stroker->has_current_face) {
status = _cairo_stroker_add_trailing_cap (stroker, &stroker->current_face);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -757,7 +761,7 @@ _cairo_stroker_move_to (void *closure, cairo_point_t *point)
/* Cap the start and end of the previous sub path as needed */
status = _cairo_stroker_add_caps (stroker);
- if (status)
+ if (unlikely (status))
return status;
stroker->first_point = *point;
@@ -802,13 +806,13 @@ _cairo_stroker_line_to (void *closure, cairo_point_t *point)
_compute_normalized_device_slope (&slope_dx, &slope_dy, stroker->ctm_inverse, NULL);
status = _cairo_stroker_add_sub_edge (stroker, p1, p2, &dev_slope, slope_dx, slope_dy, &start, &end);
- if (status)
+ if (unlikely (status))
return status;
if (stroker->has_current_face) {
/* Join with final face from previous segment */
status = _cairo_stroker_join (stroker, &stroker->current_face, &start);
- if (status)
+ if (unlikely (status))
return status;
} else if (!stroker->has_first_face) {
/* Save sub path's first face in case needed for closing join */
@@ -886,7 +890,7 @@ _cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point)
&dev_slope,
slope_dx, slope_dy,
&sub_start, &sub_end);
- if (status)
+ if (unlikely (status))
return status;
if (stroker->has_current_face) {
@@ -894,7 +898,7 @@ _cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point)
status = _cairo_stroker_join (stroker,
&stroker->current_face,
&sub_start);
- if (status)
+ if (unlikely (status))
return status;
stroker->has_current_face = FALSE;
@@ -905,14 +909,14 @@ _cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point)
} else {
/* Cap dash start if not connecting to a previous segment */
status = _cairo_stroker_add_leading_cap (stroker, &sub_start);
- if (status)
+ if (unlikely (status))
return status;
}
if (remain) {
/* Cap dash end if not at end of segment */
status = _cairo_stroker_add_trailing_cap (stroker, &sub_end);
- if (status)
+ if (unlikely (status))
return status;
} else {
stroker->current_face = sub_end;
@@ -923,7 +927,7 @@ _cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point)
/* Cap final face from previous segment */
status = _cairo_stroker_add_trailing_cap (stroker,
&stroker->current_face);
- if (status)
+ if (unlikely (status))
return status;
stroker->has_current_face = FALSE;
@@ -951,7 +955,7 @@ _cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point)
status = _cairo_stroker_add_leading_cap (stroker,
&stroker->current_face);
- if (status)
+ if (unlikely (status))
return status;
stroker->has_current_face = TRUE;
@@ -968,40 +972,51 @@ _cairo_stroker_curve_to (void *closure,
cairo_point_t *c,
cairo_point_t *d)
{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_stroker_t *stroker = closure;
- cairo_spline_t spline;
- cairo_pen_t pen;
+ cairo_pen_stroke_spline_t spline_pen;
cairo_stroke_face_t start, end;
cairo_point_t extra_points[4];
cairo_point_t *a = &stroker->current_point;
double initial_slope_dx, initial_slope_dy;
double final_slope_dx, final_slope_dy;
+ cairo_status_t status;
- status = _cairo_spline_init (&spline, a, b, c, d);
+ status = _cairo_pen_stroke_spline_init (&spline_pen,
+ &stroker->pen,
+ a, b, c, d);
if (status == CAIRO_INT_STATUS_DEGENERATE)
return _cairo_stroker_line_to (closure, d);
+ else if (unlikely (status))
+ return status;
- status = _cairo_pen_init_copy (&pen, &stroker->pen);
- if (status)
- goto CLEANUP_SPLINE;
-
- initial_slope_dx = _cairo_fixed_to_double (spline.initial_slope.dx);
- initial_slope_dy = _cairo_fixed_to_double (spline.initial_slope.dy);
- final_slope_dx = _cairo_fixed_to_double (spline.final_slope.dx);
- final_slope_dy = _cairo_fixed_to_double (spline.final_slope.dy);
+ initial_slope_dx = _cairo_fixed_to_double (spline_pen.spline.initial_slope.dx);
+ initial_slope_dy = _cairo_fixed_to_double (spline_pen.spline.initial_slope.dy);
+ final_slope_dx = _cairo_fixed_to_double (spline_pen.spline.final_slope.dx);
+ final_slope_dy = _cairo_fixed_to_double (spline_pen.spline.final_slope.dy);
- if (_compute_normalized_device_slope (&initial_slope_dx, &initial_slope_dy, stroker->ctm_inverse, NULL))
- _compute_face (a, &spline.initial_slope, initial_slope_dx, initial_slope_dy, stroker, &start);
+ if (_compute_normalized_device_slope (&initial_slope_dx, &initial_slope_dy,
+ stroker->ctm_inverse, NULL))
+ {
+ _compute_face (a,
+ &spline_pen.spline.initial_slope,
+ initial_slope_dx, initial_slope_dy,
+ stroker, &start);
+ }
- if (_compute_normalized_device_slope (&final_slope_dx, &final_slope_dy, stroker->ctm_inverse, NULL))
- _compute_face (d, &spline.final_slope, final_slope_dx, final_slope_dy, stroker, &end);
+ if (_compute_normalized_device_slope (&final_slope_dx, &final_slope_dy,
+ stroker->ctm_inverse, NULL))
+ {
+ _compute_face (d,
+ &spline_pen.spline.final_slope,
+ final_slope_dx, final_slope_dy,
+ stroker, &end);
+ }
if (stroker->has_current_face) {
status = _cairo_stroker_join (stroker, &stroker->current_face, &start);
- if (status)
+ if (unlikely (status))
goto CLEANUP_PEN;
- } else if (!stroker->has_first_face) {
+ } else if (! stroker->has_first_face) {
stroker->first_face = start;
stroker->has_first_face = TRUE;
}
@@ -1021,18 +1036,16 @@ _cairo_stroker_curve_to (void *closure,
extra_points[3].x -= end.point.x;
extra_points[3].y -= end.point.y;
- status = _cairo_pen_add_points (&pen, extra_points, 4);
- if (status)
+ status = _cairo_pen_add_points (&spline_pen.pen, extra_points, 4);
+ if (unlikely (status))
goto CLEANUP_PEN;
- status = _cairo_pen_stroke_spline (&pen, &spline, stroker->tolerance, stroker->traps);
- if (status)
- goto CLEANUP_PEN;
+ status = _cairo_pen_stroke_spline (&spline_pen,
+ stroker->tolerance,
+ stroker->traps);
CLEANUP_PEN:
- _cairo_pen_fini (&pen);
- CLEANUP_SPLINE:
- _cairo_spline_fini (&spline);
+ _cairo_pen_stroke_spline_fini (&spline_pen);
stroker->current_point = *d;
@@ -1063,16 +1076,20 @@ _cairo_stroker_curve_to_dashed (void *closure,
cairo_point_t *c,
cairo_point_t *d)
{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_stroker_t *stroker = closure;
cairo_spline_t spline;
cairo_point_t *a = &stroker->current_point;
cairo_line_join_t line_join_save;
- int i;
- status = _cairo_spline_init (&spline, a, b, c, d);
- if (status == CAIRO_INT_STATUS_DEGENERATE)
+ if (! _cairo_spline_init (&spline,
+ stroker->dashed ?
+ (cairo_add_point_func_t) _cairo_stroker_line_to_dashed :
+ (cairo_add_point_func_t) _cairo_stroker_line_to,
+ stroker,
+ a, b, c, d))
+ {
return _cairo_stroker_line_to_dashed (closure, d);
+ }
/* If the line width is so small that the pen is reduced to a
single point, then we have nothing to do. */
@@ -1084,26 +1101,14 @@ _cairo_stroker_curve_to_dashed (void *closure,
line_join_save = stroker->style->line_join;
stroker->style->line_join = CAIRO_LINE_JOIN_ROUND;
- status = _cairo_spline_decompose (&spline, stroker->tolerance);
- if (status)
- goto CLEANUP_GSTATE;
-
- for (i = 1; i < spline.num_points; i++) {
- if (stroker->dashed)
- status = _cairo_stroker_line_to_dashed (stroker, &spline.points[i]);
- else
- status = _cairo_stroker_line_to (stroker, &spline.points[i]);
- if (status)
- break;
- }
+ _cairo_spline_decompose (&spline, stroker->tolerance);
- CLEANUP_GSTATE:
stroker->style->line_join = line_join_save;
CLEANUP_SPLINE:
_cairo_spline_fini (&spline);
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
@@ -1116,18 +1121,18 @@ _cairo_stroker_close_path (void *closure)
status = _cairo_stroker_line_to_dashed (stroker, &stroker->first_point);
else
status = _cairo_stroker_line_to (stroker, &stroker->first_point);
- if (status)
+ if (unlikely (status))
return status;
if (stroker->has_first_face && stroker->has_current_face) {
/* Join first and final faces of sub path */
status = _cairo_stroker_join (stroker, &stroker->current_face, &stroker->first_face);
- if (status)
+ if (unlikely (status))
return status;
} else {
/* Cap the start and end of the sub path as needed */
status = _cairo_stroker_add_caps (stroker);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -1170,7 +1175,7 @@ _cairo_path_fixed_stroke_to_traps (cairo_path_fixed_t *path,
status = _cairo_stroker_init (&stroker, stroke_style,
ctm, ctm_inverse, tolerance,
traps);
- if (status)
+ if (unlikely (status))
return status;
if (stroker.style->dash)
@@ -1189,7 +1194,7 @@ _cairo_path_fixed_stroke_to_traps (cairo_path_fixed_t *path,
_cairo_stroker_curve_to,
_cairo_stroker_close_path,
&stroker);
- if (status)
+ if (unlikely (status))
goto BAIL;
/* Cap the start and end of the final sub path as needed */
@@ -1249,7 +1254,7 @@ _cairo_rectilinear_stroker_add_segment (cairo_rectilinear_stroker_t *stroker,
if (stroker->segments == stroker->segments_embedded) {
new_segments = _cairo_malloc_ab (new_size, sizeof (cairo_line_t));
- if (new_segments == NULL)
+ if (unlikely (new_segments == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (new_segments, stroker->segments,
@@ -1257,7 +1262,7 @@ _cairo_rectilinear_stroker_add_segment (cairo_rectilinear_stroker_t *stroker,
} else {
new_segments = _cairo_realloc_ab (stroker->segments,
new_size, sizeof (cairo_line_t));
- if (new_segments == NULL)
+ if (unlikely (new_segments == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -1381,7 +1386,7 @@ _cairo_rectilinear_stroker_emit_segments (cairo_rectilinear_stroker_t *stroker)
}
status = _cairo_traps_tessellate_rectangle (stroker->traps, a, b);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -1398,7 +1403,7 @@ _cairo_rectilinear_stroker_move_to (void *closure,
cairo_status_t status;
status = _cairo_rectilinear_stroker_emit_segments (stroker);
- if (status)
+ if (unlikely (status))
return status;
stroker->current_point = *point;
@@ -1444,13 +1449,13 @@ _cairo_rectilinear_stroker_close_path (void *closure)
status = _cairo_rectilinear_stroker_line_to (stroker,
&stroker->first_point);
- if (status)
+ if (unlikely (status))
return status;
stroker->open_sub_path = FALSE;
status = _cairo_rectilinear_stroker_emit_segments (stroker);
- if (status)
+ if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
@@ -1507,7 +1512,7 @@ _cairo_path_fixed_stroke_rectilinear (cairo_path_fixed_t *path,
NULL,
_cairo_rectilinear_stroker_close_path,
&rectilinear_stroker);
- if (status)
+ if (unlikely (status))
goto BAIL;
status = _cairo_rectilinear_stroker_emit_segments (&rectilinear_stroker);
@@ -1515,7 +1520,7 @@ _cairo_path_fixed_stroke_rectilinear (cairo_path_fixed_t *path,
BAIL:
_cairo_rectilinear_stroker_fini (&rectilinear_stroker);
- if (status)
+ if (unlikely (status))
_cairo_traps_clear (traps);
return status;
diff --git a/src/cairo-path.c b/src/cairo-path.c
index c6639f3f..84dfc0c4 100644
--- a/src/cairo-path.c
+++ b/src/cairo-path.c
@@ -127,7 +127,7 @@ _cairo_path_count (cairo_path_t *path,
&cpc);
}
- if (status)
+ if (unlikely (status))
return -1;
return cpc.count;
@@ -283,7 +283,7 @@ _cairo_path_populate (cairo_path_t *path,
&cpp);
}
- if (status)
+ if (unlikely (status))
return status;
/* Sanity check the count */
@@ -302,7 +302,7 @@ _cairo_path_create_in_error (cairo_status_t status)
return (cairo_path_t*) &_cairo_path_nil;
path = malloc (sizeof (cairo_path_t));
- if (path == NULL) {
+ if (unlikely (path == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_path_t*) &_cairo_path_nil;
}
@@ -322,7 +322,7 @@ _cairo_path_create_internal (cairo_path_fixed_t *path_fixed,
cairo_path_t *path;
path = malloc (sizeof (cairo_path_t));
- if (path == NULL) {
+ if (unlikely (path == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_path_t*) &_cairo_path_nil;
}
@@ -337,8 +337,8 @@ _cairo_path_create_internal (cairo_path_fixed_t *path_fixed,
if (path->num_data) {
path->data = _cairo_malloc_ab (path->num_data,
- sizeof (cairo_path_data_t));
- if (path->data == NULL) {
+ sizeof (cairo_path_data_t));
+ if (unlikely (path->data == NULL)) {
free (path);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_path_t*) &_cairo_path_nil;
@@ -474,7 +474,7 @@ _cairo_path_append_to_context (const cairo_path_t *path,
}
status = cairo_status (cr);
- if (status)
+ if (unlikely (status))
return status;
}
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 02b0674f..aa580d55 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -140,7 +140,7 @@ _cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern,
{
pattern->stops = _cairo_malloc_ab (other->stops_size,
sizeof (cairo_gradient_stop_t));
- if (pattern->stops == NULL) {
+ if (unlikely (pattern->stops == NULL)) {
pattern->stops_size = 0;
pattern->n_stops = 0;
return _cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY);
@@ -181,7 +181,7 @@ _cairo_pattern_init_copy (cairo_pattern_t *pattern,
cairo_status_t status;
status = _cairo_gradient_pattern_init_copy (dst, src);
- if (status)
+ if (unlikely (status))
return status;
} break;
@@ -203,7 +203,7 @@ _cairo_pattern_init_snapshot (cairo_pattern_t *pattern,
/* We don't bother doing any fancy copy-on-write implementation
* for the pattern's data. It's generally quite tiny. */
status = _cairo_pattern_init_copy (pattern, other);
- if (status)
+ if (unlikely (status))
return status;
/* But we do let the surface snapshot stuff be as fancy as it
@@ -272,11 +272,11 @@ _cairo_pattern_create_copy (cairo_pattern_t **pattern,
*pattern = malloc (sizeof (cairo_radial_pattern_t));
break;
}
- if (*pattern == NULL)
+ if (unlikely (*pattern == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_pattern_init_copy (*pattern, other);
- if (status) {
+ if (unlikely (status)) {
free (*pattern);
return status;
}
@@ -379,18 +379,17 @@ _cairo_pattern_create_solid (const cairo_color_t *color,
CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_pattern_cache_lock);
- if (pattern == NULL) {
+ if (unlikely (pattern == NULL)) {
/* None cached, need to create a new pattern. */
pattern = malloc (sizeof (cairo_solid_pattern_t));
+ if (unlikely (pattern == NULL)) {
+ _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+ return (cairo_pattern_t *) &_cairo_pattern_nil;
+ }
}
- if (pattern == NULL) {
- _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
- pattern = (cairo_solid_pattern_t *) &_cairo_pattern_nil;
- } else {
- _cairo_pattern_init_solid (pattern, color, content);
- CAIRO_REFERENCE_COUNT_INIT (&pattern->base.ref_count, 1);
- }
+ _cairo_pattern_init_solid (pattern, color, content);
+ CAIRO_REFERENCE_COUNT_INIT (&pattern->base.ref_count, 1);
return &pattern->base;
}
@@ -535,7 +534,7 @@ cairo_pattern_create_for_surface (cairo_surface_t *surface)
return (cairo_pattern_t*) _cairo_pattern_create_in_error (surface->status);
pattern = malloc (sizeof (cairo_surface_pattern_t));
- if (pattern == NULL) {
+ if (unlikely (pattern == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_pattern_t *)&_cairo_pattern_nil.base;
}
@@ -581,7 +580,7 @@ cairo_pattern_create_linear (double x0, double y0, double x1, double y1)
cairo_linear_pattern_t *pattern;
pattern = malloc (sizeof (cairo_linear_pattern_t));
- if (pattern == NULL) {
+ if (unlikely (pattern == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_pattern_t *) &_cairo_pattern_nil.base;
}
@@ -629,7 +628,7 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0,
cairo_radial_pattern_t *pattern;
pattern = malloc (sizeof (cairo_radial_pattern_t));
- if (pattern == NULL) {
+ if (unlikely (pattern == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_pattern_t *) &_cairo_pattern_nil.base;
}
@@ -686,7 +685,6 @@ cairo_pattern_get_type (cairo_pattern_t *pattern)
{
return pattern->type;
}
-slim_hidden_def (cairo_pattern_get_type);
/**
* cairo_pattern_status:
@@ -847,11 +845,11 @@ _cairo_pattern_gradient_grow (cairo_gradient_pattern_t *pattern)
memcpy (new_stops, pattern->stops, old_size * sizeof (cairo_gradient_stop_t));
} else {
new_stops = _cairo_realloc_ab (pattern->stops,
- new_size,
+ new_size,
sizeof (cairo_gradient_stop_t));
}
- if (new_stops == NULL)
+ if (unlikely (new_stops == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
pattern->stops = new_stops;
@@ -873,7 +871,7 @@ _cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern,
if (pattern->n_stops >= pattern->stops_size) {
cairo_status_t status = _cairo_pattern_gradient_grow (pattern);
- if (status) {
+ if (unlikely (status)) {
status = _cairo_pattern_set_error (&pattern->base, status);
return;
}
@@ -1064,7 +1062,7 @@ cairo_pattern_set_matrix (cairo_pattern_t *pattern,
inverse = *matrix;
status = cairo_matrix_invert (&inverse);
- if (status)
+ if (unlikely (status))
status = _cairo_pattern_set_error (pattern, status);
}
slim_hidden_def (cairo_pattern_set_matrix);
@@ -1256,8 +1254,9 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
cairo_matrix_t matrix = pattern->base.matrix;
if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
- pixman_stops = _cairo_malloc_ab (pattern->n_stops, sizeof(pixman_gradient_stop_t));
- if (pixman_stops == NULL)
+ pixman_stops = _cairo_malloc_ab (pattern->n_stops,
+ sizeof(pixman_gradient_stop_t));
+ if (unlikely (pixman_stops == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -1341,7 +1340,7 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
if (pixman_stops != pixman_stops_static)
free (pixman_stops);
- if (pixman_image == NULL)
+ if (unlikely (pixman_image == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (_cairo_surface_is_image (dst))
@@ -1403,7 +1402,8 @@ _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pat
return image->base.status;
}
- _cairo_matrix_to_pixman_matrix (&matrix, &pixman_transform);
+ _cairo_matrix_to_pixman_matrix (&matrix, &pixman_transform,
+ width/2., height/2.);
if (!pixman_image_set_transform (pixman_image, &pixman_transform)) {
cairo_surface_destroy (&image->base);
pixman_image_unref (pixman_image);
@@ -1519,7 +1519,7 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt
dst))
{
status = _cairo_surface_reset (solid_surface_cache.cache[i].surface);
- if (status)
+ if (unlikely (status))
goto UNLOCK;
goto DONE;
@@ -1531,7 +1531,7 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt
dst))
{
status = _cairo_surface_reset (solid_surface_cache.cache[i].surface);
- if (status)
+ if (unlikely (status))
goto UNLOCK;
goto DONE;
@@ -1551,11 +1551,11 @@ _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *patt
/* Reuse the surface instead of evicting */
status = _cairo_surface_reset (surface);
- if (status)
+ if (unlikely (status))
goto EVICT;
status = _cairo_surface_repaint_solid_pattern_surface (dst, surface, pattern);
- if (status)
+ if (unlikely (status))
goto EVICT;
cairo_surface_reference (surface);
@@ -1839,14 +1839,14 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
int w, h;
status = _cairo_surface_get_extents (surface, &extents);
- if (status)
+ if (unlikely (status))
goto BAIL;
- status = _cairo_surface_clone_similar (dst, pattern->surface,
+ status = _cairo_surface_clone_similar (dst, surface,
extents.x, extents.y,
extents.width, extents.height,
&extents.x, &extents.y, &src);
- if (status)
+ if (unlikely (status))
goto BAIL;
w = 2 * extents.width;
@@ -1914,14 +1914,14 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
cairo_surface_destroy (src);
- if (status)
+ if (unlikely (status))
goto BAIL;
attr->extend = CAIRO_EXTEND_REPEAT;
}
status = _cairo_surface_get_extents (surface, &extents);
- if (status)
+ if (unlikely (status))
goto BAIL;
/* We first transform the rectangle to the coordinate space of the
@@ -1969,7 +1969,7 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
extents.x, extents.y,
extents.width, extents.height,
&x, &y, out);
- if (status)
+ if (unlikely (status))
goto BAIL;
if (x != 0 || y != 0) {
@@ -1999,8 +1999,11 @@ _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pat
assert (invert_status == CAIRO_STATUS_SUCCESS);
if (m.x0 != 0. || m.y0 != 0.) {
- x = floor (m.x0);
- y = floor (m.y0);
+ /* pixman also limits the [xy]_offset to 16 bits so evenly
+ * spread the bits between the two.
+ */
+ x = floor (m.x0 / 2);
+ y = floor (m.y0 / 2);
attr->x_offset -= x;
attr->y_offset -= y;
cairo_matrix_init_translate (&m, x, y);
@@ -2181,7 +2184,7 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
src_x, src_y,
width, height,
src_out, src_attributes);
- if (status)
+ if (unlikely (status))
goto BAIL;
if (mask == NULL) {
@@ -2193,7 +2196,7 @@ _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
mask_x, mask_y,
width, height,
mask_out, mask_attributes);
- if (status)
+ if (unlikely (status))
_cairo_pattern_release_surface (src, *src_out, src_attributes);
BAIL:
@@ -2234,7 +2237,7 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern,
status = _cairo_surface_get_extents (surface, &surface_extents);
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
goto UNBOUNDED;
- if (status)
+ if (unlikely (status))
return status;
/* The filter can effectively enlarge the extents of the
@@ -2290,6 +2293,261 @@ _cairo_pattern_get_extents (const cairo_pattern_t *pattern,
return CAIRO_STATUS_SUCCESS;
}
+
+static unsigned long
+_cairo_solid_pattern_hash (unsigned long hash,
+ const cairo_pattern_t *pattern)
+{
+ const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
+
+ hash = _cairo_hash_bytes (hash, &solid->content, sizeof (solid->content));
+ hash = _cairo_hash_bytes (hash, &solid->color, sizeof (solid->color));
+
+ return hash;
+}
+
+static unsigned long
+_cairo_gradient_color_stops_hash (unsigned long hash,
+ const cairo_gradient_pattern_t *gradient)
+{
+ unsigned int n;
+
+ hash = _cairo_hash_bytes (hash,
+ &gradient->n_stops,
+ sizeof (gradient->n_stops));
+
+ for (n = 0; n < gradient->n_stops; n++) {
+ hash = _cairo_hash_bytes (hash,
+ &gradient->stops[n].offset,
+ sizeof (double));
+ hash = _cairo_hash_bytes (hash,
+ &gradient->stops[n].color,
+ sizeof (cairo_color_t));
+ }
+
+ return hash;
+}
+
+static unsigned long
+_cairo_linear_pattern_hash (unsigned long hash,
+ const cairo_pattern_t *pattern)
+{
+ const cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
+
+ hash = _cairo_hash_bytes (hash, &linear->p1, sizeof (linear->p1));
+ hash = _cairo_hash_bytes (hash, &linear->p2, sizeof (linear->p2));
+
+ return _cairo_gradient_color_stops_hash (hash, &linear->base);
+}
+
+static unsigned long
+_cairo_radial_pattern_hash (unsigned long hash, const cairo_pattern_t *pattern)
+{
+ const cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
+
+ hash = _cairo_hash_bytes (hash, &radial->c1, sizeof (radial->c1));
+ hash = _cairo_hash_bytes (hash, &radial->r1, sizeof (radial->r1));
+ hash = _cairo_hash_bytes (hash, &radial->c2, sizeof (radial->c2));
+ hash = _cairo_hash_bytes (hash, &radial->r2, sizeof (radial->r2));
+
+ return _cairo_gradient_color_stops_hash (hash, &radial->base);
+}
+
+static unsigned long
+_cairo_surface_pattern_hash (unsigned long hash,
+ const cairo_pattern_t *pattern)
+{
+ /* XXX requires cow-snapshots */
+ return hash;
+}
+
+unsigned long
+_cairo_pattern_hash (const cairo_pattern_t *pattern)
+{
+ unsigned long hash = _CAIRO_HASH_INIT_VALUE;
+
+ if (pattern->status)
+ return 0;
+
+ hash = _cairo_hash_bytes (hash, &pattern->type, sizeof (pattern->type));
+ hash = _cairo_hash_bytes (hash, &pattern->matrix, sizeof (pattern->matrix));
+ hash = _cairo_hash_bytes (hash, &pattern->filter, sizeof (pattern->filter));
+ hash = _cairo_hash_bytes (hash, &pattern->extend, sizeof (pattern->extend));
+
+ switch (pattern->type) {
+ case CAIRO_PATTERN_TYPE_SOLID:
+ return _cairo_solid_pattern_hash (hash, pattern);
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ return _cairo_linear_pattern_hash (hash, pattern);
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ return _cairo_radial_pattern_hash (hash, pattern);
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ return _cairo_surface_pattern_hash (hash, pattern);
+ default:
+ ASSERT_NOT_REACHED;
+ return FALSE;
+ }
+}
+
+static unsigned long
+_cairo_gradient_pattern_color_stops_size (const cairo_pattern_t *pattern)
+{
+ cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern;
+
+ return gradient->n_stops * (sizeof (double) + sizeof (cairo_color_t));
+}
+
+unsigned long
+_cairo_pattern_size (const cairo_pattern_t *pattern)
+{
+ if (pattern->status)
+ return 0;
+
+ /* XXX */
+ switch (pattern->type) {
+ case CAIRO_PATTERN_TYPE_SOLID:
+ return sizeof (cairo_solid_pattern_t);
+ break;
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ return sizeof (cairo_surface_pattern_t);
+ break;
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ return sizeof (cairo_linear_pattern_t) +
+ _cairo_gradient_pattern_color_stops_size (pattern);
+ break;
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ return sizeof (cairo_radial_pattern_t) +
+ _cairo_gradient_pattern_color_stops_size (pattern);
+ default:
+ ASSERT_NOT_REACHED;
+ return 0;
+ }
+}
+
+
+static cairo_bool_t
+_cairo_solid_pattern_equal (const cairo_pattern_t *A,
+ const cairo_pattern_t *B)
+{
+ const cairo_solid_pattern_t *a = (cairo_solid_pattern_t *) A;
+ const cairo_solid_pattern_t *b = (cairo_solid_pattern_t *) B;
+
+ if (a->content != b->content)
+ return FALSE;
+
+ return _cairo_color_equal (&a->color, &b->color);
+}
+
+static cairo_bool_t
+_cairo_gradient_color_stops_equal (const cairo_gradient_pattern_t *a,
+ const cairo_gradient_pattern_t *b)
+{
+ unsigned int n;
+
+ if (a->n_stops != b->n_stops)
+ return FALSE;
+
+ for (n = 0; n < a->n_stops; n++) {
+ if (a->stops[n].offset != b->stops[n].offset)
+ return FALSE;
+ if (! _cairo_color_equal (&a->stops[n].color, &b->stops[n].color))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static cairo_bool_t
+_cairo_linear_pattern_equal (const cairo_pattern_t *A,
+ const cairo_pattern_t *B)
+{
+ const cairo_linear_pattern_t *a = (cairo_linear_pattern_t *) A;
+ const cairo_linear_pattern_t *b = (cairo_linear_pattern_t *) B;
+
+ if (a->p1.x != b->p1.x)
+ return FALSE;
+
+ if (a->p1.y != b->p1.y)
+ return FALSE;
+
+ if (a->p2.x != b->p2.x)
+ return FALSE;
+
+ if (a->p2.y != b->p2.y)
+ return FALSE;
+
+ return _cairo_gradient_color_stops_equal (&a->base, &b->base);
+}
+
+static cairo_bool_t
+_cairo_radial_pattern_equal (const cairo_pattern_t *A,
+ const cairo_pattern_t *B)
+{
+ const cairo_radial_pattern_t *a = (cairo_radial_pattern_t *) A;
+ const cairo_radial_pattern_t *b = (cairo_radial_pattern_t *) B;
+
+ if (a->c1.x != b->c1.x)
+ return FALSE;
+
+ if (a->c1.y != b->c1.y)
+ return FALSE;
+
+ if (a->r1 != b->r1)
+ return FALSE;
+
+ if (a->c2.x != b->c2.x)
+ return FALSE;
+
+ if (a->c2.y != b->c2.y)
+ return FALSE;
+
+ if (a->r2 != b->r2)
+ return FALSE;
+
+ return _cairo_gradient_color_stops_equal (&a->base, &b->base);
+}
+
+static cairo_bool_t
+_cairo_surface_pattern_equal (const cairo_pattern_t *A,
+ const cairo_pattern_t *B)
+{
+ /* XXX requires cow-snapshots */
+ return FALSE;
+}
+
+cairo_bool_t
+_cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b)
+{
+ if (a->status || b->status)
+ return FALSE;
+
+ if (a->type != b->type)
+ return FALSE;
+
+ if (memcmp (&a->matrix, &b->matrix, sizeof (cairo_matrix_t)))
+ return FALSE;
+
+ if (a->filter != b->filter)
+ return FALSE;
+
+ if (a->extend != b->extend)
+ return FALSE;
+
+ switch (a->type) {
+ case CAIRO_PATTERN_TYPE_SOLID:
+ return _cairo_solid_pattern_equal (a, b);
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ return _cairo_linear_pattern_equal (a, b);
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ return _cairo_radial_pattern_equal (a, b);
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ return _cairo_surface_pattern_equal (a, b);
+ default:
+ ASSERT_NOT_REACHED;
+ return FALSE;
+ }
+}
+
/**
* cairo_pattern_get_rgba
* @pattern: a #cairo_pattern_t
diff --git a/src/cairo-pdf-operators-private.h b/src/cairo-pdf-operators-private.h
index 7ff843b1..4ef0fcae 100644
--- a/src/cairo-pdf-operators-private.h
+++ b/src/cairo-pdf-operators-private.h
@@ -68,6 +68,7 @@ typedef struct _cairo_pdf_operators {
cairo_scaled_font_subsets_t *font_subsets;
cairo_pdf_operators_use_font_subset_t use_font_subset;
void *use_font_subset_closure;
+ cairo_bool_t use_actual_text;
cairo_bool_t in_text_object; /* inside BT/ET pair */
/* PDF text state */
@@ -115,6 +116,10 @@ cairo_private void
_cairo_pdf_operators_set_cairo_to_pdf_matrix (cairo_pdf_operators_t *pdf_operators,
cairo_matrix_t *cairo_to_pdf);
+cairo_private void
+_cairo_pdf_operators_enable_actual_text (cairo_pdf_operators_t *pdf_operators,
+ cairo_bool_t enable);
+
cairo_private cairo_status_t
_cairo_pdf_operators_flush (cairo_pdf_operators_t *pdf_operators);
diff --git a/src/cairo-pdf-operators.c b/src/cairo-pdf-operators.c
index 819318a1..ea5c5148 100644
--- a/src/cairo-pdf-operators.c
+++ b/src/cairo-pdf-operators.c
@@ -68,6 +68,7 @@ _cairo_pdf_operators_init (cairo_pdf_operators_t *pdf_operators,
pdf_operators->in_text_object = FALSE;
pdf_operators->num_glyphs = 0;
pdf_operators->has_line_style = FALSE;
+ pdf_operators->use_actual_text = FALSE;
}
cairo_status_t
@@ -105,6 +106,13 @@ _cairo_pdf_operators_set_cairo_to_pdf_matrix (cairo_pdf_operators_t *pdf_operato
pdf_operators->has_line_style = FALSE;
}
+cairo_private void
+_cairo_pdf_operators_enable_actual_text (cairo_pdf_operators_t *pdf_operators,
+ cairo_bool_t enable)
+{
+ pdf_operators->use_actual_text = enable;
+}
+
/* Finish writing out any pending commands to the stream. This
* function must be called by the surface before emitting anything
* into the PDF stream.
@@ -293,13 +301,14 @@ _word_wrap_stream_create (cairo_output_stream_t *output, int max_column)
return _cairo_output_stream_create_in_error (output->status);
stream = malloc (sizeof (word_wrap_stream_t));
- if (stream == NULL) {
+ if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base,
_word_wrap_stream_write,
+ NULL,
_word_wrap_stream_close);
stream->output = output;
stream->max_column = max_column;
@@ -438,7 +447,7 @@ _cairo_pdf_operators_emit_path (cairo_pdf_operators_t *pdf_operators,
word_wrap = _word_wrap_stream_create (pdf_operators->stream, 72);
status = _cairo_output_stream_get_status (word_wrap);
- if (status)
+ if (unlikely (status))
return _cairo_output_stream_destroy (word_wrap);
info.output = word_wrap;
@@ -479,7 +488,7 @@ _cairo_pdf_operators_clip (cairo_pdf_operators_t *pdf_operators,
path,
&pdf_operators->cairo_to_pdf,
CAIRO_LINE_CAP_ROUND);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -560,7 +569,7 @@ _cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
*/
if (num_dashes % 2) {
dash = _cairo_malloc_abc (num_dashes, 2, sizeof (double));
- if (dash == NULL)
+ if (unlikely (dash == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (dash, style->dash, num_dashes * sizeof (double));
@@ -576,7 +585,7 @@ _cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators,
*/
if (dash == style->dash) {
dash = _cairo_malloc_ab (num_dashes, sizeof (double));
- if (dash == NULL)
+ if (unlikely (dash == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (dash, style->dash, num_dashes * sizeof (double));
}
@@ -705,7 +714,7 @@ _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators,
if (pdf_operators->in_text_object) {
status = _cairo_pdf_operators_end_text (pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -744,7 +753,7 @@ _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators,
_cairo_matrix_factor_out_scale (&m, &scale);
path_transform = m;
status = cairo_matrix_invert (&path_transform);
- if (status)
+ if (unlikely (status))
return status;
cairo_matrix_multiply (&m, &m, &pdf_operators->cairo_to_pdf);
@@ -753,7 +762,7 @@ _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators,
status = _cairo_pdf_operators_emit_stroke_style (pdf_operators, style, scale);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
- if (status)
+ if (unlikely (status))
return status;
if (has_ctm) {
@@ -769,7 +778,7 @@ _cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators,
path,
&path_transform,
style->line_cap);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (pdf_operators->stream, "%s", pdf_operator);
@@ -806,7 +815,7 @@ _cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators,
if (pdf_operators->in_text_object) {
status = _cairo_pdf_operators_end_text (pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -814,7 +823,7 @@ _cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators,
path,
&pdf_operators->cairo_to_pdf,
CAIRO_LINE_CAP_ROUND);
- if (status)
+ if (unlikely (status))
return status;
switch (fill_rule) {
@@ -955,7 +964,7 @@ _cairo_pdf_operators_flush_glyphs (cairo_pdf_operators_t *pdf_operators)
word_wrap_stream = _word_wrap_stream_create (pdf_operators->stream, 72);
status = _cairo_output_stream_get_status (word_wrap_stream);
- if (status)
+ if (unlikely (status))
return _cairo_output_stream_destroy (word_wrap_stream);
/* Check if glyph advance used to position every glyph */
@@ -1014,7 +1023,7 @@ _cairo_pdf_operators_set_text_matrix (cairo_pdf_operators_t *pdf_operators,
/* We require the matrix to be invertable. */
inverse = *matrix;
status = cairo_matrix_invert (&inverse);
- if (status)
+ if (unlikely (status))
return status;
pdf_operators->text_matrix = *matrix;
@@ -1103,7 +1112,7 @@ _cairo_pdf_operators_set_font_subset (cairo_pdf_operators_t *pdf_ope
status = pdf_operators->use_font_subset (subset_glyph->font_id,
subset_glyph->subset_id,
pdf_operators->use_font_subset_closure);
- if (status)
+ if (unlikely (status))
return status;
}
pdf_operators->font_id = subset_glyph->font_id;
@@ -1134,7 +1143,7 @@ _cairo_pdf_operators_end_text (cairo_pdf_operators_t *pdf_operators)
cairo_status_t status;
status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (pdf_operators->stream, "ET\n");
@@ -1168,7 +1177,7 @@ _cairo_pdf_operators_begin_actualtext (cairo_pdf_operators_t *pdf_operators,
_cairo_output_stream_printf (pdf_operators->stream, "/Span << /ActualText <feff");
if (utf8_len) {
status = _cairo_utf8_to_utf16 (utf8, utf8_len, &utf16, &utf16_len);
- if (status)
+ if (unlikely (status))
return status;
for (i = 0; i < utf16_len; i++) {
@@ -1203,11 +1212,11 @@ _cairo_pdf_operators_emit_glyph (cairo_pdf_operators_t *pdf_operator
pdf_operators->subset_id != subset_glyph->subset_id)
{
status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_operators_set_font_subset (pdf_operators, subset_glyph);
- if (status)
+ if (unlikely (status))
return status;
pdf_operators->is_new_text_object = FALSE;
@@ -1232,14 +1241,14 @@ _cairo_pdf_operators_emit_glyph (cairo_pdf_operators_t *pdf_operator
fabs(y - pdf_operators->cur_y) > GLYPH_POSITION_TOLERANCE)
{
status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
x = glyph->x;
y = glyph->y;
cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &x, &y);
status = _cairo_pdf_operators_set_text_position (pdf_operators, x, y);
- if (status)
+ if (unlikely (status))
return status;
x = 0.0;
@@ -1287,14 +1296,14 @@ _cairo_pdf_operators_emit_cluster (cairo_pdf_operators_t *pdf_operators,
utf8,
utf8_len,
&subset_glyph);
- if (status)
+ if (unlikely (status))
return status;
if (subset_glyph.utf8_is_mapped || utf8_len < 0) {
status = _cairo_pdf_operators_emit_glyph (pdf_operators,
glyphs,
&subset_glyph);
- if (status)
+ if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
@@ -1304,11 +1313,11 @@ _cairo_pdf_operators_emit_cluster (cairo_pdf_operators_t *pdf_operators,
/* Fallback to using ActualText to map zero or more glyphs to a
* unicode string. */
status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_operators_begin_actualtext (pdf_operators, utf8, utf8_len);
- if (status)
+ if (unlikely (status))
return status;
cur_glyph = glyphs;
@@ -1320,13 +1329,13 @@ _cairo_pdf_operators_emit_cluster (cairo_pdf_operators_t *pdf_operators,
cur_glyph->index,
NULL, -1,
&subset_glyph);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_operators_emit_glyph (pdf_operators,
cur_glyph,
&subset_glyph);
- if (status)
+ if (unlikely (status))
return status;
if ((cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD))
@@ -1335,7 +1344,7 @@ _cairo_pdf_operators_emit_cluster (cairo_pdf_operators_t *pdf_operators,
cur_glyph++;
}
status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_operators_end_actualtext (pdf_operators);
@@ -1365,13 +1374,13 @@ _cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators,
status = cairo_matrix_invert (&pdf_operators->font_matrix_inverse);
if (status == CAIRO_STATUS_INVALID_MATRIX)
return CAIRO_STATUS_SUCCESS;
- if (status)
+ if (unlikely (status))
return status;
pdf_operators->is_new_text_object = FALSE;
if (pdf_operators->in_text_object == FALSE) {
status = _cairo_pdf_operators_begin_text (pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
/* Force Tm and Tf to be emitted when starting a new text
@@ -1392,7 +1401,7 @@ _cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators,
! _cairo_matrix_scale_equal (&pdf_operators->text_matrix, &text_matrix))
{
status = _cairo_pdf_operators_flush_glyphs (pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
x = glyphs[0].x;
@@ -1403,7 +1412,7 @@ _cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators,
status = _cairo_pdf_operators_set_text_matrix (pdf_operators, &text_matrix);
if (status == CAIRO_STATUS_INVALID_MATRIX)
return CAIRO_STATUS_SUCCESS;
- if (status)
+ if (unlikely (status))
return status;
}
@@ -1423,7 +1432,7 @@ _cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators,
clusters[i].num_glyphs,
cluster_flags,
scaled_font);
- if (status)
+ if (unlikely (status))
return status;
cur_text += clusters[i].num_bytes;
@@ -1439,7 +1448,7 @@ _cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators,
1,
FALSE,
scaled_font);
- if (status)
+ if (unlikely (status))
return status;
}
}
diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index ab222ded..d2fa43c4 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -63,6 +63,7 @@ typedef struct _cairo_pdf_group_resources {
typedef struct _cairo_pdf_pattern {
double width;
double height;
+ cairo_rectangle_int_t extents;
cairo_pattern_t *pattern;
cairo_pdf_resource_t pattern_res;
cairo_pdf_resource_t gstate_res;
@@ -127,12 +128,14 @@ struct _cairo_pdf_surface {
cairo_pdf_resource_t next_available_resource;
cairo_pdf_resource_t pages_resource;
+ cairo_pdf_version_t pdf_version;
cairo_bool_t compress_content;
cairo_pdf_resource_t content;
cairo_pdf_resource_t content_resources;
cairo_pdf_group_resources_t resources;
cairo_bool_t has_fallback_images;
+ cairo_bool_t header_emitted;
struct {
cairo_bool_t active;
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index b2a5619e..5862c4b5 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -45,6 +45,7 @@
#include "cairo-pdf-surface-private.h"
#include "cairo-pdf-operators-private.h"
#include "cairo-analysis-surface-private.h"
+#include "cairo-image-info-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-output-stream-private.h"
#include "cairo-paginated-private.h"
@@ -110,6 +111,20 @@
* XObject instead of using an indirect object.
*/
+static const cairo_pdf_version_t _cairo_pdf_versions[] =
+{
+ CAIRO_PDF_VERSION_1_4,
+ CAIRO_PDF_VERSION_1_5
+};
+
+#define CAIRO_PDF_VERSION_LAST ARRAY_LENGTH (_cairo_pdf_versions)
+
+static const char * _cairo_pdf_version_strings[CAIRO_PDF_VERSION_LAST] =
+{
+ "PDF 1.4",
+ "PDF 1.5"
+};
+
typedef struct _cairo_pdf_object {
long offset;
} cairo_pdf_object_t;
@@ -192,7 +207,7 @@ _cairo_pdf_surface_new_object (cairo_pdf_surface_t *surface)
object.offset = _cairo_output_stream_get_position (surface->output);
status = _cairo_array_append (&surface->objects, &object);
- if (status) {
+ if (unlikely (status)) {
resource.id = 0;
return resource;
}
@@ -234,7 +249,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
cairo_status_t status, status_ignored;
surface = malloc (sizeof (cairo_pdf_surface_t));
- if (surface == NULL) {
+ if (unlikely (surface == NULL)) {
/* destroy stream on behalf of caller */
status = _cairo_output_stream_destroy (output);
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
@@ -272,6 +287,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
goto BAIL1;
}
+ surface->pdf_version = CAIRO_PDF_VERSION_1_5;
surface->compress_content = TRUE;
surface->pdf_stream.active = FALSE;
surface->pdf_stream.old_output = NULL;
@@ -284,6 +300,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
surface->force_fallbacks = FALSE;
surface->select_pattern_gstate_saved = FALSE;
surface->current_pattern_is_solid_color = FALSE;
+ surface->header_emitted = FALSE;
_cairo_pdf_operators_init (&surface->pdf_operators,
surface->output,
@@ -292,12 +309,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
_cairo_pdf_operators_set_font_subsets_callback (&surface->pdf_operators,
_cairo_pdf_surface_add_font,
surface);
-
- /* Document header */
- _cairo_output_stream_printf (surface->output,
- "%%PDF-1.4\n");
- _cairo_output_stream_printf (surface->output,
- "%%%c%c%c%c\n", 181, 237, 174, 251);
+ _cairo_pdf_operators_enable_actual_text(&surface->pdf_operators, TRUE);
surface->paginated_surface = _cairo_paginated_surface_create (
&surface->base,
@@ -437,6 +449,83 @@ _extract_pdf_surface (cairo_surface_t *surface,
}
/**
+ * cairo_pdf_surface_restrict_to_version:
+ * @surface: a PDF #cairo_surface_t
+ * @version: PDF version
+ *
+ * Restricts the generated PDF file to @version. See cairo_pdf_get_versions()
+ * for a list of available version values that can be used here.
+ *
+ * This function should only be called before any drawing operations
+ * have been performed on the given surface. The simplest way to do
+ * this is to call this function immediately after creating the
+ * surface.
+ *
+ * Since: 1.10
+ **/
+void
+cairo_pdf_surface_restrict_to_version (cairo_surface_t *abstract_surface,
+ cairo_pdf_version_t version)
+{
+ cairo_pdf_surface_t *surface = NULL; /* hide compiler warning */
+ cairo_status_t status;
+
+ status = _extract_pdf_surface (abstract_surface, &surface);
+ if (status) {
+ status = _cairo_surface_set_error (abstract_surface, status);
+ return;
+ }
+
+ if (version < CAIRO_PDF_VERSION_LAST)
+ surface->pdf_version = version;
+
+ _cairo_pdf_operators_enable_actual_text(&surface->pdf_operators,
+ version >= CAIRO_PDF_VERSION_1_5);
+}
+
+/**
+ * cairo_pdf_get_versions:
+ * @versions: supported version list
+ * @num_versions: list length
+ *
+ * Used to retrieve the list of supported versions. See
+ * cairo_pdf_surface_restrict_to_version().
+ *
+ * Since: 1.10
+ **/
+void
+cairo_pdf_get_versions (cairo_pdf_version_t const **versions,
+ int *num_versions)
+{
+ if (versions != NULL)
+ *versions = _cairo_pdf_versions;
+
+ if (num_versions != NULL)
+ *num_versions = CAIRO_PDF_VERSION_LAST;
+}
+
+/**
+ * cairo_pdf_version_to_string:
+ * @version: a version id
+ *
+ * Get the string representation of the given @version id. This function
+ * will return %NULL if @version isn't valid. See cairo_pdf_get_versions()
+ * for a way to get the list of valid version ids.
+ *
+ * Return value: the string associated to given version.
+ *
+ * Since: 1.10
+ **/
+const char *
+cairo_pdf_version_to_string (cairo_pdf_version_t version)
+{
+ if (version >= CAIRO_PDF_VERSION_LAST)
+ return NULL;
+
+ return _cairo_pdf_version_strings[version];
+}
+
+/**
* cairo_pdf_surface_set_size:
* @surface: a PDF #cairo_surface_t
* @width_in_points: new surface width, in points (1 point == 1/72.0 inch)
@@ -462,7 +551,7 @@ cairo_pdf_surface_set_size (cairo_surface_t *surface,
cairo_status_t status;
status = _extract_pdf_surface (surface, &pdf_surface);
- if (status) {
+ if (unlikely (status)) {
status = _cairo_surface_set_error (surface, status);
return;
}
@@ -473,7 +562,7 @@ cairo_pdf_surface_set_size (cairo_surface_t *surface,
status = _cairo_paginated_surface_set_size (pdf_surface->paginated_surface,
width_in_points,
height_in_points);
- if (status)
+ if (unlikely (status))
status = _cairo_surface_set_error (surface, status);
}
@@ -550,7 +639,7 @@ _cairo_pdf_surface_add_alpha (cairo_pdf_surface_t *surface,
}
status = _cairo_array_append (&res->alphas, &alpha);
- if (status)
+ if (unlikely (status))
return status;
*index = _cairo_array_num_elements (&res->alphas) - 1;
@@ -613,7 +702,7 @@ _cairo_pdf_surface_add_font (unsigned int font_id,
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_array_append (&surface->fonts, &font);
- if (status)
+ if (unlikely (status))
return status;
return _cairo_array_append (&res->fonts, &font);
@@ -728,7 +817,7 @@ _cairo_pdf_surface_create_smask_group (cairo_pdf_surface_t *surface)
cairo_pdf_smask_group_t *group;
group = calloc (1, sizeof (cairo_pdf_smask_group_t));
- if (group == NULL) {
+ if (unlikely (group == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
@@ -775,6 +864,7 @@ _cairo_pdf_surface_add_smask_group (cairo_pdf_surface_t *surface,
static cairo_status_t
_cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
const cairo_pattern_t *pattern,
+ cairo_rectangle_int_t *extents,
cairo_pdf_resource_t *pattern_res,
cairo_pdf_resource_t *gstate_res)
{
@@ -808,7 +898,7 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
}
status = _cairo_pattern_create_copy (&pdf_pattern.pattern, pattern);
- if (status)
+ if (unlikely (status))
return status;
pdf_pattern.pattern_res = _cairo_pdf_surface_new_object (surface);
@@ -833,11 +923,20 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
pdf_pattern.width = surface->width;
pdf_pattern.height = surface->height;
+ if (extents) {
+ pdf_pattern.extents = *extents;
+ } else {
+ pdf_pattern.extents.x = 0;
+ pdf_pattern.extents.y = 0;
+ pdf_pattern.extents.width = surface->width;
+ pdf_pattern.extents.height = surface->height;
+ }
+
*pattern_res = pdf_pattern.pattern_res;
*gstate_res = pdf_pattern.gstate_res;
status = _cairo_array_append (&surface->patterns, &pdf_pattern);
- if (status) {
+ if (unlikely (status)) {
cairo_pattern_destroy (pdf_pattern.pattern);
return status;
}
@@ -923,7 +1022,7 @@ _cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface)
return CAIRO_STATUS_SUCCESS;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
if (surface->pdf_stream.compressed) {
@@ -1052,7 +1151,7 @@ _cairo_pdf_surface_open_knockout_group (cairo_pdf_surface_t *surface)
cairo_status_t status;
status = _cairo_pdf_surface_open_group (surface, NULL);
- if (status)
+ if (unlikely (status))
return status;
surface->group_stream.is_knockout = TRUE;
@@ -1070,7 +1169,7 @@ _cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface,
assert (surface->group_stream.active == TRUE);
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
if (surface->compress_content) {
@@ -1138,7 +1237,7 @@ _cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t *surface,
surface->compress_content,
NULL);
}
- if (status)
+ if (unlikely (status))
return status;
surface->content = surface->pdf_stream.self;
@@ -1157,12 +1256,12 @@ _cairo_pdf_surface_close_content_stream (cairo_pdf_surface_t *surface)
assert (surface->group_stream.active == FALSE);
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output, "Q\n");
status = _cairo_pdf_surface_close_stream (surface);
- if (status)
+ if (unlikely (status))
return status;
_cairo_pdf_surface_update_object (surface, surface->content_resources);
@@ -1280,6 +1379,27 @@ _cairo_pdf_surface_start_page (void *abstract_surface)
{
cairo_pdf_surface_t *surface = abstract_surface;
+ /* Document header */
+ if (! surface->header_emitted) {
+ const char *version;
+
+ switch (surface->pdf_version) {
+ case CAIRO_PDF_VERSION_1_4:
+ version = "1.4";
+ break;
+ default:
+ case CAIRO_PDF_VERSION_1_5:
+ version = "1.5";
+ break;
+ }
+
+ _cairo_output_stream_printf (surface->output,
+ "%%PDF-%s\n", version);
+ _cairo_output_stream_printf (surface->output,
+ "%%%c%c%c%c\n", 181, 237, 174, 251);
+ surface->header_emitted = TRUE;
+ }
+
_cairo_pdf_group_resources_clear (&surface->resources);
return CAIRO_STATUS_SUCCESS;
@@ -1294,7 +1414,7 @@ _cairo_pdf_surface_has_fallback_images (void *abstract_surface,
surface->has_fallback_images = has_fallbacks;
status = _cairo_pdf_surface_open_content_stream (surface, has_fallbacks);
- if (status)
+ if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
@@ -1341,7 +1461,7 @@ _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface,
alpha = _cairo_malloc_ab (image->height, image->width);
}
- if (alpha == NULL) {
+ if (unlikely (alpha == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP;
}
@@ -1395,7 +1515,7 @@ _cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface,
" /BitsPerComponent %d\n",
image->width, image->height,
image->format == CAIRO_FORMAT_A1 ? 1 : 8);
- if (status)
+ if (unlikely (status))
goto CLEANUP_ALPHA;
*stream_ret = surface->pdf_stream.self;
@@ -1437,7 +1557,7 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface,
rgb_size = image->height * image->width * 3;
rgb = _cairo_malloc_abc (image->width, image->height, 3);
- if (rgb == NULL) {
+ if (unlikely (rgb == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP;
}
@@ -1481,7 +1601,7 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface,
image->format == CAIRO_FORMAT_A8 ||
image->format == CAIRO_FORMAT_A1) {
status = _cairo_pdf_surface_emit_smask (surface, image, &smask);
- if (status)
+ if (unlikely (status))
goto CLEANUP_RGB;
if (smask.id)
@@ -1525,7 +1645,7 @@ _cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface,
IMAGE_DICTIONARY,
image->width, image->height,
interpolate);
- if (status)
+ if (unlikely (status))
goto CLEANUP_RGB;
#undef IMAGE_DICTIONARY
@@ -1540,27 +1660,188 @@ CLEANUP:
return status;
}
+static cairo_int_status_t
+_cairo_pdf_surface_emit_jpx_image (cairo_pdf_surface_t *surface,
+ cairo_surface_t *source,
+ cairo_pdf_resource_t *res,
+ int *width,
+ int *height)
+{
+ cairo_status_t status;
+ const unsigned char *mime_data;
+ unsigned int mime_data_length;
+ cairo_image_info_t info;
+
+ if (surface->pdf_version < CAIRO_PDF_VERSION_1_5)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JP2,
+ &mime_data, &mime_data_length);
+ if (mime_data == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_image_info_get_jpx_info (&info, mime_data, mime_data_length);
+ if (status)
+ return status;
+
+ status = _cairo_pdf_surface_open_stream (surface,
+ NULL,
+ FALSE,
+ " /Type /XObject\n"
+ " /Subtype /Image\n"
+ " /Width %d\n"
+ " /Height %d\n"
+ " /ColorSpace /DeviceRGB\n"
+ " /Filter /JPXDecode\n",
+ info.width,
+ info.height);
+ if (status)
+ return status;
+
+ *res = surface->pdf_stream.self;
+ _cairo_output_stream_write (surface->output, mime_data, mime_data_length);
+ _cairo_output_stream_printf (surface->output, "\n");
+ status = _cairo_pdf_surface_close_stream (surface);
+
+ *width = info.width;
+ *height = info.height;
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface,
+ cairo_surface_t *source,
+ cairo_pdf_resource_t *res,
+ int *width,
+ int *height)
+{
+ cairo_status_t status;
+ const unsigned char *mime_data;
+ unsigned int mime_data_length;
+ cairo_image_info_t info;
+
+ cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
+ &mime_data, &mime_data_length);
+ if (mime_data == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_image_info_get_jpeg_info (&info, mime_data, mime_data_length);
+ if (unlikely (status))
+ return status;
+
+ if (info.num_components != 1 && info.num_components != 3)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_pdf_surface_open_stream (surface,
+ NULL,
+ FALSE,
+ " /Type /XObject\n"
+ " /Subtype /Image\n"
+ " /Width %d\n"
+ " /Height %d\n"
+ " /ColorSpace %s\n"
+ " /BitsPerComponent %d\n"
+ " /Filter /DCTDecode\n",
+ info.width,
+ info.height,
+ info.num_components == 1 ? "/DeviceGray" : "/DeviceRGB",
+ info.bits_per_component);
+ if (unlikely (status))
+ return status;
+
+ *res = surface->pdf_stream.self;
+ _cairo_output_stream_write (surface->output, mime_data, mime_data_length);
+ _cairo_output_stream_printf (surface->output, "\n");
+ status = _cairo_pdf_surface_close_stream (surface);
+
+ *width = info.width;
+ *height = info.height;
+
+ return status;
+}
+
static cairo_status_t
_cairo_pdf_surface_emit_image_surface (cairo_pdf_surface_t *surface,
- cairo_surface_pattern_t *pattern,
+ cairo_pdf_pattern_t *pdf_pattern,
cairo_pdf_resource_t *resource,
int *width,
- int *height)
+ int *height,
+ int *origin_x,
+ int *origin_y)
{
cairo_image_surface_t *image;
+ cairo_surface_t *pad_image;
void *image_extra;
cairo_status_t status;
+ cairo_surface_pattern_t *pattern = (cairo_surface_pattern_t *) pdf_pattern->pattern;
+ int x = 0;
+ int y = 0;
+
+ status = _cairo_pdf_surface_emit_jpx_image (surface, pattern->surface,
+ resource, width, height);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
+ status = _cairo_pdf_surface_emit_jpeg_image (surface, pattern->surface,
+ resource, width, height);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra);
- if (status)
+ if (unlikely (status))
goto BAIL;
- status = _cairo_pdf_surface_emit_image (surface, image, resource, pattern->base.filter);
- if (status)
+ pad_image = &image->base;
+ if (cairo_pattern_get_extend (&pattern->base) == CAIRO_EXTEND_PAD) {
+ cairo_box_t box;
+ cairo_rectangle_int_t rect;
+ cairo_surface_pattern_t pad_pattern;
+
+ /* get the operation extents in pattern space */
+ _cairo_box_from_rectangle (&box, &pdf_pattern->extents);
+ _cairo_matrix_transform_bounding_box_fixed (&pattern->base.matrix, &box, NULL);
+ _cairo_box_round_to_rectangle (&box, &rect);
+ x = -rect.x;
+ y = -rect.y;
+
+ pad_image = _cairo_image_surface_create_with_content (pattern->surface->content,
+ rect.width,
+ rect.height);
+ if (pad_image->status) {
+ status = pad_image->status;
+ goto BAIL;
+ }
+
+ _cairo_pattern_init_for_surface (&pad_pattern, &image->base);
+ cairo_matrix_init_translate (&pad_pattern.base.matrix, -x, -y);
+ pad_pattern.base.extend = CAIRO_EXTEND_PAD;
+ status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
+ &pad_pattern.base,
+ NULL,
+ pad_image,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ rect.width,
+ rect.height);
+ _cairo_pattern_fini (&pad_pattern.base);
+ if (unlikely (status))
+ goto BAIL;
+ }
+
+ status = _cairo_pdf_surface_emit_image (surface, (cairo_image_surface_t *)pad_image,
+ resource, pattern->base.filter);
+ if (unlikely (status))
goto BAIL;
- *width = image->width;
- *height = image->height;
+ *width = ((cairo_image_surface_t *)pad_image)->width;
+ *height = ((cairo_image_surface_t *)pad_image)->height;
+ *origin_x = x;
+ *origin_y = y;
+
+ if (pad_image != &image->base)
+ cairo_surface_destroy (pad_image);
BAIL:
_cairo_surface_release_source_image (pattern->surface, image, image_extra);
@@ -1581,7 +1862,7 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface,
int alpha = 0;
status = _cairo_surface_get_extents (meta_surface, &meta_extents);
- if (status)
+ if (unlikely (status))
return status;
old_width = surface->width;
@@ -1598,13 +1879,13 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface,
surface->paginated_mode = CAIRO_PAGINATED_MODE_RENDER;
_cairo_pdf_group_resources_clear (&surface->resources);
status = _cairo_pdf_surface_open_content_stream (surface, TRUE);
- if (status)
+ if (unlikely (status))
return status;
*resource = surface->content;
if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
@@ -1617,11 +1898,11 @@ _cairo_pdf_surface_emit_meta_surface (cairo_pdf_surface_t *surface,
status = _cairo_meta_surface_replay_region (meta_surface, &surface->base,
CAIRO_META_REGION_NATIVE);
assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_surface_set_clip (&surface->base, old_clip);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_close_content_stream (surface);
@@ -1647,6 +1928,8 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
cairo_rectangle_int_t surface_extents;
int pattern_width = 0; /* squelch bogus compiler warning */
int pattern_height = 0; /* squelch bogus compiler warning */
+ int origin_x = 0; /* squelch bogus compiler warning */
+ int origin_y = 0; /* squelch bogus compiler warning */
int bbox_x, bbox_y;
char draw_surface[200];
@@ -1657,33 +1940,34 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
status = _cairo_pdf_surface_emit_meta_surface (surface,
meta_surface,
&pattern_resource);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_surface_get_extents (meta_surface, &pattern_extents);
- if (status)
+ if (unlikely (status))
return status;
pattern_width = pattern_extents.width;
pattern_height = pattern_extents.height;
} else {
status = _cairo_pdf_surface_emit_image_surface (surface,
- pattern,
+ pdf_pattern,
&pattern_resource,
&pattern_width,
- &pattern_height);
- if (status)
+ &pattern_height,
+ &origin_x,
+ &origin_y);
+ if (unlikely (status))
return status;
}
status = _cairo_surface_get_extents (&surface->base, &surface_extents);
- if (status)
+ if (unlikely (status))
return status;
bbox_x = pattern_width;
bbox_y = pattern_height;
switch (extend) {
- /* We implement EXTEND_PAD like EXTEND_NONE for now */
case CAIRO_EXTEND_PAD:
case CAIRO_EXTEND_NONE:
{
@@ -1767,6 +2051,7 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
cairo_matrix_translate (&pdf_p2d, 0.0, surface_extents.height);
cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &pdf_p2d);
+ cairo_matrix_translate (&pdf_p2d, -origin_x, -origin_y);
cairo_matrix_translate (&pdf_p2d, 0.0, pattern_height);
cairo_matrix_scale (&pdf_p2d, 1.0, -1.0);
@@ -1789,7 +2074,7 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
pdf_p2d.x0, pdf_p2d.y0,
pattern_resource.id,
pattern_resource.id);
- if (status)
+ if (unlikely (status))
return status;
if (_cairo_surface_is_meta (pattern->surface)) {
@@ -1827,7 +2112,7 @@ _cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface,
}
status = _cairo_pdf_surface_close_stream (surface);
- if (status)
+ if (unlikely (status))
return status;
return _cairo_output_stream_get_status (surface->output);
@@ -1959,14 +2244,14 @@ _cairo_pdf_surface_emit_stitched_colorgradient (cairo_pdf_surface_t *surface,
&stops[i],
&stops[i+1],
&stops[i].resource);
- if (status)
+ if (unlikely (status))
return status;
} else {
status = cairo_pdf_surface_emit_rgb_linear_function (surface,
&stops[i],
&stops[i+1],
&stops[i].resource);
- if (status)
+ if (unlikely (status))
return status;
}
}
@@ -2048,7 +2333,7 @@ _cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface,
alpha_function->id = 0;
allstops = _cairo_malloc_ab ((pattern->n_stops + 2), sizeof (cairo_pdf_color_stop_t));
- if (allstops == NULL)
+ if (unlikely (allstops == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
stops = &allstops[1];
@@ -2095,7 +2380,7 @@ _cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface,
&stops[0],
&stops[1],
color_function);
- if (status)
+ if (unlikely (status))
goto BAIL;
if (emit_alpha) {
@@ -2103,7 +2388,7 @@ _cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface,
&stops[0],
&stops[1],
alpha_function);
- if (status)
+ if (unlikely (status))
goto BAIL;
}
} else {
@@ -2114,7 +2399,7 @@ _cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface,
stops,
FALSE,
color_function);
- if (status)
+ if (unlikely (status))
goto BAIL;
if (emit_alpha) {
@@ -2123,7 +2408,7 @@ _cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface,
stops,
TRUE,
alpha_function);
- if (status)
+ if (unlikely (status))
goto BAIL;
}
}
@@ -2225,7 +2510,7 @@ cairo_pdf_surface_emit_transparency_group (cairo_pdf_surface_t *surface,
surface->height,
gradient_mask.id,
gradient_mask.id);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
@@ -2240,7 +2525,7 @@ cairo_pdf_surface_emit_transparency_group (cairo_pdf_surface_t *surface,
surface->height);
status = _cairo_pdf_surface_close_stream (surface);
- if (status)
+ if (unlikely (status))
return status;
smask_resource = _cairo_pdf_surface_new_object (surface);
@@ -2363,7 +2648,7 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface,
&pattern->base,
&color_function,
&alpha_function);
- if (status)
+ if (unlikely (status))
return status;
if (pattern->base.base.extend == CAIRO_EXTEND_REPEAT ||
@@ -2373,7 +2658,7 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface,
&color_function,
repeat_begin,
repeat_end);
- if (status)
+ if (unlikely (status))
return status;
if (alpha_function.id != 0) {
@@ -2382,7 +2667,7 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface,
&alpha_function,
repeat_begin,
repeat_end);
- if (status)
+ if (unlikely (status))
return status;
}
}
@@ -2462,13 +2747,13 @@ _cairo_pdf_surface_emit_linear_pattern (cairo_pdf_surface_t *surface,
">>\n"
"endobj\n");
status = _cairo_pdf_surface_add_pattern (surface, mask_resource);
- if (status)
+ if (unlikely (status))
return status;
status = cairo_pdf_surface_emit_transparency_group (surface,
pdf_pattern->gstate_res,
mask_resource);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -2494,7 +2779,7 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t *surface,
&pattern->base,
&color_function,
&alpha_function);
- if (status)
+ if (unlikely (status))
return status;
pat_to_pdf = pattern->base.base.matrix;
@@ -2585,7 +2870,7 @@ _cairo_pdf_surface_emit_radial_pattern (cairo_pdf_surface_t *surface,
status = cairo_pdf_surface_emit_transparency_group (surface,
pdf_pattern->gstate_res,
mask_resource);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -2668,7 +2953,7 @@ _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface,
surface->current_color_is_stroke != is_stroke)
{
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
@@ -2692,11 +2977,11 @@ _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface,
surface->current_color_alpha != solid_color->alpha)
{
status = _cairo_pdf_surface_add_alpha (surface, solid_color->alpha, &alpha);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
@@ -2708,15 +2993,15 @@ _cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface,
surface->current_pattern_is_solid_color = TRUE;
} else {
status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_add_pattern (surface, pattern_res);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
/* fill-stroke calls select_pattern twice. Don't save if the
@@ -2750,7 +3035,7 @@ _cairo_pdf_surface_unselect_pattern (cairo_pdf_surface_t *surface)
if (surface->select_pattern_gstate_saved) {
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output, "Q\n");
@@ -2768,11 +3053,11 @@ _cairo_pdf_surface_show_page (void *abstract_surface)
cairo_int_status_t status;
status = _cairo_pdf_surface_close_content_stream (surface);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_write_page (surface);
- if (status)
+ if (unlikely (status))
return status;
_cairo_pdf_surface_clear (surface);
@@ -2811,7 +3096,7 @@ _cairo_pdf_surface_intersect_clip_path (void *abstract_surface,
if (path == NULL) {
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output, "Q q\n");
@@ -2898,7 +3183,7 @@ _cairo_pdf_surface_emit_unicode_for_glyph (cairo_pdf_surface_t *surface,
if (utf8 && *utf8) {
status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -2940,7 +3225,7 @@ _cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface,
NULL,
surface->compress_content,
NULL);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
@@ -2992,7 +3277,7 @@ _cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface,
}
status = _cairo_pdf_surface_emit_unicode_for_glyph (surface,
font_subset->utf8[i + 1]);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
@@ -3032,14 +3317,14 @@ _cairo_pdf_surface_emit_cff_font (cairo_pdf_surface_t *surface,
NULL,
TRUE,
" /Subtype /CIDFontType0C\n");
- if (status)
+ if (unlikely (status))
return status;
stream = surface->pdf_stream.self;
_cairo_output_stream_write (surface->output,
subset->data, subset->data_length);
status = _cairo_pdf_surface_close_stream (surface);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
@@ -3147,7 +3432,7 @@ _cairo_pdf_surface_emit_cff_font_subset (cairo_pdf_surface_t *surface,
snprintf (name, sizeof name, "CairoFont-%d-%d",
font_subset->font_id, font_subset->subset_id);
status = _cairo_cff_subset_init (&subset, name, font_subset);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_emit_cff_font (surface, font_subset, &subset);
@@ -3168,7 +3453,7 @@ _cairo_pdf_surface_emit_cff_fallback_font (cairo_pdf_surface_t *surface,
snprintf (name, sizeof name, "CairoFont-%d-%d",
font_subset->font_id, font_subset->subset_id);
status = _cairo_cff_fallback_init (&subset, name, font_subset);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_emit_cff_font (surface, font_subset, &subset);
@@ -3205,13 +3490,13 @@ _cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface,
" /Length3 0\n",
subset->header_length,
subset->data_length);
- if (status)
+ if (unlikely (status))
return status;
stream = surface->pdf_stream.self;
_cairo_output_stream_write (surface->output, subset->data, length);
status = _cairo_pdf_surface_close_stream (surface);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_emit_to_unicode_stream (surface,
@@ -3299,7 +3584,7 @@ _cairo_pdf_surface_emit_type1_font_subset (cairo_pdf_surface_t *surface,
snprintf (name, sizeof name, "CairoFont-%d-%d",
font_subset->font_id, font_subset->subset_id);
status = _cairo_type1_subset_init (&subset, name, font_subset, FALSE);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_emit_type1_font (surface, font_subset, &subset);
@@ -3320,7 +3605,7 @@ _cairo_pdf_surface_emit_type1_fallback_font (cairo_pdf_surface_t *surface,
snprintf (name, sizeof name, "CairoFont-%d-%d",
font_subset->font_id, font_subset->subset_id);
status = _cairo_type1_fallback_init_binary (&subset, name, font_subset);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_emit_type1_font (surface, font_subset, &subset);
@@ -3349,7 +3634,7 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
status = _cairo_truetype_subset_init (&subset, font_subset);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_open_stream (surface,
@@ -3357,7 +3642,7 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface,
TRUE,
" /Length1 %lu\n",
subset.data_length);
- if (status) {
+ if (unlikely (status)) {
_cairo_truetype_subset_fini (&subset);
return status;
}
@@ -3366,7 +3651,7 @@ _cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface,
_cairo_output_stream_write (surface->output,
subset.data, subset.data_length);
status = _cairo_pdf_surface_close_stream (surface);
- if (status) {
+ if (unlikely (status)) {
_cairo_truetype_subset_fini (&subset);
return status;
}
@@ -3537,7 +3822,7 @@ _cairo_pdf_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_su
for (i = 0; i < font_subset->num_glyphs; i++) {
status = _cairo_type3_glyph_surface_analyze_glyph (type3_surface,
font_subset->glyphs[i]);
- if (status)
+ if (unlikely (status))
break;
}
@@ -3572,11 +3857,11 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
glyphs = _cairo_malloc_ab (font_subset->num_glyphs, sizeof (cairo_pdf_resource_t));
- if (glyphs == NULL)
+ if (unlikely (glyphs == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
widths = _cairo_malloc_ab (font_subset->num_glyphs, sizeof (double));
- if (widths == NULL) {
+ if (unlikely (widths == NULL)) {
free (glyphs);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -3595,7 +3880,7 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
NULL,
surface->compress_content,
NULL);
- if (status)
+ if (unlikely (status))
break;
glyphs[i] = surface->pdf_stream.self;
@@ -3604,11 +3889,11 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
font_subset->glyphs[i],
&bbox,
&widths[i]);
- if (status)
+ if (unlikely (status))
break;
status = _cairo_pdf_surface_close_stream (surface);
- if (status)
+ if (unlikely (status))
break;
if (i == 0) {
@@ -3628,7 +3913,7 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
}
}
cairo_surface_destroy (type3_surface);
- if (status) {
+ if (unlikely (status)) {
free (glyphs);
free (widths);
return status;
@@ -3787,19 +4072,19 @@ _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface)
status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
_cairo_pdf_surface_analyze_user_font_subset,
surface);
- if (status)
+ if (unlikely (status))
goto BAIL;
status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets,
_cairo_pdf_surface_emit_unscaled_font_subset,
surface);
- if (status)
+ if (unlikely (status))
goto BAIL;
status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
_cairo_pdf_surface_emit_scaled_font_subset,
surface);
- if (status)
+ if (unlikely (status))
goto BAIL;
status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
@@ -3874,35 +4159,36 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface,
/* Create mask group */
status = _cairo_pdf_surface_open_group (surface, NULL);
- if (status)
+ if (unlikely (status))
return status;
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, group->mask, &pattern_res, &gstate_res);
- if (status)
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, group->mask, NULL,
+ &pattern_res, &gstate_res);
+ if (unlikely (status))
return status;
if (gstate_res.id != 0) {
smask_group = _cairo_pdf_surface_create_smask_group (surface);
- if (smask_group == NULL)
+ if (unlikely (smask_group == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
smask_group->operation = PDF_PAINT;
smask_group->source = cairo_pattern_reference (group->mask);
smask_group->source_res = pattern_res;
status = _cairo_pdf_surface_add_smask_group (surface, smask_group);
- if (status) {
+ if (unlikely (status)) {
_cairo_pdf_smask_group_destroy (smask_group);
return status;
}
status = _cairo_pdf_surface_add_smask (surface, gstate_res);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_add_xobject (surface, smask_group->group_res);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
@@ -3911,7 +4197,7 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface,
smask_group->group_res.id);
} else {
status = _cairo_pdf_surface_select_pattern (surface, group->mask, pattern_res, FALSE);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
@@ -3919,45 +4205,46 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface,
surface->width, surface->height);
status = _cairo_pdf_surface_unselect_pattern (surface);
- if (status)
+ if (unlikely (status))
return status;
}
status = _cairo_pdf_surface_close_group (surface, &mask_group);
- if (status)
+ if (unlikely (status))
return status;
/* Create source group */
status = _cairo_pdf_surface_open_group (surface, &group->source_res);
- if (status)
+ if (unlikely (status))
return status;
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, group->source, &pattern_res, &gstate_res);
- if (status)
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, group->source, NULL,
+ &pattern_res, &gstate_res);
+ if (unlikely (status))
return status;
if (gstate_res.id != 0) {
smask_group = _cairo_pdf_surface_create_smask_group (surface);
- if (smask_group == NULL)
+ if (unlikely (smask_group == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
smask_group->operation = PDF_PAINT;
smask_group->source = cairo_pattern_reference (group->source);
smask_group->source_res = pattern_res;
status = _cairo_pdf_surface_add_smask_group (surface, smask_group);
- if (status) {
+ if (unlikely (status)) {
_cairo_pdf_smask_group_destroy (smask_group);
return status;
}
status = _cairo_pdf_surface_add_smask (surface, gstate_res);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_add_xobject (surface, smask_group->group_res);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
@@ -3966,7 +4253,7 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface,
smask_group->group_res.id);
} else {
status = _cairo_pdf_surface_select_pattern (surface, group->source, pattern_res, FALSE);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
@@ -3974,12 +4261,12 @@ _cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface,
surface->width, surface->height);
status = _cairo_pdf_surface_unselect_pattern (surface);
- if (status)
+ if (unlikely (status))
return status;
}
status = _cairo_pdf_surface_close_group (surface, NULL);
- if (status)
+ if (unlikely (status))
return status;
/* Create an smask based on the alpha component of mask_group */
@@ -4032,14 +4319,14 @@ _cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t *surface,
return _cairo_pdf_surface_write_mask_group (surface, group);
status = _cairo_pdf_surface_open_group (surface, &group->group_res);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_select_pattern (surface,
group->source,
group->source_res,
group->operation == PDF_STROKE);
- if (status)
+ if (unlikely (status))
return status;
switch (group->operation) {
@@ -4072,11 +4359,11 @@ _cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t *surface,
group->scaled_font);
break;
}
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_unselect_pattern (surface);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_close_group (surface, NULL);
@@ -4111,14 +4398,14 @@ _cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface
for (; group_index < _cairo_array_num_elements (&surface->smask_groups); group_index++) {
_cairo_array_copy_element (&surface->smask_groups, group_index, &group);
status = _cairo_pdf_surface_write_smask_group (surface, group);
- if (status)
+ if (unlikely (status))
return status;
}
for (; pattern_index < _cairo_array_num_elements (&surface->patterns); pattern_index++) {
_cairo_array_copy_element (&surface->patterns, pattern_index, &pattern);
status = _cairo_pdf_surface_emit_pattern (surface, &pattern);
- if (status)
+ if (unlikely (status))
return status;
}
}
@@ -4136,7 +4423,7 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
_cairo_pdf_group_resources_clear (&surface->resources);
if (surface->has_fallback_images) {
status = _cairo_pdf_surface_open_knockout_group (surface);
- if (status)
+ if (unlikely (status))
return status;
len = _cairo_array_num_elements (&surface->knockout_group);
@@ -4146,34 +4433,34 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
"/x%d Do\n",
res.id);
status = _cairo_pdf_surface_add_xobject (surface, res);
- if (status)
+ if (unlikely (status))
return status;
}
_cairo_output_stream_printf (surface->output,
"/x%d Do\n",
surface->content.id);
status = _cairo_pdf_surface_add_xobject (surface, surface->content);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_close_group (surface, &knockout);
- if (status)
+ if (unlikely (status))
return status;
_cairo_pdf_group_resources_clear (&surface->resources);
status = _cairo_pdf_surface_open_content_stream (surface, FALSE);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
"/x%d Do\n",
knockout.id);
status = _cairo_pdf_surface_add_xobject (surface, knockout);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_close_content_stream (surface);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -4203,11 +4490,11 @@ _cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface)
surface->content_resources.id);
status = _cairo_array_append (&surface->pages, &page);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_write_patterns_and_smask_groups (surface);
- if (status)
+ if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
@@ -4225,7 +4512,7 @@ _cairo_pdf_surface_analyze_surface_pattern_transparency (cairo_pdf_surface_t
status = _cairo_surface_acquire_source_image (pattern->surface,
&image,
&image_extra);
- if (status)
+ if (unlikely (status))
return status;
if (image->base.status)
@@ -4346,8 +4633,12 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface,
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
- if ( _cairo_surface_is_meta (surface_pattern->surface))
- return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
+ if ( _cairo_surface_is_meta (surface_pattern->surface)) {
+ if (pattern->extend == CAIRO_EXTEND_PAD)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ else
+ return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
+ }
}
}
@@ -4406,11 +4697,11 @@ _cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface)
cairo_status_t status;
status = _cairo_pdf_surface_close_content_stream (surface);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_array_append (&surface->knockout_group, &surface->content);
- if (status)
+ if (unlikely (status))
return status;
_cairo_pdf_group_resources_clear (&surface->resources);
@@ -4420,7 +4711,8 @@ _cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface)
static cairo_int_status_t
_cairo_pdf_surface_paint (void *abstract_surface,
cairo_operator_t op,
- const cairo_pattern_t *source)
+ const cairo_pattern_t *source,
+ cairo_rectangle_int_t *extents)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
@@ -4431,7 +4723,7 @@ _cairo_pdf_surface_paint (void *abstract_surface,
return _cairo_pdf_surface_analyze_operation (surface, op, source);
} else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
status = _cairo_pdf_surface_start_fallback (surface);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -4439,40 +4731,41 @@ _cairo_pdf_surface_paint (void *abstract_surface,
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &pattern_res, &gstate_res);
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents,
+ &pattern_res, &gstate_res);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
- if (status)
+ if (unlikely (status))
return status;
if (gstate_res.id != 0) {
group = _cairo_pdf_surface_create_smask_group (surface);
- if (group == NULL)
+ if (unlikely (group == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
group->operation = PDF_PAINT;
status = _cairo_pattern_create_copy (&group->source, source);
- if (status) {
+ if (unlikely (status)) {
_cairo_pdf_smask_group_destroy (group);
return status;
}
group->source_res = pattern_res;
status = _cairo_pdf_surface_add_smask_group (surface, group);
- if (status) {
+ if (unlikely (status)) {
_cairo_pdf_smask_group_destroy (group);
return status;
}
status = _cairo_pdf_surface_add_smask (surface, gstate_res);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
@@ -4481,7 +4774,7 @@ _cairo_pdf_surface_paint (void *abstract_surface,
group->group_res.id);
} else {
status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
@@ -4489,7 +4782,7 @@ _cairo_pdf_surface_paint (void *abstract_surface,
surface->width, surface->height);
status = _cairo_pdf_surface_unselect_pattern (surface);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -4500,7 +4793,8 @@ static cairo_int_status_t
_cairo_pdf_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- const cairo_pattern_t *mask)
+ const cairo_pattern_t *mask,
+ cairo_rectangle_int_t *extents)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_pdf_smask_group_t *group;
@@ -4521,7 +4815,7 @@ _cairo_pdf_surface_mask (void *abstract_surface,
mask_status);
} else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
status = _cairo_pdf_surface_start_fallback (surface);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -4529,17 +4823,17 @@ _cairo_pdf_surface_mask (void *abstract_surface,
assert (_cairo_pdf_surface_operation_supported (surface, op, mask));
group = _cairo_pdf_surface_create_smask_group (surface);
- if (group == NULL)
+ if (unlikely (group == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
group->operation = PDF_MASK;
status = _cairo_pattern_create_copy (&group->source, source);
- if (status) {
+ if (unlikely (status)) {
_cairo_pdf_smask_group_destroy (group);
return status;
}
status = _cairo_pattern_create_copy (&group->mask, mask);
- if (status) {
+ if (unlikely (status)) {
_cairo_pdf_smask_group_destroy (group);
return status;
}
@@ -4550,21 +4844,21 @@ _cairo_pdf_surface_mask (void *abstract_surface,
}
status = _cairo_pdf_surface_add_smask_group (surface, group);
- if (status) {
+ if (unlikely (status)) {
_cairo_pdf_smask_group_destroy (group);
return status;
}
status = _cairo_pdf_surface_add_smask (surface, group->group_res);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_add_xobject (surface, group->source_res);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
@@ -4584,7 +4878,8 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
@@ -4598,26 +4893,27 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &pattern_res, &gstate_res);
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents,
+ &pattern_res, &gstate_res);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
- if (status)
+ if (unlikely (status))
return status;
if (gstate_res.id != 0) {
group = _cairo_pdf_surface_create_smask_group (surface);
- if (group == NULL)
+ if (unlikely (group == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
group->operation = PDF_STROKE;
status = _cairo_pattern_create_copy (&group->source, source);
- if (status) {
+ if (unlikely (status)) {
_cairo_pdf_smask_group_destroy (group);
return status;
}
group->source_res = pattern_res;
status = _cairo_path_fixed_init_copy (&group->path, path);
- if (status) {
+ if (unlikely (status)) {
_cairo_pdf_smask_group_destroy (group);
return status;
}
@@ -4626,21 +4922,21 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
group->ctm = *ctm;
group->ctm_inverse = *ctm_inverse;
status = _cairo_pdf_surface_add_smask_group (surface, group);
- if (status) {
+ if (unlikely (status)) {
_cairo_pdf_smask_group_destroy (group);
return status;
}
status = _cairo_pdf_surface_add_smask (surface, gstate_res);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
@@ -4649,7 +4945,7 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
group->group_res.id);
} else {
status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, TRUE);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_operators_stroke (&surface->pdf_operators,
@@ -4657,11 +4953,11 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
style,
ctm,
ctm_inverse);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_unselect_pattern (surface);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -4675,7 +4971,8 @@ _cairo_pdf_surface_fill (void *abstract_surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
@@ -4686,7 +4983,7 @@ _cairo_pdf_surface_fill (void *abstract_surface,
return _cairo_pdf_surface_analyze_operation (surface, op, source);
} else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) {
status = _cairo_pdf_surface_start_fallback (surface);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -4694,47 +4991,48 @@ _cairo_pdf_surface_fill (void *abstract_surface,
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &pattern_res, &gstate_res);
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents,
+ &pattern_res, &gstate_res);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
- if (status)
+ if (unlikely (status))
return status;
if (gstate_res.id != 0) {
group = _cairo_pdf_surface_create_smask_group (surface);
- if (group == NULL)
+ if (unlikely (group == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
group->operation = PDF_FILL;
status = _cairo_pattern_create_copy (&group->source, source);
- if (status) {
+ if (unlikely (status)) {
_cairo_pdf_smask_group_destroy (group);
return status;
}
group->source_res = pattern_res;
status = _cairo_path_fixed_init_copy (&group->path, path);
- if (status) {
+ if (unlikely (status)) {
_cairo_pdf_smask_group_destroy (group);
return status;
}
group->fill_rule = fill_rule;
status = _cairo_pdf_surface_add_smask_group (surface, group);
- if (status) {
+ if (unlikely (status)) {
_cairo_pdf_smask_group_destroy (group);
return status;
}
status = _cairo_pdf_surface_add_smask (surface, gstate_res);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
@@ -4743,17 +5041,17 @@ _cairo_pdf_surface_fill (void *abstract_surface,
group->group_res.id);
} else {
status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_operators_fill (&surface->pdf_operators,
path,
fill_rule);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_unselect_pattern (surface);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -4774,7 +5072,8 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
cairo_matrix_t *stroke_ctm,
cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
- cairo_antialias_t stroke_antialias)
+ cairo_antialias_t stroke_antialias,
+ cairo_rectangle_int_t *extents)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
@@ -4802,9 +5101,10 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
fill_pattern_res.id = 0;
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface, fill_source,
+ extents,
&fill_pattern_res,
&gstate_res);
- if (status)
+ if (unlikely (status))
return status;
assert (gstate_res.id == 0);
@@ -4813,9 +5113,10 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface,
stroke_source,
+ extents,
&stroke_pattern_res,
&gstate_res);
- if (status)
+ if (unlikely (status))
return status;
assert (gstate_res.id == 0);
@@ -4824,12 +5125,12 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
* select both at the same time */
status = _cairo_pdf_surface_select_pattern (surface, fill_source,
fill_pattern_res, FALSE);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_select_pattern (surface, stroke_source,
stroke_pattern_res, TRUE);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_operators_fill_stroke (&surface->pdf_operators,
@@ -4838,11 +5139,11 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
stroke_style,
stroke_ctm,
stroke_ctm_inverse);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_unselect_pattern (surface);
- if (status)
+ if (unlikely (status))
return status;
return _cairo_output_stream_get_status (surface->output);
@@ -4865,7 +5166,8 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
- cairo_scaled_font_t *scaled_font)
+ cairo_scaled_font_t *scaled_font,
+ cairo_rectangle_int_t *extents)
{
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
@@ -4879,20 +5181,21 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &pattern_res, &gstate_res);
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, source, extents,
+ &pattern_res, &gstate_res);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
- if (status)
+ if (unlikely (status))
return status;
if (gstate_res.id != 0) {
group = _cairo_pdf_surface_create_smask_group (surface);
- if (group == NULL)
+ if (unlikely (group == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
group->operation = PDF_SHOW_GLYPHS;
status = _cairo_pattern_create_copy (&group->source, source);
- if (status) {
+ if (unlikely (status)) {
_cairo_pdf_smask_group_destroy (group);
return status;
}
@@ -4900,7 +5203,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
if (utf8_len) {
group->utf8 = malloc (utf8_len);
- if (group->utf8 == NULL) {
+ if (unlikely (group->utf8 == NULL)) {
_cairo_pdf_smask_group_destroy (group);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -4910,7 +5213,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
if (num_glyphs) {
group->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
- if (group->glyphs == NULL) {
+ if (unlikely (group->glyphs == NULL)) {
_cairo_pdf_smask_group_destroy (group);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -4920,7 +5223,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
if (num_clusters) {
group->clusters = _cairo_malloc_ab (num_clusters, sizeof (cairo_text_cluster_t));
- if (group->clusters == NULL) {
+ if (unlikely (group->clusters == NULL)) {
_cairo_pdf_smask_group_destroy (group);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -4930,21 +5233,21 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
group->scaled_font = cairo_scaled_font_reference (scaled_font);
status = _cairo_pdf_surface_add_smask_group (surface, group);
- if (status) {
+ if (unlikely (status)) {
_cairo_pdf_smask_group_destroy (group);
return status;
}
status = _cairo_pdf_surface_add_smask (surface, gstate_res);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_add_xobject (surface, group->group_res);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->output,
@@ -4953,7 +5256,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
group->group_res.id);
} else {
status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE);
- if (status)
+ if (unlikely (status))
return status;
/* Each call to show_glyphs() with a transclucent pattern must
@@ -4962,7 +5265,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
* each other. */
if (! _cairo_pattern_is_opaque (source)) {
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -4972,11 +5275,11 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
clusters, num_clusters,
cluster_flags,
scaled_font);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_surface_unselect_pattern (surface);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -5005,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-pdf.h b/src/cairo-pdf.h
index 1a066b3a..294f36d2 100644
--- a/src/cairo-pdf.h
+++ b/src/cairo-pdf.h
@@ -43,6 +43,19 @@
CAIRO_BEGIN_DECLS
+/**
+ * cairo_pdf_version_t:
+ * @CAIRO_PDF_VERSION_1_4: The version 1.4 of the PDF specification.
+ * @CAIRO_PDF_VERSION_1_5: The version 1.5 of the PDF specification.
+ *
+ * #cairo_pdf_version_t is used to describe the version number of the PDF
+ * specification that a generated PDF file will conform to.
+ */
+typedef enum _cairo_pdf_version {
+ CAIRO_PDF_VERSION_1_4,
+ CAIRO_PDF_VERSION_1_5
+} cairo_pdf_version_t;
+
cairo_public cairo_surface_t *
cairo_pdf_surface_create (const char *filename,
double width_in_points,
@@ -55,6 +68,17 @@ cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func,
double height_in_points);
cairo_public void
+cairo_pdf_surface_restrict_to_version (cairo_surface_t *surface,
+ cairo_pdf_version_t version);
+
+cairo_public void
+cairo_pdf_get_versions (cairo_pdf_version_t const **versions,
+ int *num_versions);
+
+cairo_public const char *
+cairo_pdf_version_to_string (cairo_pdf_version_t version);
+
+cairo_public void
cairo_pdf_surface_set_size (cairo_surface_t *surface,
double width_in_points,
double height_in_points);
diff --git a/src/cairo-pen.c b/src/cairo-pen.c
index 425b3b96..4158f175 100644
--- a/src/cairo-pen.c
+++ b/src/cairo-pen.c
@@ -1,6 +1,7 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
+ * Copyright © 2008 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -32,6 +33,7 @@
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
+ * Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
@@ -42,9 +44,6 @@ _cairo_pen_vertices_needed (double tolerance, double radius, cairo_matrix_t *mat
static void
_cairo_pen_compute_slopes (cairo_pen_t *pen);
-static void
-_cairo_pen_stroke_spline_half (cairo_pen_t *pen, cairo_spline_t *spline, cairo_direction_t dir, cairo_polygon_t *polygon);
-
cairo_status_t
_cairo_pen_init (cairo_pen_t *pen,
double radius,
@@ -66,7 +65,7 @@ _cairo_pen_init (cairo_pen_t *pen,
if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) {
pen->vertices = _cairo_malloc_ab (pen->num_vertices,
sizeof (cairo_pen_vertex_t));
- if (pen->vertices == NULL)
+ if (unlikely (pen->vertices == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} else {
pen->vertices = pen->vertices_embedded;
@@ -104,7 +103,7 @@ _cairo_pen_fini (cairo_pen_t *pen)
}
cairo_status_t
-_cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
+_cairo_pen_init_copy (cairo_pen_t *pen, const cairo_pen_t *other)
{
*pen = *other;
@@ -113,7 +112,7 @@ _cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) {
pen->vertices = _cairo_malloc_ab (pen->num_vertices,
sizeof (cairo_pen_vertex_t));
- if (pen->vertices == NULL)
+ if (unlikely (pen->vertices == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -140,7 +139,7 @@ _cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points)
if (pen->vertices == pen->vertices_embedded) {
vertices = _cairo_malloc_ab (num_vertices,
sizeof (cairo_pen_vertex_t));
- if (vertices == NULL)
+ if (unlikely (vertices == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (vertices, pen->vertices,
@@ -149,7 +148,7 @@ _cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points)
vertices = _cairo_realloc_ab (pen->vertices,
num_vertices,
sizeof (cairo_pen_vertex_t));
- if (vertices == NULL)
+ if (unlikely (vertices == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -163,7 +162,7 @@ _cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points)
pen->vertices[pen->num_vertices-num_points+i].point = point[i];
status = _cairo_hull_compute (pen->vertices, &pen->num_vertices);
- if (status)
+ if (unlikely (status))
return status;
_cairo_pen_compute_slopes (pen);
@@ -323,10 +322,9 @@ _cairo_pen_compute_slopes (cairo_pen_t *pen)
* pen's "extra points" from the spline's initial and final slopes are
* properly found when beginning the spline stroking.]
*/
-void
-_cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen,
- cairo_slope_t *slope,
- int *active)
+int
+_cairo_pen_find_active_cw_vertex_index (const cairo_pen_t *pen,
+ const cairo_slope_t *slope)
{
int i;
@@ -344,7 +342,7 @@ _cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen,
if (i == pen->num_vertices)
i = 0;
- *active = i;
+ return i;
}
/* Find active pen vertex for counterclockwise edge of stroke at the given slope.
@@ -352,13 +350,12 @@ _cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen,
* Note: See the comments for _cairo_pen_find_active_cw_vertex_index
* for some details about the strictness of the inequalities here.
*/
-void
-_cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen,
- cairo_slope_t *slope,
- int *active)
+int
+_cairo_pen_find_active_ccw_vertex_index (const cairo_pen_t *pen,
+ const cairo_slope_t *slope)
{
- int i;
cairo_slope_t slope_reverse;
+ int i;
slope_reverse = *slope;
slope_reverse.dx = -slope_reverse.dx;
@@ -378,56 +375,26 @@ _cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen,
if (i < 0)
i = pen->num_vertices - 1;
- *active = i;
+ return i;
}
-static void
-_cairo_pen_stroke_spline_half (cairo_pen_t *pen,
- cairo_spline_t *spline,
- cairo_direction_t dir,
- cairo_polygon_t *polygon)
+static int
+_cairo_pen_stroke_spline_add_convolved_point (cairo_pen_stroke_spline_t *stroker,
+ const cairo_point_t *last_point,
+ const cairo_slope_t *slope,
+ cairo_point_t *last_hull_point,
+ int active,
+ int step)
{
- int i;
- int start, stop, step;
- int active = 0;
- cairo_point_t hull_point;
- cairo_slope_t slope, initial_slope, final_slope;
- cairo_point_t *point = spline->points;
- int num_points = spline->num_points;
-
- if (dir == CAIRO_DIRECTION_FORWARD) {
- start = 0;
- stop = num_points;
- step = 1;
- initial_slope = spline->initial_slope;
- final_slope = spline->final_slope;
- } else {
- start = num_points - 1;
- stop = -1;
- step = -1;
- initial_slope = spline->final_slope;
- initial_slope.dx = -initial_slope.dx;
- initial_slope.dy = -initial_slope.dy;
- final_slope = spline->initial_slope;
- final_slope.dx = -final_slope.dx;
- final_slope.dy = -final_slope.dy;
- }
-
- _cairo_pen_find_active_cw_vertex_index (pen,
- &initial_slope,
- &active);
+ do {
+ cairo_point_t hull_point;
- i = start;
- while (i != stop) {
- hull_point.x = point[i].x + pen->vertices[active].point.x;
- hull_point.y = point[i].y + pen->vertices[active].point.y;
-
- _cairo_polygon_line_to (polygon, &hull_point);
-
- if (i + step == stop)
- slope = final_slope;
- else
- _cairo_slope_init (&slope, &point[i], &point[i+step]);
+ hull_point.x = last_point->x + stroker->pen.vertices[active].point.x;
+ hull_point.y = last_point->y + stroker->pen.vertices[active].point.y;
+ _cairo_polygon_add_edge (&stroker->polygon,
+ last_hull_point, &hull_point,
+ step);
+ *last_hull_point = hull_point;
/* The strict inequalities here ensure that if a spline slope
* compares identically with either of the slopes of the
@@ -439,53 +406,164 @@ _cairo_pen_stroke_spline_half (cairo_pen_t *pen,
* consider it unequal and reject. This is due to the inherent
* ambiguity when comparing slopes that differ by exactly
* pi. */
- if (_cairo_slope_compare (&slope, &pen->vertices[active].slope_ccw) > 0) {
- if (++active == pen->num_vertices)
+ if (_cairo_slope_compare (slope,
+ &stroker->pen.vertices[active].slope_ccw) > 0)
+ {
+ if (++active == stroker->pen.num_vertices)
active = 0;
- } else if (_cairo_slope_compare (&slope, &pen->vertices[active].slope_cw) < 0) {
+ }
+ else if (_cairo_slope_compare (slope,
+ &stroker->pen.vertices[active].slope_cw) < 0)
+ {
if (--active == -1)
- active = pen->num_vertices - 1;
- } else {
- i += step;
+ active = stroker->pen.num_vertices - 1;
}
- }
+ else
+ {
+ return active;
+ }
+ } while (TRUE);
}
+
/* Compute outline of a given spline using the pen.
- The trapezoids needed to fill that outline will be added to traps
-*/
+ * The trapezoids needed to fill that outline will be added to traps
+ */
cairo_status_t
-_cairo_pen_stroke_spline (cairo_pen_t *pen,
- cairo_spline_t *spline,
- double tolerance,
- cairo_traps_t *traps)
+_cairo_pen_stroke_spline (cairo_pen_stroke_spline_t *stroker,
+ double tolerance,
+ cairo_traps_t *traps)
{
cairo_status_t status;
- cairo_polygon_t polygon;
+ cairo_slope_t slope;
/* If the line width is so small that the pen is reduced to a
single point, then we have nothing to do. */
- if (pen->num_vertices <= 1)
+ if (stroker->pen.num_vertices <= 1)
return CAIRO_STATUS_SUCCESS;
- _cairo_polygon_init (&polygon);
-
- status = _cairo_spline_decompose (spline, tolerance);
- if (status)
+ /* open the polygon */
+ slope = stroker->spline.initial_slope;
+ stroker->forward_vertex =
+ _cairo_pen_find_active_cw_vertex_index (&stroker->pen, &slope);
+ stroker->forward_hull_point.x = stroker->last_point.x +
+ stroker->pen.vertices[stroker->forward_vertex].point.x;
+ stroker->forward_hull_point.y = stroker->last_point.y +
+ stroker->pen.vertices[stroker->forward_vertex].point.y;
+
+ slope.dx = -slope.dx;
+ slope.dy = -slope.dy;
+ stroker->backward_vertex =
+ _cairo_pen_find_active_cw_vertex_index (&stroker->pen, &slope);
+ stroker->backward_hull_point.x = stroker->last_point.x +
+ stroker->pen.vertices[stroker->backward_vertex].point.x;
+ stroker->backward_hull_point.y = stroker->last_point.y +
+ stroker->pen.vertices[stroker->backward_vertex].point.y;
+
+ _cairo_polygon_add_edge (&stroker->polygon,
+ &stroker->backward_hull_point,
+ &stroker->forward_hull_point,
+ 1);
+
+ _cairo_spline_decompose (&stroker->spline, tolerance);
+
+ /* close the polygon */
+ slope = stroker->spline.final_slope;
+ _cairo_pen_stroke_spline_add_convolved_point (stroker,
+ &stroker->last_point,
+ &slope,
+ &stroker->forward_hull_point,
+ stroker->forward_vertex,
+ 1);
+
+ slope.dx = -slope.dx;
+ slope.dy = -slope.dy;
+ _cairo_pen_stroke_spline_add_convolved_point (stroker,
+ &stroker->last_point,
+ &slope,
+ &stroker->backward_hull_point,
+ stroker->backward_vertex,
+ -1);
+
+ _cairo_polygon_add_edge (&stroker->polygon,
+ &stroker->forward_hull_point,
+ &stroker->backward_hull_point,
+ 1);
+
+ status = _cairo_polygon_status (&stroker->polygon);
+ if (unlikely (status))
goto BAIL;
- _cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_FORWARD, &polygon);
+ status = _cairo_bentley_ottmann_tessellate_polygon (traps,
+ &stroker->polygon,
+ CAIRO_FILL_RULE_WINDING);
+BAIL:
- _cairo_pen_stroke_spline_half (pen, spline, CAIRO_DIRECTION_REVERSE, &polygon);
+ return status;
+}
- _cairo_polygon_close (&polygon);
- status = _cairo_polygon_status (&polygon);
- if (status)
- goto BAIL;
+static void
+_cairo_pen_stroke_spline_add_point (cairo_pen_stroke_spline_t *stroker,
+ const cairo_point_t *point)
+{
+ cairo_slope_t slope;
+
+ _cairo_slope_init (&slope, &stroker->last_point, point);
+ stroker->forward_vertex =
+ _cairo_pen_stroke_spline_add_convolved_point (stroker,
+ &stroker->last_point,
+ &slope,
+ &stroker->forward_hull_point,
+ stroker->forward_vertex,
+ 1);
+
+ slope.dx = -slope.dx;
+ slope.dy = -slope.dy;
+ stroker->backward_vertex =
+ _cairo_pen_stroke_spline_add_convolved_point (stroker,
+ &stroker->last_point,
+ &slope,
+ &stroker->backward_hull_point,
+ stroker->backward_vertex,
+ -1);
+ stroker->last_point = *point;
+}
- status = _cairo_bentley_ottmann_tessellate_polygon (traps, &polygon, CAIRO_FILL_RULE_WINDING);
-BAIL:
- _cairo_polygon_fini (&polygon);
+cairo_int_status_t
+_cairo_pen_stroke_spline_init (cairo_pen_stroke_spline_t *stroker,
+ const cairo_pen_t *pen,
+ const cairo_point_t *a,
+ const cairo_point_t *b,
+ const cairo_point_t *c,
+ const cairo_point_t *d)
+{
+ cairo_int_status_t status;
- return status;
+ if (! _cairo_spline_init (&stroker->spline,
+ (cairo_add_point_func_t) _cairo_pen_stroke_spline_add_point,
+ stroker,
+ a, b, c, d))
+ {
+ return CAIRO_INT_STATUS_DEGENERATE;
+ }
+
+ status = _cairo_pen_init_copy (&stroker->pen, pen);
+ if (unlikely (status)) {
+ _cairo_spline_fini (&stroker->spline);
+ return status;
+ }
+
+ _cairo_polygon_init (&stroker->polygon);
+
+ stroker->last_point = *a;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_pen_stroke_spline_fini (cairo_pen_stroke_spline_t *stroker)
+{
+ _cairo_polygon_fini (&stroker->polygon);
+ _cairo_spline_fini (&stroker->spline);
+ _cairo_pen_fini (&stroker->pen);
}
diff --git a/src/cairo-png.c b/src/cairo-png.c
index 06e7cb55..fd16c4dc 100644
--- a/src/cairo-png.c
+++ b/src/cairo-png.c
@@ -37,10 +37,19 @@
*/
#include "cairoint.h"
+#include "cairo-output-stream-private.h"
+#include <stdio.h>
#include <errno.h>
#include <png.h>
+struct png_read_closure_t {
+ cairo_read_func_t read_func;
+ void *closure;
+ cairo_output_stream_t *png_data;
+};
+
+
/* Unpremultiplies data and converts native endian ARGB => RGBA bytes */
static void
unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
@@ -139,6 +148,8 @@ write_png (cairo_surface_t *surface,
png_info *info;
png_byte **volatile rows = NULL;
png_color_16 white;
+ const unsigned char *mime_data;
+ unsigned int mime_data_length;
int png_color_type;
int depth;
@@ -148,7 +159,7 @@ write_png (cairo_surface_t *surface,
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
- else if (status)
+ else if (unlikely (status))
return status;
/* PNG complains about "Image width or height is zero in IHDR" */
@@ -158,7 +169,7 @@ write_png (cairo_surface_t *surface,
}
rows = _cairo_malloc_ab (image->height, sizeof (png_byte*));
- if (rows == NULL) {
+ if (unlikely (rows == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL1;
}
@@ -169,13 +180,13 @@ write_png (cairo_surface_t *surface,
png = png_create_write_struct (PNG_LIBPNG_VER_STRING, &status,
png_simple_error_callback,
png_simple_warning_callback);
- if (png == NULL) {
+ if (unlikely (png == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL2;
}
info = png_create_info_struct (png);
- if (info == NULL) {
+ if (unlikely (info == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL3;
}
@@ -187,10 +198,25 @@ write_png (cairo_surface_t *surface,
png_set_write_fn (png, closure, write_func, png_simple_output_flush_fn);
+ /* XXX This is very questionable.
+ * This breaks the read_from_png(); draw(); write_to_png(); cycle, but
+ * that is affected by mime-data in general. OTOH, by using mime-data
+ * here we are consistent with the other backends.
+ */
+ cairo_surface_get_mime_data (surface, CAIRO_MIME_TYPE_PNG,
+ &mime_data, &mime_data_length);
+ if (mime_data != NULL) {
+ write_func (png, (png_bytep) mime_data, mime_data_length);
+ goto BAIL3;
+ }
+
switch (image->format) {
case CAIRO_FORMAT_ARGB32:
depth = 8;
- png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ if (_cairo_image_analyze_transparency (image) == CAIRO_IMAGE_IS_OPAQUE)
+ png_color_type = PNG_COLOR_TYPE_RGB;
+ else
+ png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
break;
case CAIRO_FORMAT_RGB24:
depth = 8;
@@ -237,12 +263,12 @@ write_png (cairo_surface_t *surface,
*/
png_write_info (png, info);
- if (image->format == CAIRO_FORMAT_ARGB32)
+ if (png_color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
png_set_write_user_transform_fn (png, unpremultiply_data);
- else if (image->format == CAIRO_FORMAT_RGB24)
+ } else if (png_color_type == PNG_COLOR_TYPE_RGB) {
png_set_write_user_transform_fn (png, convert_data_to_bytes);
- if (image->format == CAIRO_FORMAT_RGB24)
png_set_filler (png, 0, PNG_FILLER_AFTER);
+ }
png_write_image (png, rows);
png_write_end (png, info);
@@ -335,7 +361,7 @@ stream_write_func (png_structp png, png_bytep data, png_size_t size)
png_closure = png_get_io_ptr (png);
status = png_closure->write_func (png_closure->closure, data, size);
- if (status) {
+ if (unlikely (status)) {
cairo_status_t *error = png_get_error_ptr (png);
if (*error == CAIRO_STATUS_SUCCESS)
*error = status;
@@ -433,9 +459,45 @@ convert_bytes_to_data (png_structp png, png_row_infop row_info, png_bytep data)
}
}
+static cairo_status_t
+stdio_read_func (void *closure, unsigned char *data, unsigned int size)
+{
+ FILE *file = closure;
+
+ while (size) {
+ size_t ret;
+
+ ret = fread (data, 1, size, file);
+ size -= ret;
+ data += ret;
+
+ if (size && (feof (file) || ferror (file)))
+ return _cairo_error (CAIRO_STATUS_READ_ERROR);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+stream_read_func (png_structp png, png_bytep data, png_size_t size)
+{
+ cairo_status_t status;
+ struct png_read_closure_t *png_closure;
+
+ png_closure = png_get_io_ptr (png);
+ status = png_closure->read_func (png_closure->closure, data, size);
+ if (unlikely (status)) {
+ cairo_status_t *error = png_get_error_ptr (png);
+ if (*error == CAIRO_STATUS_SUCCESS)
+ *error = status;
+ png_error (png, NULL);
+ }
+
+ _cairo_output_stream_write (png_closure->png_data, data, size);
+}
+
static cairo_surface_t *
-read_png (png_rw_ptr read_func,
- void *closure)
+read_png (struct png_read_closure_t *png_closure)
{
cairo_surface_t *surface;
png_struct *png = NULL;
@@ -447,24 +509,28 @@ read_png (png_rw_ptr read_func,
unsigned int i;
cairo_format_t format;
cairo_status_t status;
+ unsigned char *mime_data;
+ unsigned int mime_data_length;
+
+ png_closure->png_data = _cairo_memory_stream_create ();
/* XXX: Perhaps we'll want some other error handlers? */
png = png_create_read_struct (PNG_LIBPNG_VER_STRING,
&status,
png_simple_error_callback,
png_simple_warning_callback);
- if (png == NULL) {
+ if (unlikely (png == NULL)) {
surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
goto BAIL;
}
info = png_create_info_struct (png);
- if (info == NULL) {
+ if (unlikely (info == NULL)) {
surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
goto BAIL;
}
- png_set_read_fn (png, closure, read_func);
+ png_set_read_fn (png, png_closure, stream_read_func);
status = CAIRO_STATUS_SUCCESS;
#ifdef PNG_SETJMP_SUPPORTED
@@ -479,7 +545,7 @@ read_png (png_rw_ptr read_func,
png_get_IHDR (png, info,
&png_width, &png_height, &depth,
&color_type, &interlace, NULL, NULL);
- if (status) { /* catch any early warnings */
+ if (unlikely (status)) { /* catch any early warnings */
surface = _cairo_surface_create_in_error (status);
goto BAIL;
}
@@ -555,13 +621,13 @@ read_png (png_rw_ptr read_func,
}
data = _cairo_malloc_ab (png_height, stride);
- if (data == NULL) {
+ if (unlikely (data == NULL)) {
surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
goto BAIL;
}
row_pointers = _cairo_malloc_ab (png_height, sizeof (char *));
- if (row_pointers == NULL) {
+ if (unlikely (row_pointers == NULL)) {
surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
goto BAIL;
}
@@ -572,7 +638,7 @@ read_png (png_rw_ptr read_func,
png_read_image (png, row_pointers);
png_read_end (png, info);
- if (status) { /* catch any late warnings - probably hit an error already */
+ if (unlikely (status)) { /* catch any late warnings - probably hit an error already */
surface = _cairo_surface_create_in_error (status);
goto BAIL;
}
@@ -586,34 +652,43 @@ read_png (png_rw_ptr read_func,
_cairo_image_surface_assume_ownership_of_data ((cairo_image_surface_t*)surface);
data = NULL;
+ status = _cairo_memory_stream_destroy (png_closure->png_data,
+ &mime_data,
+ &mime_data_length);
+ if (unlikely (status)) {
+ cairo_surface_destroy (surface);
+ surface = _cairo_surface_create_in_error (status);
+ goto BAIL;
+ }
+ png_closure->png_data = NULL;
+
+ status = cairo_surface_set_mime_data (surface,
+ CAIRO_MIME_TYPE_PNG,
+ mime_data,
+ mime_data_length,
+ free,
+ mime_data);
+ if (unlikely (status)) {
+ free (mime_data);
+ cairo_surface_destroy (surface);
+ surface = _cairo_surface_create_in_error (status);
+ goto BAIL;
+ }
+
BAIL:
- if (row_pointers)
+ if (row_pointers != NULL)
free (row_pointers);
- if (data)
+ if (data != NULL)
free (data);
- if (png)
+ if (png != NULL)
png_destroy_read_struct (&png, &info, NULL);
+ if (png_closure->png_data != NULL) {
+ cairo_status_t status_ignored;
- return surface;
-}
-
-static void
-stdio_read_func (png_structp png, png_bytep data, png_size_t size)
-{
- FILE *fp;
-
- fp = png_get_io_ptr (png);
- while (size) {
- size_t ret = fread (data, 1, size, fp);
- size -= ret;
- data += ret;
- if (size && (feof (fp) || ferror (fp))) {
- cairo_status_t *error = png_get_error_ptr (png);
- if (*error == CAIRO_STATUS_SUCCESS)
- *error = _cairo_error (CAIRO_STATUS_READ_ERROR);
- png_error (png, NULL);
- }
+ status_ignored = _cairo_output_stream_destroy (png_closure->png_data);
}
+
+ return surface;
}
/**
@@ -635,11 +710,11 @@ stdio_read_func (png_structp png, png_bytep data, png_size_t size)
cairo_surface_t *
cairo_image_surface_create_from_png (const char *filename)
{
- FILE *fp;
+ struct png_read_closure_t png_closure;
cairo_surface_t *surface;
- fp = fopen (filename, "rb");
- if (fp == NULL) {
+ png_closure.closure = fopen (filename, "rb");
+ if (png_closure.closure == NULL) {
cairo_status_t status;
switch (errno) {
case ENOMEM:
@@ -655,32 +730,13 @@ cairo_image_surface_create_from_png (const char *filename)
return _cairo_surface_create_in_error (status);
}
- surface = read_png (stdio_read_func, fp);
-
- fclose (fp);
+ png_closure.read_func = stdio_read_func;
- return surface;
-}
+ surface = read_png (&png_closure);
-struct png_read_closure_t {
- cairo_read_func_t read_func;
- void *closure;
-};
-
-static void
-stream_read_func (png_structp png, png_bytep data, png_size_t size)
-{
- cairo_status_t status;
- struct png_read_closure_t *png_closure;
+ fclose (png_closure.closure);
- png_closure = png_get_io_ptr (png);
- status = png_closure->read_func (png_closure->closure, data, size);
- if (status) {
- cairo_status_t *error = png_get_error_ptr (png);
- if (*error == CAIRO_STATUS_SUCCESS)
- *error = status;
- png_error (png, NULL);
- }
+ return surface;
}
/**
@@ -704,5 +760,5 @@ cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func,
png_closure.read_func = read_func;
png_closure.closure = closure;
- return read_png (stream_read_func, &png_closure);
+ return read_png (&png_closure);
}
diff --git a/src/cairo-polygon.c b/src/cairo-polygon.c
index 1392bfa1..0b0fa991 100644
--- a/src/cairo-polygon.c
+++ b/src/cairo-polygon.c
@@ -73,7 +73,7 @@ _cairo_polygon_grow (cairo_polygon_t *polygon)
new_size, sizeof (cairo_edge_t));
}
- if (new_edges == NULL) {
+ if (unlikely (new_edges == NULL)) {
polygon->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return FALSE;
}
@@ -84,16 +84,17 @@ _cairo_polygon_grow (cairo_polygon_t *polygon)
return TRUE;
}
-static void
+void
_cairo_polygon_add_edge (cairo_polygon_t *polygon,
const cairo_point_t *p1,
- const cairo_point_t *p2)
+ const cairo_point_t *p2,
+ int dir)
{
cairo_edge_t *edge;
/* drop horizontal edges */
if (p1->y == p2->y)
- goto DONE;
+ return;
if (polygon->num_edges == polygon->edges_size) {
if (! _cairo_polygon_grow (polygon))
@@ -104,15 +105,12 @@ _cairo_polygon_add_edge (cairo_polygon_t *polygon,
if (p1->y < p2->y) {
edge->edge.p1 = *p1;
edge->edge.p2 = *p2;
- edge->clockWise = 1;
+ edge->dir = dir;
} else {
edge->edge.p1 = *p2;
edge->edge.p2 = *p1;
- edge->clockWise = 0;
+ edge->dir = -dir;
}
-
- DONE:
- _cairo_polygon_move_to (polygon, p2);
}
void
@@ -131,9 +129,9 @@ _cairo_polygon_line_to (cairo_polygon_t *polygon,
const cairo_point_t *point)
{
if (polygon->has_current_point)
- _cairo_polygon_add_edge (polygon, &polygon->current_point, point);
- else
- _cairo_polygon_move_to (polygon, point);
+ _cairo_polygon_add_edge (polygon, &polygon->current_point, point, 1);
+
+ _cairo_polygon_move_to (polygon, point);
}
void
@@ -142,7 +140,8 @@ _cairo_polygon_close (cairo_polygon_t *polygon)
if (polygon->has_current_point) {
_cairo_polygon_add_edge (polygon,
&polygon->current_point,
- &polygon->first_point);
+ &polygon->first_point,
+ 1);
polygon->has_current_point = FALSE;
}
diff --git a/src/cairo-ps-surface-private.h b/src/cairo-ps-surface-private.h
index e78833d0..98d2750a 100644
--- a/src/cairo-ps-surface-private.h
+++ b/src/cairo-ps-surface-private.h
@@ -68,6 +68,7 @@ typedef struct cairo_ps_surface {
int bbox_x1, bbox_y1, bbox_x2, bbox_y2;
cairo_matrix_t cairo_to_ps;
cairo_image_surface_t *image;
+ cairo_image_surface_t *acquired_image;
void *image_extra;
cairo_bool_t use_string_datasource;
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index fbfdc3e5..a13be1d8 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -63,6 +63,7 @@
#include "cairo-meta-surface-private.h"
#include "cairo-output-stream-private.h"
#include "cairo-type3-glyph-surface-private.h"
+#include "cairo-image-info-private.h"
#include <stdio.h>
#include <ctype.h>
@@ -79,6 +80,10 @@
static const cairo_surface_backend_t cairo_ps_surface_backend;
static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend;
+static void
+_cairo_ps_surface_release_surface (cairo_ps_surface_t *surface,
+ cairo_surface_pattern_t *pattern);
+
static const cairo_ps_level_t _cairo_ps_levels[] =
{
CAIRO_PS_LEVEL_2,
@@ -257,7 +262,7 @@ _cairo_ps_surface_emit_type1_font_subset (cairo_ps_surface_t *surface,
snprintf (name, sizeof name, "f-%d-%d",
font_subset->font_id, font_subset->subset_id);
status = _cairo_type1_subset_init (&subset, name, font_subset, TRUE);
- if (status)
+ if (unlikely (status))
return status;
/* FIXME: Figure out document structure convention for fonts */
@@ -288,7 +293,7 @@ _cairo_ps_surface_emit_type1_font_fallback (cairo_ps_surface_t *surface,
snprintf (name, sizeof name, "f-%d-%d",
font_subset->font_id, font_subset->subset_id);
status = _cairo_type1_fallback_init_hex (&subset, name, font_subset);
- if (status)
+ if (unlikely (status))
return status;
/* FIXME: Figure out document structure convention for fonts */
@@ -317,7 +322,7 @@ _cairo_ps_surface_emit_truetype_font_subset (cairo_ps_surface_t *surface,
unsigned int i, begin, end;
status = _cairo_truetype_subset_init (&subset, font_subset);
- if (status)
+ if (unlikely (status))
return status;
/* FIXME: Figure out document structure convention for fonts */
@@ -458,7 +463,7 @@ _cairo_ps_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_sub
for (i = 0; i < font_subset->num_glyphs; i++) {
status = _cairo_type3_glyph_surface_analyze_glyph (type3_surface,
font_subset->glyphs[i]);
- if (status)
+ if (unlikely (status))
break;
}
@@ -522,7 +527,7 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface,
font_subset->glyphs[i],
&bbox,
&width);
- if (status)
+ if (unlikely (status))
break;
_cairo_output_stream_printf (surface->final_stream,
@@ -544,7 +549,7 @@ _cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface,
}
}
cairo_surface_destroy (type3_surface);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->final_stream,
@@ -630,19 +635,19 @@ _cairo_ps_surface_emit_font_subsets (cairo_ps_surface_t *surface)
status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
_cairo_ps_surface_analyze_user_font_subset,
surface);
- if (status)
+ if (unlikely (status))
goto BAIL;
status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets,
_cairo_ps_surface_emit_unscaled_font_subset,
surface);
- if (status)
+ if (unlikely (status))
goto BAIL;
status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
_cairo_ps_surface_emit_scaled_font_subset,
surface);
- if (status)
+ if (unlikely (status))
goto BAIL;
status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
@@ -700,7 +705,7 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
cairo_ps_surface_t *surface;
surface = malloc (sizeof (cairo_ps_surface_t));
- if (surface == NULL) {
+ if (unlikely (surface == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP;
}
@@ -725,11 +730,11 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
surface->stream = _cairo_output_stream_create_for_file (surface->tmpfile);
status = _cairo_output_stream_get_status (surface->stream);
- if (status)
+ if (unlikely (status))
goto CLEANUP_OUTPUT_STREAM;
surface->font_subsets = _cairo_scaled_font_subsets_create_simple ();
- if (surface->font_subsets == NULL) {
+ if (unlikely (surface->font_subsets == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_OUTPUT_STREAM;
}
@@ -930,7 +935,7 @@ cairo_ps_surface_restrict_to_level (cairo_surface_t *surface,
cairo_status_t status;
status = _extract_ps_surface (surface, &ps_surface);
- if (status) {
+ if (unlikely (status)) {
status = _cairo_surface_set_error (surface, status);
return;
}
@@ -1005,7 +1010,7 @@ cairo_ps_surface_set_eps (cairo_surface_t *surface,
cairo_status_t status;
status = _extract_ps_surface (surface, &ps_surface);
- if (status) {
+ if (unlikely (status)) {
status = _cairo_surface_set_error (surface, status);
return;
}
@@ -1030,7 +1035,7 @@ cairo_ps_surface_get_eps (cairo_surface_t *surface)
cairo_status_t status;
status = _extract_ps_surface (surface, &ps_surface);
- if (status) {
+ if (unlikely (status)) {
status = _cairo_surface_set_error (surface, status);
return FALSE;
}
@@ -1064,7 +1069,7 @@ cairo_ps_surface_set_size (cairo_surface_t *surface,
cairo_status_t status;
status = _extract_ps_surface (surface, &ps_surface);
- if (status) {
+ if (unlikely (status)) {
status = _cairo_surface_set_error (surface, status);
return;
}
@@ -1077,7 +1082,7 @@ cairo_ps_surface_set_size (cairo_surface_t *surface,
status = _cairo_paginated_surface_set_size (ps_surface->paginated_surface,
width_in_points,
height_in_points);
- if (status)
+ if (unlikely (status))
status = _cairo_surface_set_error (surface, status);
}
@@ -1178,7 +1183,7 @@ cairo_ps_surface_dsc_comment (cairo_surface_t *surface,
char *comment_copy;
status = _extract_ps_surface (surface, &ps_surface);
- if (status) {
+ if (unlikely (status)) {
status = _cairo_surface_set_error (surface, status);
return;
}
@@ -1196,13 +1201,13 @@ cairo_ps_surface_dsc_comment (cairo_surface_t *surface,
/* Then, copy the comment and store it in the appropriate array. */
comment_copy = strdup (comment);
- if (comment_copy == NULL) {
+ if (unlikely (comment_copy == NULL)) {
status = _cairo_surface_set_error (surface, CAIRO_STATUS_NO_MEMORY);
return;
}
status = _cairo_array_append (ps_surface->dsc_comment_target, &comment_copy);
- if (status) {
+ if (unlikely (status)) {
free (comment_copy);
status = _cairo_surface_set_error (surface, status);
return;
@@ -1232,7 +1237,7 @@ cairo_ps_surface_dsc_begin_setup (cairo_surface_t *surface)
cairo_status_t status;
status = _extract_ps_surface (surface, &ps_surface);
- if (status) {
+ if (unlikely (status)) {
status = _cairo_surface_set_error (surface, status);
return;
}
@@ -1267,7 +1272,7 @@ cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t *surface)
cairo_status_t status;
status = _extract_ps_surface (surface, &ps_surface);
- if (status) {
+ if (unlikely (status)) {
status = _cairo_surface_set_error (surface, status);
return;
}
@@ -1299,11 +1304,11 @@ _cairo_ps_surface_finish (void *abstract_surface)
_cairo_ps_surface_emit_header (surface);
status = _cairo_ps_surface_emit_font_subsets (surface);
- if (status)
+ if (unlikely (status))
goto CLEANUP;
status = _cairo_ps_surface_emit_body (surface);
- if (status)
+ if (unlikely (status))
goto CLEANUP;
_cairo_ps_surface_emit_footer (surface);
@@ -1357,7 +1362,7 @@ _cairo_ps_surface_end_page (cairo_ps_surface_t *surface)
cairo_int_status_t status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->stream,
@@ -1373,7 +1378,7 @@ _cairo_ps_surface_show_page (void *abstract_surface)
cairo_int_status_t status;
status = _cairo_ps_surface_end_page (surface);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->stream, "showpage\n");
@@ -1402,7 +1407,7 @@ _cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t
status = _cairo_surface_acquire_source_image (pattern->surface,
&image,
&image_extra);
- if (status)
+ if (unlikely (status))
return status;
if (image->base.status)
@@ -1567,8 +1572,12 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
- if ( _cairo_surface_is_meta (surface_pattern->surface))
- return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
+ if ( _cairo_surface_is_meta (surface_pattern->surface)) {
+ if (pattern->extend == CAIRO_EXTEND_PAD)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ else
+ return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
+ }
}
if (op == CAIRO_OPERATOR_SOURCE)
@@ -1724,13 +1733,14 @@ _string_array_stream_create (cairo_output_stream_t *output)
string_array_stream_t *stream;
stream = malloc (sizeof (string_array_stream_t));
- if (stream == NULL) {
+ if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base,
_string_array_stream_write,
+ NULL,
_string_array_stream_close);
stream->output = output;
stream->column = 0;
@@ -1750,13 +1760,14 @@ _base85_array_stream_create (cairo_output_stream_t *output)
string_array_stream_t *stream;
stream = malloc (sizeof (string_array_stream_t));
- if (stream == NULL) {
+ if (unlikely (stream == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base,
_string_array_stream_write,
+ NULL,
_string_array_stream_close);
stream->output = output;
stream->column = 0;
@@ -1798,7 +1809,7 @@ _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t *surface,
background_color,
0, 0,
image->width, image->height);
- if (status)
+ if (unlikely (status))
goto fail;
status = _cairo_surface_composite (CAIRO_OPERATOR_OVER,
@@ -1810,7 +1821,7 @@ _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t *surface,
0, 0,
image->width,
image->height);
- if (status)
+ if (unlikely (status))
goto fail;
_cairo_pattern_fini (&pattern.base);
@@ -1827,7 +1838,7 @@ fail:
static cairo_status_t
_cairo_ps_surface_emit_base85_string (cairo_ps_surface_t *surface,
- unsigned char *data,
+ const unsigned char *data,
unsigned long length,
cairo_bool_t use_strings)
{
@@ -1840,12 +1851,12 @@ _cairo_ps_surface_emit_base85_string (cairo_ps_surface_t *surface,
string_array_stream = _base85_array_stream_create (surface->stream);
status = _cairo_output_stream_get_status (string_array_stream);
- if (status)
+ if (unlikely (status))
return _cairo_output_stream_destroy (string_array_stream);
base85_stream = _cairo_base85_stream_create (string_array_stream);
status = _cairo_output_stream_get_status (base85_stream);
- if (status) {
+ if (unlikely (status)) {
status2 = _cairo_output_stream_destroy (string_array_stream);
return _cairo_output_stream_destroy (base85_stream);
}
@@ -1907,7 +1918,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
status = _cairo_ps_surface_flatten_image_transparency (surface,
image,
&opaque_image);
- if (status)
+ if (unlikely (status))
return status;
use_mask = FALSE;
@@ -1929,7 +1940,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
data_size = image->height * image->width * 3;
}
data = malloc (data_size);
- if (data == NULL) {
+ if (unlikely (data == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto bail1;
}
@@ -1978,7 +1989,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
* instead. */
data_compressed_size = data_size;
data_compressed = _cairo_lzw_compress (data, &data_compressed_size);
- if (data_compressed == NULL) {
+ if (unlikely (data_compressed == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto bail2;
}
@@ -1993,7 +2004,7 @@ _cairo_ps_surface_emit_image (cairo_ps_surface_t *surface,
data_compressed,
data_compressed_size,
TRUE);
- if (status)
+ if (unlikely (status))
goto bail3;
_cairo_output_stream_printf (surface->stream,
@@ -2111,6 +2122,92 @@ bail1:
}
static cairo_status_t
+_cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t *surface,
+ cairo_surface_t *source,
+ int width,
+ int height)
+{
+ cairo_status_t status;
+ const unsigned char *mime_data;
+ unsigned int mime_data_length;
+ cairo_image_info_t info;
+
+ cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
+ &mime_data, &mime_data_length);
+ if (mime_data == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_image_info_get_jpeg_info (&info, mime_data, mime_data_length);
+ if (unlikely (status))
+ return status;
+
+ if (info.num_components != 1 && info.num_components != 3)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (surface->use_string_datasource) {
+ /* Emit the image data as a base85-encoded string which will
+ * be used as the data source for the image operator later. */
+ _cairo_output_stream_printf (surface->stream,
+ "/CairoImageData [\n");
+
+ status = _cairo_ps_surface_emit_base85_string (surface,
+ mime_data,
+ mime_data_length,
+ TRUE);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_printf (surface->stream,
+ "] def\n");
+ _cairo_output_stream_printf (surface->stream,
+ "/CairoImageDataIndex 0 def\n");
+ }
+
+ _cairo_output_stream_printf (surface->stream,
+ "/%s setcolorspace\n"
+ "8 dict dup begin\n"
+ " /ImageType 1 def\n"
+ " /Width %d def\n"
+ " /Height %d def\n"
+ " /BitsPerComponent %d def\n"
+ " /Decode [ 0 1 0 1 0 1 ] def\n",
+ info.num_components == 1 ? "DeviceGray" : "DeviceRGB",
+ info.width,
+ info.height,
+ info.bits_per_component);
+
+ if (surface->use_string_datasource) {
+ _cairo_output_stream_printf (surface->stream,
+ " /DataSource {\n"
+ " CairoImageData CairoImageDataIndex get\n"
+ " /CairoImageDataIndex CairoImageDataIndex 1 add def\n"
+ " CairoImageDataIndex CairoImageData length 1 sub gt\n"
+ " { /CairoImageDataIndex 0 def } if\n"
+ " } /ASCII85Decode filter /DCTDecode filter def\n");
+ } else {
+ _cairo_output_stream_printf (surface->stream,
+ " /DataSource currentfile /ASCII85Decode filter /DCTDecode filter def\n");
+ }
+
+ _cairo_output_stream_printf (surface->stream,
+ " /ImageMatrix [ 1 0 0 -1 0 %d ] def\n"
+ "end\n"
+ "image\n",
+ info.height);
+
+ if (!surface->use_string_datasource) {
+ /* Emit the image data as a base85-encoded string which will
+ * be used as the data source for the image operator. */
+ status = _cairo_ps_surface_emit_base85_string (surface,
+ mime_data,
+ mime_data_length,
+ FALSE);
+ }
+
+ return status;
+}
+
+static cairo_status_t
_cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
cairo_surface_t *meta_surface)
{
@@ -2122,7 +2219,7 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
cairo_status_t status;
status = _cairo_surface_get_extents (meta_surface, &meta_extents);
- if (status)
+ if (unlikely (status))
return status;
old_content = surface->content;
@@ -2154,11 +2251,11 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
status = _cairo_meta_surface_replay_region (meta_surface, &surface->base,
CAIRO_META_REGION_NATIVE);
assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->stream,
@@ -2170,7 +2267,7 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
_cairo_pdf_operators_reset (&surface->pdf_operators);
surface->cairo_to_ps = old_cairo_to_ps;
status = _cairo_surface_set_clip (&surface->base, old_clip);
- if (status)
+ if (unlikely (status))
return status;
_cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
@@ -2224,40 +2321,93 @@ _cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface,
static cairo_status_t
_cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface,
cairo_surface_pattern_t *pattern,
+ cairo_rectangle_int_t *extents,
int *width,
int *height,
- cairo_operator_t op)
+ int *origin_x,
+ int *origin_y)
{
cairo_status_t status;
+ cairo_surface_t *pad_image;
+ int x = 0;
+ int y = 0;
if (_cairo_surface_is_meta (pattern->surface)) {
cairo_surface_t *meta_surface = pattern->surface;
cairo_rectangle_int_t pattern_extents;
status = _cairo_surface_get_extents (meta_surface, &pattern_extents);
- if (status)
+ if (unlikely (status))
return status;
*width = pattern_extents.width;
*height = pattern_extents.height;
} else {
status = _cairo_surface_acquire_source_image (pattern->surface,
- &surface->image,
+ &surface->acquired_image,
&surface->image_extra);
- if (status)
+ if (unlikely (status))
return status;
+ pad_image = &surface->acquired_image->base;
+ if (cairo_pattern_get_extend (&pattern->base) == CAIRO_EXTEND_PAD) {
+ cairo_box_t box;
+ cairo_rectangle_int_t rect;
+ cairo_surface_pattern_t pad_pattern;
+
+ /* get the operation extents in pattern space */
+ _cairo_box_from_rectangle (&box, extents);
+ _cairo_matrix_transform_bounding_box_fixed (&pattern->base.matrix, &box, NULL);
+ _cairo_box_round_to_rectangle (&box, &rect);
+ x = -rect.x;
+ y = -rect.y;
+
+ pad_image = _cairo_image_surface_create_with_content (pattern->surface->content,
+ rect.width,
+ rect.height);
+ if (pad_image->status) {
+ status = pad_image->status;
+ goto BAIL;
+ }
+
+ _cairo_pattern_init_for_surface (&pad_pattern, &surface->acquired_image->base);
+ cairo_matrix_init_translate (&pad_pattern.base.matrix, -x, -y);
+ pad_pattern.base.extend = CAIRO_EXTEND_PAD;
+ status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
+ &pad_pattern.base,
+ NULL,
+ pad_image,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ rect.width,
+ rect.height);
+ _cairo_pattern_fini (&pad_pattern.base);
+ if (unlikely (status))
+ goto BAIL;
+ }
+
+ surface->image = (cairo_image_surface_t *) pad_image;
*width = surface->image->width;
*height = surface->image->height;
+ *origin_x = x;
+ *origin_y = y;
}
return CAIRO_STATUS_SUCCESS;
+
+BAIL:
+ _cairo_ps_surface_release_surface (surface, pattern);
+
+ return status;
}
static cairo_status_t
_cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface,
cairo_surface_pattern_t *pattern,
- cairo_operator_t op)
+ cairo_operator_t op,
+ int width,
+ int height)
{
cairo_status_t status;
@@ -2267,6 +2417,13 @@ _cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface,
status = _cairo_ps_surface_emit_meta_surface (surface,
meta_surface);
} else {
+ if (cairo_pattern_get_extend (&pattern->base) != CAIRO_EXTEND_PAD) {
+ status = _cairo_ps_surface_emit_jpeg_image (surface, pattern->surface,
+ width, height);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
+
status = _cairo_ps_surface_emit_image (surface, surface->image,
op, pattern->base.filter);
}
@@ -2279,25 +2436,29 @@ _cairo_ps_surface_release_surface (cairo_ps_surface_t *surface,
cairo_surface_pattern_t *pattern)
{
if (!_cairo_surface_is_meta (pattern->surface))
- _cairo_surface_release_source_image (pattern->surface, surface->image,
+ _cairo_surface_release_source_image (pattern->surface,
+ surface->acquired_image,
surface->image_extra);
}
static cairo_status_t
_cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface,
cairo_surface_pattern_t *pattern,
+ cairo_rectangle_int_t *extents,
cairo_operator_t op)
{
cairo_status_t status;
int width, height;
cairo_matrix_t cairo_p2d, ps_p2d;
+ int origin_x = 0;
+ int origin_y = 0;
status = _cairo_ps_surface_acquire_surface (surface,
pattern,
- &width,
- &height,
- op);
- if (status)
+ extents,
+ &width, &height,
+ &origin_x, &origin_y);
+ if (unlikely (status))
return status;
cairo_p2d = pattern->base.matrix;
@@ -2329,6 +2490,7 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface,
ps_p2d = surface->cairo_to_ps;
cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
+ cairo_matrix_translate (&ps_p2d, -origin_x, -origin_y);
cairo_matrix_translate (&ps_p2d, 0.0, height);
cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
@@ -2340,7 +2502,7 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface,
ps_p2d.x0, ps_p2d.y0);
}
- status = _cairo_ps_surface_emit_surface (surface, pattern, op);
+ status = _cairo_ps_surface_emit_surface (surface, pattern, op, width, height);
_cairo_ps_surface_release_surface (surface, pattern);
return status;
@@ -2349,6 +2511,7 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface,
static cairo_status_t
_cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
cairo_surface_pattern_t *pattern,
+ cairo_rectangle_int_t *extents,
cairo_operator_t op)
{
cairo_status_t status;
@@ -2358,6 +2521,8 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
cairo_matrix_t cairo_p2d, ps_p2d;
cairo_rectangle_int_t surface_extents;
cairo_bool_t old_use_string_datasource;
+ int origin_x = 0;
+ int origin_y = 0;
cairo_p2d = pattern->base.matrix;
status = cairo_matrix_invert (&cairo_p2d);
@@ -2366,19 +2531,19 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
ps_p2d = surface->cairo_to_ps;
cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d);
+ cairo_matrix_translate (&ps_p2d, -origin_x, -origin_y);
cairo_matrix_translate (&ps_p2d, 0.0, pattern_height);
cairo_matrix_scale (&ps_p2d, 1.0, -1.0);
status = _cairo_ps_surface_acquire_surface (surface,
pattern,
- &pattern_width,
- &pattern_height,
- op);
- if (status)
+ extents,
+ &pattern_width, &pattern_height,
+ &origin_x, &origin_y);
+ if (unlikely (status))
return status;
switch (pattern->base.extend) {
- /* We implement EXTEND_PAD like EXTEND_NONE for now */
case CAIRO_EXTEND_PAD:
case CAIRO_EXTEND_NONE:
{
@@ -2435,8 +2600,9 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
surface->content == CAIRO_CONTENT_COLOR ? 0 : 1,
xstep, ystep);
}
- status = _cairo_ps_surface_emit_surface (surface, pattern, op);
- if (status)
+ status = _cairo_ps_surface_emit_surface (surface, pattern, op,
+ pattern_width, pattern_height);
+ if (unlikely (status))
return status;
surface->use_string_datasource = old_use_string_datasource;
@@ -2483,7 +2649,7 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
">>\n");
status = _cairo_surface_get_extents (&surface->base, &surface_extents);
- if (status)
+ if (unlikely (status))
return status;
cairo_p2d = pattern->base.matrix;
@@ -2583,7 +2749,7 @@ _cairo_ps_surface_emit_pattern_stops (cairo_ps_surface_t *surface,
unsigned int i, n_stops;
allstops = _cairo_malloc_ab ((pattern->n_stops + 2), sizeof (cairo_ps_color_stop_t));
- if (allstops == NULL)
+ if (unlikely (allstops == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
stops = &allstops[1];
@@ -2789,7 +2955,7 @@ _cairo_ps_surface_emit_linear_pattern (cairo_ps_surface_t *surface,
status = _cairo_ps_surface_emit_pattern_stops (surface,
&pattern->base);
- if (status)
+ if (unlikely (status))
return status;
if (pattern->base.base.extend == CAIRO_EXTEND_REPEAT ||
@@ -2798,7 +2964,7 @@ _cairo_ps_surface_emit_linear_pattern (cairo_ps_surface_t *surface,
&pattern->base,
repeat_begin,
repeat_end);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -2876,7 +3042,7 @@ _cairo_ps_surface_emit_radial_pattern (cairo_ps_surface_t *surface,
r2 = _cairo_fixed_to_double (pattern->r2);
status = _cairo_ps_surface_emit_pattern_stops (surface, &pattern->base);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->stream,
@@ -2914,7 +3080,8 @@ _cairo_ps_surface_emit_radial_pattern (cairo_ps_surface_t *surface,
static cairo_status_t
_cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface,
const cairo_pattern_t *pattern,
- cairo_operator_t op)
+ cairo_rectangle_int_t *extents,
+ cairo_operator_t op)
{
cairo_status_t status;
@@ -2925,7 +3092,7 @@ _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface,
! _cairo_color_equal (&surface->current_color, &solid->color))
{
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
_cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
@@ -2939,7 +3106,7 @@ _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface,
surface->current_pattern_is_solid_color = FALSE;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
switch (pattern->type) {
@@ -2951,22 +3118,23 @@ _cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface,
case CAIRO_PATTERN_TYPE_SURFACE:
status = _cairo_ps_surface_emit_surface_pattern (surface,
(cairo_surface_pattern_t *) pattern,
+ extents,
op);
- if (status)
+ if (unlikely (status))
return status;
break;
case CAIRO_PATTERN_TYPE_LINEAR:
status = _cairo_ps_surface_emit_linear_pattern (surface,
(cairo_linear_pattern_t *) pattern);
- if (status)
+ if (unlikely (status))
return status;
break;
case CAIRO_PATTERN_TYPE_RADIAL:
status = _cairo_ps_surface_emit_radial_pattern (surface,
(cairo_radial_pattern_t *) pattern);
- if (status)
+ if (unlikely (status))
return status;
break;
}
@@ -2995,7 +3163,7 @@ _cairo_ps_surface_intersect_clip_path (void *abstract_surface,
if (path == NULL) {
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (stream, "Q q\n");
@@ -3043,7 +3211,8 @@ _cairo_ps_surface_get_font_options (void *abstract_surface,
static cairo_int_status_t
_cairo_ps_surface_paint (void *abstract_surface,
cairo_operator_t op,
- const cairo_pattern_t *source)
+ const cairo_pattern_t *source,
+ cairo_rectangle_int_t *paint_extents)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_output_stream_t *stream = surface->stream;
@@ -3061,11 +3230,11 @@ _cairo_ps_surface_paint (void *abstract_surface,
#endif
status = _cairo_surface_get_extents (&surface->base, &extents);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
@@ -3078,17 +3247,17 @@ _cairo_ps_surface_paint (void *abstract_surface,
status = _cairo_ps_surface_paint_surface (surface,
(cairo_surface_pattern_t *) source,
- op);
- if (status)
+ paint_extents, op);
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (stream, "Q\n");
} else {
- status = _cairo_ps_surface_emit_pattern (surface, source, op);
+ status = _cairo_ps_surface_emit_pattern (surface, source, paint_extents, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (stream, "0 0 %d %d rectfill\n",
@@ -3108,7 +3277,8 @@ _cairo_ps_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_int_status_t status;
@@ -3123,7 +3293,7 @@ _cairo_ps_surface_stroke (void *abstract_surface,
"%% _cairo_ps_surface_stroke\n");
#endif
- status = _cairo_ps_surface_emit_pattern (surface, source, op);
+ status = _cairo_ps_surface_emit_pattern (surface, source, extents, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
@@ -3141,7 +3311,8 @@ _cairo_ps_surface_fill (void *abstract_surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_int_status_t status;
@@ -3161,7 +3332,7 @@ _cairo_ps_surface_fill (void *abstract_surface,
source->extend == CAIRO_EXTEND_PAD))
{
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->stream, "q\n");
@@ -3169,23 +3340,23 @@ _cairo_ps_surface_fill (void *abstract_surface,
status = _cairo_pdf_operators_clip (&surface->pdf_operators,
path,
fill_rule);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_ps_surface_paint_surface (surface,
(cairo_surface_pattern_t *) source,
- op);
- if (status)
+ extents, op);
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->stream, "Q\n");
_cairo_pdf_operators_reset (&surface->pdf_operators);
} else {
- status = _cairo_ps_surface_emit_pattern (surface, source, op);
+ status = _cairo_ps_surface_emit_pattern (surface, source, extents, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pdf_operators_fill (&surface->pdf_operators,
@@ -3203,7 +3374,8 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs)
+ int *remaining_glyphs,
+ cairo_rectangle_int_t *extents)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_status_t status;
@@ -3221,11 +3393,11 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
if (num_glyphs <= 0)
return CAIRO_STATUS_SUCCESS;
- status = _cairo_ps_surface_emit_pattern (surface, source, op);
+ status = _cairo_ps_surface_emit_pattern (surface, source, extents, op);
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
- if (status)
+ if (unlikely (status))
return status;
return _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
@@ -3331,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 3eee2c11..3bfd9e21 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 fc9439e3..34661853 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -631,7 +631,7 @@ static void
ComputeGradientValue (void *info, const float *in, float *out)
{
double fdist = *in;
- cairo_gradient_pattern_t *grad = (cairo_gradient_pattern_t*) info;
+ const cairo_gradient_pattern_t *grad = (cairo_gradient_pattern_t*) info;
unsigned int i;
/* Put fdist back in the 0.0..1.0 range if we're doing
@@ -680,15 +680,21 @@ ComputeGradientValue (void *info, const float *in, float *out)
}
static CGFunctionRef
-CreateGradientFunction (cairo_gradient_pattern_t *gpat)
+CreateGradientFunction (const cairo_gradient_pattern_t *gpat)
{
+ cairo_pattern_t *pat;
float input_value_range[2] = { 0.f, 1.f };
float output_value_ranges[8] = { 0.f, 1.f, 0.f, 1.f, 0.f, 1.f, 0.f, 1.f };
CGFunctionCallbacks callbacks = {
0, ComputeGradientValue, (CGFunctionReleaseInfoCallback) cairo_pattern_destroy
};
- return CGFunctionCreate (_cairo_pattern_create_copy (&gpat->base),
+ if (_cairo_pattern_create_copy (&pat, &gpat->base))
+ /* quartz doesn't deal very well with malloc failing, so there's
+ * not much point in us trying either */
+ return NULL;
+
+ return CGFunctionCreate (pat,
1,
input_value_range,
4,
@@ -698,10 +704,11 @@ CreateGradientFunction (cairo_gradient_pattern_t *gpat)
static CGFunctionRef
CreateRepeatingGradientFunction (cairo_quartz_surface_t *surface,
- cairo_gradient_pattern_t *gpat,
+ const cairo_gradient_pattern_t *gpat,
CGPoint *start, CGPoint *end,
CGAffineTransform matrix)
{
+ cairo_pattern_t *pat;
float input_value_range[2];
float output_value_ranges[8] = { 0.f, 1.f, 0.f, 1.f, 0.f, 1.f, 0.f, 1.f };
CGFunctionCallbacks callbacks = {
@@ -766,7 +773,12 @@ CreateRepeatingGradientFunction (cairo_quartz_surface_t *surface,
input_value_range[0] = 0.0 - 1.0 * rep_start;
input_value_range[1] = 1.0 + 1.0 * rep_end;
- return CGFunctionCreate (_cairo_pattern_create_copy (&gpat->base),
+ if (_cairo_pattern_create_copy (&pat, &gpat->base))
+ /* quartz doesn't deal very well with malloc failing, so there's
+ * not much point in us trying either */
+ return NULL;
+
+ return CGFunctionCreate (pat,
1,
input_value_range,
4,
@@ -904,7 +916,7 @@ SurfacePatternReleaseInfoFunc (void *ainfo)
static cairo_int_status_t
_cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t *dest,
- cairo_pattern_t *apattern,
+ const cairo_pattern_t *apattern,
CGPatternRef *cgpat)
{
cairo_surface_pattern_t *spattern;
@@ -1013,7 +1025,7 @@ typedef enum {
static cairo_quartz_action_t
_cairo_quartz_setup_fallback_source (cairo_quartz_surface_t *surface,
- cairo_pattern_t *source)
+ const cairo_pattern_t *source)
{
CGRect clipBox = CGContextGetClipBoundingBox (surface->cgContext);
CGAffineTransform ctm;
@@ -1022,6 +1034,7 @@ _cairo_quartz_setup_fallback_source (cairo_quartz_surface_t *surface,
cairo_surface_t *fallback;
cairo_t *fallback_cr;
CGImageRef img;
+ cairo_pattern_t *source_copy;
cairo_status_t status;
@@ -1050,7 +1063,13 @@ _cairo_quartz_setup_fallback_source (cairo_quartz_surface_t *surface,
/* Paint the source onto our temporary */
fallback_cr = cairo_create (fallback);
cairo_set_operator (fallback_cr, CAIRO_OPERATOR_SOURCE);
- cairo_set_source (fallback_cr, source);
+
+ /* Use a copy of the pattern because it is const and could be allocated
+ * on the stack */
+ status = _cairo_pattern_create_copy (&source_copy, source);
+ cairo_set_source (fallback_cr, source_copy);
+ cairo_pattern_destroy (source_copy);
+
cairo_paint (fallback_cr);
cairo_destroy (fallback_cr);
@@ -1070,9 +1089,9 @@ _cairo_quartz_setup_fallback_source (cairo_quartz_surface_t *surface,
static cairo_quartz_action_t
_cairo_quartz_setup_linear_source (cairo_quartz_surface_t *surface,
- cairo_linear_pattern_t *lpat)
+ const cairo_linear_pattern_t *lpat)
{
- cairo_pattern_t *abspat = (cairo_pattern_t *) lpat;
+ const cairo_pattern_t *abspat = &lpat->base.base;
cairo_matrix_t mat;
CGPoint start, end;
CGFunctionRef gradFunc;
@@ -1085,7 +1104,7 @@ _cairo_quartz_setup_linear_source (cairo_quartz_surface_t *surface,
return DO_SOLID;
}
- cairo_pattern_get_matrix (abspat, &mat);
+ mat = abspat->matrix;
cairo_matrix_invert (&mat);
_cairo_quartz_cairo_matrix_to_quartz (&mat, &surface->sourceTransform);
@@ -1099,10 +1118,10 @@ _cairo_quartz_setup_linear_source (cairo_quartz_surface_t *surface,
if (abspat->extend == CAIRO_EXTEND_NONE ||
abspat->extend == CAIRO_EXTEND_PAD)
{
- gradFunc = CreateGradientFunction ((cairo_gradient_pattern_t*) lpat);
+ gradFunc = CreateGradientFunction (&lpat->base);
} else {
gradFunc = CreateRepeatingGradientFunction (surface,
- (cairo_gradient_pattern_t*) lpat,
+ &lpat->base,
&start, &end, surface->sourceTransform);
}
@@ -1119,9 +1138,9 @@ _cairo_quartz_setup_linear_source (cairo_quartz_surface_t *surface,
static cairo_quartz_action_t
_cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface,
- cairo_radial_pattern_t *rpat)
+ const cairo_radial_pattern_t *rpat)
{
- cairo_pattern_t *abspat = (cairo_pattern_t *)rpat;
+ const cairo_pattern_t *abspat = &rpat->base.base;
cairo_matrix_t mat;
CGPoint start, end;
CGFunctionRef gradFunc;
@@ -1142,10 +1161,10 @@ _cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface,
* Radial shadings). So, instead, let's just render an image
* for pixman to draw the shading into, and use that.
*/
- return _cairo_quartz_setup_fallback_source (surface, (cairo_pattern_t*) rpat);
+ return _cairo_quartz_setup_fallback_source (surface, &rpat->base.base);
}
- cairo_pattern_get_matrix (abspat, &mat);
+ mat = abspat->matrix;
cairo_matrix_invert (&mat);
_cairo_quartz_cairo_matrix_to_quartz (&mat, &surface->sourceTransform);
@@ -1156,7 +1175,7 @@ _cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface,
end = CGPointMake (_cairo_fixed_to_double (rpat->c2.x),
_cairo_fixed_to_double (rpat->c2.y));
- gradFunc = CreateGradientFunction ((cairo_gradient_pattern_t*) rpat);
+ gradFunc = CreateGradientFunction (&rpat->base);
surface->sourceShading = CGShadingCreateRadial (rgb,
start,
@@ -1174,7 +1193,7 @@ _cairo_quartz_setup_radial_source (cairo_quartz_surface_t *surface,
static cairo_quartz_action_t
_cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
- cairo_pattern_t *source)
+ const cairo_pattern_t *source)
{
assert (!(surface->sourceImage || surface->sourceShading || surface->sourcePattern));
@@ -1199,13 +1218,13 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
}
if (source->type == CAIRO_PATTERN_TYPE_LINEAR) {
- cairo_linear_pattern_t *lpat = (cairo_linear_pattern_t *)source;
+ const cairo_linear_pattern_t *lpat = (const cairo_linear_pattern_t *)source;
return _cairo_quartz_setup_linear_source (surface, lpat);
}
if (source->type == CAIRO_PATTERN_TYPE_RADIAL) {
- cairo_radial_pattern_t *rpat = (cairo_radial_pattern_t *)source;
+ const cairo_radial_pattern_t *rpat = (const cairo_radial_pattern_t *)source;
return _cairo_quartz_setup_radial_source (surface, rpat);
}
@@ -1213,7 +1232,7 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
(source->extend == CAIRO_EXTEND_NONE || (CGContextDrawTiledImagePtr && source->extend == CAIRO_EXTEND_REPEAT)))
{
- cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) source;
+ const cairo_surface_pattern_t *spat = (const cairo_surface_pattern_t *) source;
cairo_surface_t *pat_surf = spat->surface;
CGImageRef img;
cairo_matrix_t m = spat->base.matrix;
@@ -1320,7 +1339,7 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
static void
_cairo_quartz_teardown_source (cairo_quartz_surface_t *surface,
- cairo_pattern_t *source)
+ const cairo_pattern_t *source)
{
CGContextSetInterpolationQuality (surface->cgContext, surface->oldInterpolationQuality);
@@ -1667,7 +1686,8 @@ _cairo_quartz_surface_get_extents (void *abstract_surface,
static cairo_int_status_t
_cairo_quartz_surface_paint (void *abstract_surface,
cairo_operator_t op,
- cairo_pattern_t *source)
+ const cairo_pattern_t *source,
+ cairo_rectangle_int_t *extents)
{
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
@@ -1718,11 +1738,12 @@ _cairo_quartz_surface_paint (void *abstract_surface,
static cairo_int_status_t
_cairo_quartz_surface_fill (void *abstract_surface,
cairo_operator_t op,
- cairo_pattern_t *source,
+ const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
@@ -1823,13 +1844,14 @@ _cairo_quartz_surface_fill (void *abstract_surface,
static cairo_int_status_t
_cairo_quartz_surface_stroke (void *abstract_surface,
cairo_operator_t op,
- cairo_pattern_t *source,
+ const cairo_pattern_t *source,
cairo_path_fixed_t *path,
cairo_stroke_style_t *style,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
@@ -1969,11 +1991,12 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
static cairo_int_status_t
_cairo_quartz_surface_show_glyphs (void *abstract_surface,
cairo_operator_t op,
- cairo_pattern_t *source,
+ const cairo_pattern_t *source,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs)
+ int *remaining_glyphs,
+ cairo_rectangle_int_t *extents)
{
CGAffineTransform textTransform, ctm;
#define STATIC_BUF_SIZE 64
@@ -2178,22 +2201,23 @@ BAIL:
static cairo_int_status_t
_cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
cairo_operator_t op,
- cairo_pattern_t *source,
- cairo_surface_pattern_t *mask)
+ const cairo_pattern_t *source,
+ const cairo_surface_pattern_t *mask,
+ cairo_rectangle_int_t *extents)
{
- cairo_rectangle_int_t extents;
+ cairo_rectangle_int_t mask_extents;
CGRect rect;
CGImageRef img;
cairo_surface_t *pat_surf = mask->surface;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
CGAffineTransform ctm, mask_matrix;
- status = _cairo_surface_get_extents (pat_surf, &extents);
+ status = _cairo_surface_get_extents (pat_surf, &mask_extents);
if (status)
return status;
// everything would be masked out, so do nothing
- if (extents.width == 0 || extents.height == 0)
+ if (mask_extents.width == 0 || mask_extents.height == 0)
return CAIRO_STATUS_SUCCESS;
status = _cairo_surface_to_cgimage ((cairo_surface_t *) surface, pat_surf, &img);
@@ -2202,7 +2226,7 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
if (status)
return status;
- rect = CGRectMake (0.0f, 0.0f, extents.width, extents.height);
+ rect = CGRectMake (0.0f, 0.0f, mask_extents.width, mask_extents.height);
CGContextSaveGState (surface->cgContext);
@@ -2219,7 +2243,7 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
CGContextSetCTM (surface->cgContext, ctm);
- status = _cairo_quartz_surface_paint (surface, op, source);
+ status = _cairo_quartz_surface_paint (surface, op, source, extents);
CGContextRestoreGState (surface->cgContext);
@@ -2243,8 +2267,9 @@ _cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
static cairo_int_status_t
_cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface,
cairo_operator_t op,
- cairo_pattern_t *source,
- cairo_pattern_t *mask)
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_rectangle_int_t *extents)
{
int width = surface->extents.width - surface->extents.x;
int height = surface->extents.height - surface->extents.y;
@@ -2253,6 +2278,7 @@ _cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface,
cairo_t *gradient_surf_cr = NULL;
cairo_surface_pattern_t surface_pattern;
+ cairo_pattern_t *mask_copy;
cairo_int_status_t status;
/* Render the gradient to a surface */
@@ -2260,7 +2286,13 @@ _cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface,
width,
height);
gradient_surf_cr = cairo_create(gradient_surf);
- cairo_set_source (gradient_surf_cr, mask);
+
+ /* make a copy of the pattern because because cairo_set_source doesn't take
+ * a 'const cairo_pattern_t *' */
+ _cairo_pattern_create_copy (&mask_copy, mask);
+ cairo_set_source (gradient_surf_cr, mask_copy);
+ cairo_pattern_destroy (mask_copy);
+
cairo_set_operator (gradient_surf_cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (gradient_surf_cr);
status = cairo_status (gradient_surf_cr);
@@ -2271,7 +2303,7 @@ _cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface,
_cairo_pattern_init_for_surface (&surface_pattern, gradient_surf);
- status = _cairo_quartz_surface_mask_with_surface (surface, op, source, &surface_pattern);
+ status = _cairo_quartz_surface_mask_with_surface (surface, op, source, &surface_pattern, extents);
_cairo_pattern_fini (&surface_pattern.base);
@@ -2285,8 +2317,9 @@ _cairo_quartz_surface_mask_with_generic (cairo_quartz_surface_t *surface,
static cairo_int_status_t
_cairo_quartz_surface_mask (void *abstract_surface,
cairo_operator_t op,
- cairo_pattern_t *source,
- cairo_pattern_t *mask)
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_rectangle_int_t *extents)
{
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
cairo_int_status_t rv = CAIRO_STATUS_SUCCESS;
@@ -2301,7 +2334,7 @@ _cairo_quartz_surface_mask (void *abstract_surface,
cairo_solid_pattern_t *solid_mask = (cairo_solid_pattern_t *) mask;
CGContextSetAlpha (surface->cgContext, solid_mask->color.alpha);
- rv = _cairo_quartz_surface_paint (surface, op, source);
+ rv = _cairo_quartz_surface_paint (surface, op, source, extents);
CGContextSetAlpha (surface->cgContext, 1.0);
return rv;
@@ -2311,9 +2344,9 @@ _cairo_quartz_surface_mask (void *abstract_surface,
if (CGContextClipToMaskPtr) {
/* For these, we can skip creating a temporary surface, since we already have one */
if (mask->type == CAIRO_PATTERN_TYPE_SURFACE && mask->extend == CAIRO_EXTEND_NONE)
- return _cairo_quartz_surface_mask_with_surface (surface, op, source, (cairo_surface_pattern_t *) mask);
+ return _cairo_quartz_surface_mask_with_surface (surface, op, source, (cairo_surface_pattern_t *) mask, extents);
- return _cairo_quartz_surface_mask_with_generic (surface, op, source, mask);
+ return _cairo_quartz_surface_mask_with_generic (surface, op, source, mask, extents);
}
/* So, CGContextClipToMask is not present in 10.3.9, so we're
@@ -2390,6 +2423,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-rectangle.c b/src/cairo-rectangle.c
index 2143f0c6..9a68409c 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-region.c b/src/cairo-region.c
index a89c4d07..53a359b3 100644
--- a/src/cairo-region.c
+++ b/src/cairo-region.c
@@ -64,7 +64,7 @@ _cairo_region_init_boxes (cairo_region_t *region,
if (count > ARRAY_LENGTH (stack_pboxes)) {
pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t));
- if (pboxes == NULL)
+ if (unlikely (pboxes == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -114,16 +114,17 @@ _cairo_region_get_boxes (cairo_region_t *region, int *num_boxes, cairo_box_int_t
int i;
pboxes = pixman_region32_rectangles (&region->rgn, &nboxes);
-
if (nboxes == 0) {
*num_boxes = 0;
- *boxes = NULL;
return CAIRO_STATUS_SUCCESS;
}
- cboxes = _cairo_malloc_ab (nboxes, sizeof(cairo_box_int_t));
- if (cboxes == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ if (nboxes > *num_boxes) {
+ cboxes = _cairo_malloc_ab (nboxes, sizeof (cairo_box_int_t));
+ if (unlikely (cboxes == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ } else
+ cboxes = *boxes;
for (i = 0; i < nboxes; i++) {
cboxes[i].p1.x = pboxes[i].x1;
diff --git a/src/cairo-scaled-font-private.h b/src/cairo-scaled-font-private.h
index c1d87ae0..86a50bbb 100644
--- a/src/cairo-scaled-font-private.h
+++ b/src/cairo-scaled-font-private.h
@@ -94,10 +94,11 @@ struct _cairo_scaled_font {
cairo_bool_t finished;
/* "live" scaled_font members */
- cairo_matrix_t scale; /* font space => device space */
- cairo_matrix_t scale_inverse; /* device space => font space */
- double max_scale; /* maximum x/y expansion of scale */
- cairo_font_extents_t extents; /* user space */
+ cairo_matrix_t scale; /* font space => device space */
+ cairo_matrix_t scale_inverse; /* device space => font space */
+ double max_scale; /* maximum x/y expansion of scale */
+ cairo_font_extents_t extents; /* user space */
+ cairo_font_extents_t fs_extents; /* font space */
/* The mutex protects modification to all subsequent fields. */
cairo_mutex_t mutex;
diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c
index 815c4d8b..c802c314 100644
--- a/src/cairo-scaled-font-subsets.c
+++ b/src/cairo-scaled-font-subsets.c
@@ -163,7 +163,7 @@ _cairo_sub_font_glyph_create (unsigned long scaled_font_glyph_index,
cairo_sub_font_glyph_t *sub_font_glyph;
sub_font_glyph = malloc (sizeof (cairo_sub_font_glyph_t));
- if (sub_font_glyph == NULL) {
+ if (unlikely (sub_font_glyph == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
@@ -267,7 +267,7 @@ _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent,
cairo_scaled_font_subsets_glyph_t subset_glyph;
sub_font = malloc (sizeof (cairo_sub_font_t));
- if (sub_font == NULL)
+ if (unlikely (sub_font == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
sub_font->is_scaled = is_scaled;
@@ -284,7 +284,7 @@ _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent,
sub_font->max_glyphs_per_subset = max_glyphs_per_subset;
sub_font->sub_font_glyphs = _cairo_hash_table_create (_cairo_sub_font_glyphs_equal);
- if (sub_font->sub_font_glyphs == NULL) {
+ if (unlikely (sub_font->sub_font_glyphs == NULL)) {
free (sub_font);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -294,7 +294,7 @@ _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent,
* Type 3 fonts */
if (! _cairo_font_face_is_user (scaled_font->font_face)) {
status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, -1, &subset_glyph);
- if (status) {
+ if (unlikely (status)) {
_cairo_hash_table_destroy (sub_font->sub_font_glyphs);
free (sub_font);
return status;
@@ -349,7 +349,7 @@ _cairo_sub_font_glyph_lookup_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
status = scaled_font->backend->index_to_ucs4 (scaled_font,
scaled_font_glyph_index,
&unicode);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -360,7 +360,7 @@ _cairo_sub_font_glyph_lookup_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
len = _cairo_ucs4_to_utf8 (unicode, buf);
if (len > 0) {
sub_font_glyph->utf8 = malloc (len + 1);
- if (sub_font_glyph->utf8 == NULL)
+ if (unlikely (sub_font_glyph->utf8 == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (sub_font_glyph->utf8, buf, len);
@@ -420,9 +420,9 @@ _cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font,
cairo_sub_font_glyph_t key, *sub_font_glyph;
_cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
- if (_cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base,
- (cairo_hash_entry_t **) &sub_font_glyph))
- {
+ sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs,
+ &key.base);
+ if (sub_font_glyph != NULL) {
subset_glyph->font_id = sub_font->font_id;
subset_glyph->subset_id = sub_font_glyph->subset_id;
subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index;
@@ -450,9 +450,9 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
cairo_status_t status;
_cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
- if (! _cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base,
- (cairo_hash_entry_t **) &sub_font_glyph))
- {
+ sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs,
+ &key.base);
+ if (sub_font_glyph == NULL) {
cairo_scaled_glyph_t *scaled_glyph;
if (sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset)
@@ -466,7 +466,7 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
* except for Type 3 fonts */
if (! _cairo_font_face_is_user (sub_font->scaled_font->font_face)) {
status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, -1, &tmp_subset_glyph);
- if (status)
+ if (unlikely (status))
return status;
}
}
@@ -477,7 +477,7 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
CAIRO_SCALED_GLYPH_INFO_METRICS,
&scaled_glyph);
assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
- if (status) {
+ if (unlikely (status)) {
_cairo_scaled_font_thaw_cache (sub_font->scaled_font);
return status;
}
@@ -489,19 +489,19 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
scaled_glyph->metrics.y_advance);
_cairo_scaled_font_thaw_cache (sub_font->scaled_font);
- if (sub_font_glyph == NULL)
+ if (unlikely (sub_font_glyph == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_sub_font_glyph_lookup_unicode (sub_font_glyph,
sub_font->scaled_font,
scaled_font_glyph_index);
- if (status) {
+ if (unlikely (status)) {
_cairo_sub_font_glyph_destroy (sub_font_glyph);
return status;
}
status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base);
- if (status) {
+ if (unlikely (status)) {
_cairo_sub_font_glyph_destroy (sub_font_glyph);
return status;
}
@@ -596,8 +596,8 @@ _cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type)
{
cairo_scaled_font_subsets_t *subsets;
- subsets = malloc (sizeof (cairo_scaled_font_subsets_t));
- if (subsets == NULL) {
+ subsets = malloc (sizeof (cairo_scaled_font_subsets_t));
+ if (unlikely (subsets == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
@@ -679,9 +679,9 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
if (subsets->type != CAIRO_SUBSETS_SCALED) {
key.is_scaled = FALSE;
_cairo_sub_font_init_key (&key, scaled_font);
- if (_cairo_hash_table_lookup (subsets->unscaled_sub_fonts, &key.base,
- (cairo_hash_entry_t **) &sub_font))
- {
+ sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts,
+ &key.base);
+ if (sub_font != NULL) {
if (_cairo_sub_font_lookup_glyph (sub_font,
scaled_font_glyph_index,
utf8, utf8_len,
@@ -693,9 +693,9 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
/* Lookup glyph in scaled subsets */
key.is_scaled = TRUE;
_cairo_sub_font_init_key (&key, scaled_font);
- if (_cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base,
- (cairo_hash_entry_t **) &sub_font))
- {
+ sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts,
+ &key.base);
+ if (sub_font != NULL) {
if (_cairo_sub_font_lookup_glyph (sub_font,
scaled_font_glyph_index,
utf8, utf8_len,
@@ -732,9 +732,9 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
/* Path available. Add to unscaled subset. */
key.is_scaled = FALSE;
_cairo_sub_font_init_key (&key, scaled_font);
- if (! _cairo_hash_table_lookup (subsets->unscaled_sub_fonts, &key.base,
- (cairo_hash_entry_t **) &sub_font))
- {
+ sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts,
+ &key.base);
+ if (sub_font == NULL) {
font_face = cairo_scaled_font_get_font_face (scaled_font);
cairo_matrix_init_identity (&identity);
_cairo_font_options_init_default (&font_options);
@@ -744,7 +744,7 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
&identity,
&identity,
&font_options);
- if (unscaled_font->status)
+ if (unlikely (unscaled_font->status))
return unscaled_font->status;
subset_glyph->is_scaled = FALSE;
@@ -768,7 +768,7 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
subset_glyph->is_composite,
&sub_font);
- if (status) {
+ if (unlikely (status)) {
cairo_scaled_font_destroy (unscaled_font);
return status;
}
@@ -776,7 +776,7 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts,
&sub_font->base);
- if (status) {
+ if (unlikely (status)) {
_cairo_sub_font_destroy (sub_font);
return status;
}
@@ -791,9 +791,9 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
/* No path available. Add to scaled subset. */
key.is_scaled = TRUE;
_cairo_sub_font_init_key (&key, scaled_font);
- if (! _cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base,
- (cairo_hash_entry_t **) &sub_font))
- {
+ sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts,
+ &key.base);
+ if (sub_font == NULL) {
subset_glyph->is_scaled = TRUE;
subset_glyph->is_composite = FALSE;
if (subsets->type == CAIRO_SUBSETS_SCALED)
@@ -808,14 +808,14 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
subset_glyph->is_scaled,
subset_glyph->is_composite,
&sub_font);
- if (status) {
+ if (unlikely (status)) {
cairo_scaled_font_destroy (scaled_font);
return status;
}
status = _cairo_hash_table_insert (subsets->scaled_sub_fonts,
&sub_font->base);
- if (status) {
+ if (unlikely (status)) {
_cairo_sub_font_destroy (sub_font);
return status;
}
@@ -866,7 +866,7 @@ _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t
collection.glyphs = _cairo_malloc_ab (collection.glyphs_size, sizeof(unsigned long));
collection.utf8 = _cairo_malloc_ab (collection.glyphs_size, sizeof(char *));
- if (collection.glyphs == NULL || collection.utf8 == NULL) {
+ if (unlikely (collection.glyphs == NULL || collection.utf8 == NULL)) {
if (collection.glyphs != NULL)
free (collection.glyphs);
if (collection.utf8 != NULL)
@@ -957,7 +957,7 @@ static cairo_status_t
create_string_entry (char *s, cairo_string_entry_t **entry)
{
*entry = malloc (sizeof (cairo_string_entry_t));
- if (*entry == NULL)
+ if (unlikely (*entry == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_cairo_string_init_key (*entry, s);
@@ -965,24 +965,31 @@ create_string_entry (char *s, cairo_string_entry_t **entry)
return CAIRO_STATUS_SUCCESS;
}
+static void
+_pluck_entry (void *entry, void *closure)
+{
+ _cairo_hash_table_remove (closure, entry);
+ free (entry);
+}
+
cairo_int_status_t
_cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset)
{
unsigned int i;
- cairo_status_t status;
cairo_hash_table_t *names;
cairo_string_entry_t key, *entry;
char buf[30];
char *utf8;
uint16_t *utf16;
int utf16_len;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
names = _cairo_hash_table_create (_cairo_string_equal);
- if (names == NULL)
+ if (unlikely (names == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
subset->glyph_names = calloc (subset->num_glyphs, sizeof (char *));
- if (subset->glyph_names == NULL) {
+ if (unlikely (subset->glyph_names == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_HASH;
}
@@ -990,17 +997,17 @@ _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset
i = 0;
if (! _cairo_font_face_is_user (subset->scaled_font->font_face)) {
subset->glyph_names[0] = strdup (".notdef");
- if (subset->glyph_names[0] == NULL) {
+ if (unlikely (subset->glyph_names[0] == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_HASH;
}
status = create_string_entry (subset->glyph_names[0], &entry);
- if (status)
+ if (unlikely (status))
goto CLEANUP_HASH;
status = _cairo_hash_table_insert (names, &entry->base);
- if (status) {
+ if (unlikely (status)) {
free (entry);
goto CLEANUP_HASH;
}
@@ -1013,52 +1020,44 @@ _cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset
utf16_len = 0;
if (utf8 && *utf8) {
status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
- if (status)
+ if (unlikely (status))
return status; /* FIXME */
}
if (utf16_len == 1) {
- snprintf (buf, sizeof(buf), "uni%04X", (int)(utf16[0]));
+ snprintf (buf, sizeof (buf), "uni%04X", (int) utf16[0]);
_cairo_string_init_key (&key, buf);
- if (_cairo_hash_table_lookup (names, &key.base,
- (cairo_hash_entry_t **) &entry)) {
- snprintf (buf, sizeof(buf), "g%d", i);
- }
+ entry = _cairo_hash_table_lookup (names, &key.base);
+ if (entry != NULL)
+ snprintf (buf, sizeof (buf), "g%d", i);
} else {
- snprintf (buf, sizeof(buf), "g%d", i);
+ snprintf (buf, sizeof (buf), "g%d", i);
}
if (utf16)
free (utf16);
subset->glyph_names[i] = strdup (buf);
- if (subset->glyph_names[i] == NULL) {
+ if (unlikely (subset->glyph_names[i] == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_HASH;
}
status = create_string_entry (subset->glyph_names[i], &entry);
- if (status)
+ if (unlikely (status))
goto CLEANUP_HASH;
status = _cairo_hash_table_insert (names, &entry->base);
- if (status) {
+ if (unlikely (status)) {
free (entry);
goto CLEANUP_HASH;
}
}
CLEANUP_HASH:
- while (1) {
- entry = _cairo_hash_table_random_entry (names, NULL);
- if (entry == NULL)
- break;
-
- _cairo_hash_table_remove (names, (cairo_hash_entry_t *) entry);
- free (entry);
- }
+ _cairo_hash_table_foreach (names, _pluck_entry, names);
_cairo_hash_table_destroy (names);
- if (status == CAIRO_STATUS_SUCCESS)
+ if (likely (status == CAIRO_STATUS_SUCCESS))
return CAIRO_STATUS_SUCCESS;
if (subset->glyph_names != NULL) {
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index bfeeaf66..ca86f512 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -201,6 +201,7 @@ static const cairo_scaled_font_t _cairo_scaled_font_nil = {
{ 1., 0., 0., 1., 0, 0}, /* scale_inverse */
1., /* max_scale */
{ 0., 0., 0., 0., 0. }, /* extents */
+ { 0., 0., 0., 0., 0. }, /* fs_extents */
CAIRO_MUTEX_NIL_INITIALIZER,/* mutex */
NULL, /* glyphs */
NULL, /* surface_backend */
@@ -320,14 +321,14 @@ _cairo_scaled_font_map_lock (void)
if (cairo_scaled_font_map == NULL) {
cairo_scaled_font_map = malloc (sizeof (cairo_scaled_font_map_t));
- if (cairo_scaled_font_map == NULL)
+ if (unlikely (cairo_scaled_font_map == NULL))
goto CLEANUP_MUTEX_LOCK;
cairo_scaled_font_map->mru_scaled_font = NULL;
cairo_scaled_font_map->hash_table =
_cairo_hash_table_create (_cairo_scaled_font_keys_equal);
- if (cairo_scaled_font_map->hash_table == NULL)
+ if (unlikely (cairo_scaled_font_map->hash_table == NULL))
goto CLEANUP_SCALED_FONT_MAP;
cairo_scaled_font_map->num_holdovers = 0;
@@ -359,7 +360,7 @@ _cairo_scaled_font_map_destroy (void)
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
font_map = cairo_scaled_font_map;
- if (font_map == NULL) {
+ if (unlikely (font_map == NULL)) {
goto CLEANUP_MUTEX_LOCK;
}
@@ -424,11 +425,11 @@ _cairo_scaled_font_register_placeholder_and_unlock_font_map (cairo_scaled_font_t
assert (CAIRO_MUTEX_IS_LOCKED (_cairo_scaled_font_map_mutex));
status = scaled_font->status;
- if (status)
+ if (unlikely (status))
return status;
placeholder_scaled_font = malloc (sizeof (cairo_scaled_font_t));
- if (placeholder_scaled_font == NULL)
+ if (unlikely (placeholder_scaled_font == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
/* full initialization is wasteful, but who cares... */
@@ -438,14 +439,14 @@ _cairo_scaled_font_register_placeholder_and_unlock_font_map (cairo_scaled_font_t
&scaled_font->ctm,
&scaled_font->options,
NULL);
- if (status)
+ if (unlikely (status))
goto FREE_PLACEHOLDER;
placeholder_scaled_font->placeholder = TRUE;
status = _cairo_hash_table_insert (cairo_scaled_font_map->hash_table,
&placeholder_scaled_font->hash_entry);
- if (status)
+ if (unlikely (status))
goto FINI_PLACEHOLDER;
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
@@ -465,19 +466,18 @@ void
_cairo_scaled_font_unregister_placeholder_and_lock_font_map (cairo_scaled_font_t *scaled_font)
{
cairo_scaled_font_t *placeholder_scaled_font;
- cairo_bool_t found;
CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex);
- found = _cairo_hash_table_lookup (cairo_scaled_font_map->hash_table,
- &scaled_font->hash_entry,
- (cairo_hash_entry_t**) &placeholder_scaled_font);
- assert (found);
+ placeholder_scaled_font =
+ _cairo_hash_table_lookup (cairo_scaled_font_map->hash_table,
+ &scaled_font->hash_entry);
+ assert (placeholder_scaled_font != NULL);
assert (placeholder_scaled_font->placeholder);
assert (CAIRO_MUTEX_IS_LOCKED (placeholder_scaled_font->mutex));
_cairo_hash_table_remove (cairo_scaled_font_map->hash_table,
- &scaled_font->hash_entry);
+ &placeholder_scaled_font->hash_entry);
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
@@ -599,7 +599,7 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
cairo_status_t status;
status = cairo_font_options_status ((cairo_font_options_t *) options);
- if (status)
+ if (unlikely (status))
return status;
_cairo_scaled_font_init_key (scaled_font, font_face,
@@ -613,7 +613,7 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
fabs (scaled_font->scale.yx) + fabs (scaled_font->scale.yy));
scaled_font->scale_inverse = scaled_font->scale;
status = cairo_matrix_invert (&scaled_font->scale_inverse);
- if (status) {
+ if (unlikely (status)) {
/* If the font scale matrix is rank 0, just using an all-zero inverse matrix
* makes everything work correctly. This make font size 0 work without
* producing an error.
@@ -638,7 +638,7 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
scaled_font->glyphs = _cairo_cache_create (_cairo_scaled_glyph_keys_equal,
_cairo_scaled_glyph_destroy,
MAX_GLYPHS_CACHED_PER_FONT);
- if (scaled_font->glyphs == NULL)
+ if (unlikely (scaled_font->glyphs == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
CAIRO_REFERENCE_COUNT_INIT (&scaled_font->ref_count, 1);
@@ -692,10 +692,12 @@ _cairo_scaled_font_set_metrics (cairo_scaled_font_t *scaled_font,
cairo_status_t status;
double font_scale_x, font_scale_y;
+ scaled_font->fs_extents = *fs_metrics;
+
status = _cairo_matrix_compute_basis_scale_factors (&scaled_font->font_matrix,
&font_scale_x, &font_scale_y,
1);
- if (status)
+ if (unlikely (status))
return status;
/*
@@ -780,7 +782,7 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
return _cairo_scaled_font_create_in_error (font_face->status);
status = cairo_font_options_status ((cairo_font_options_t *) options);
- if (status)
+ if (unlikely (status))
return _cairo_scaled_font_create_in_error (status);
/* Note that degenerate ctm or font_matrix *are* allowed.
@@ -789,13 +791,13 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
if (font_face->backend->get_implementation != NULL) {
/* indirect implementation, lookup the face that is used for the key */
status = font_face->backend->get_implementation (font_face, &impl_face);
- if (status)
+ if (unlikely (status))
return _cairo_scaled_font_create_in_error (status);
} else
impl_face = font_face;
font_map = _cairo_scaled_font_map_lock ();
- if (font_map == NULL)
+ if (unlikely (font_map == NULL))
return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_scaled_font_init_key (&key, impl_face,
@@ -818,13 +820,14 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
}
/* the font has been put into an error status - abandon the cache */
- _cairo_hash_table_remove (font_map->hash_table, &key.hash_entry);
+ _cairo_hash_table_remove (font_map->hash_table,
+ &scaled_font->hash_entry);
scaled_font->hash_entry.hash = ZOMBIE;
}
else
{
- while (_cairo_hash_table_lookup (font_map->hash_table, &key.hash_entry,
- (cairo_hash_entry_t**) &scaled_font))
+ while ((scaled_font = _cairo_hash_table_lookup (font_map->hash_table,
+ &key.hash_entry)))
{
if (! scaled_font->placeholder)
break;
@@ -877,7 +880,8 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
}
/* the font has been put into an error status - abandon the cache */
- _cairo_hash_table_remove (font_map->hash_table, &key.hash_entry);
+ _cairo_hash_table_remove (font_map->hash_table,
+ &scaled_font->hash_entry);
scaled_font->hash_entry.hash = ZOMBIE;
}
}
@@ -885,7 +889,7 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
/* Otherwise create it and insert it into the hash table. */
status = font_face->backend->scaled_font_create (font_face, font_matrix,
ctm, options, &scaled_font);
- if (status) {
+ if (unlikely (status)) {
_cairo_scaled_font_map_unlock ();
status = _cairo_font_face_set_error (font_face, status);
return _cairo_scaled_font_create_in_error (status);
@@ -901,7 +905,7 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
_cairo_scaled_font_map_unlock ();
- if (status) {
+ if (unlikely (status)) {
/* We can't call _cairo_scaled_font_destroy here since it expects
* that the font has already been successfully inserted into the
* hash table. */
@@ -931,9 +935,9 @@ _cairo_scaled_font_create_in_error (cairo_status_t status)
CAIRO_MUTEX_LOCK (_cairo_scaled_font_error_mutex);
scaled_font = _cairo_scaled_font_nil_objects[status];
- if (scaled_font == NULL) {
+ if (unlikely (scaled_font == NULL)) {
scaled_font = malloc (sizeof (cairo_scaled_font_t));
- if (scaled_font == NULL) {
+ if (unlikely (scaled_font == NULL)) {
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_scaled_font_t *) &_cairo_scaled_font_nil;
@@ -1036,7 +1040,8 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
lru = font_map->holdovers[0];
assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&lru->ref_count));
- _cairo_hash_table_remove (font_map->hash_table, &lru->hash_entry);
+ _cairo_hash_table_remove (font_map->hash_table,
+ &lru->hash_entry);
font_map->num_holdovers--;
memmove (&font_map->holdovers[0],
@@ -1216,7 +1221,7 @@ cairo_scaled_font_text_extents (cairo_scaled_font_t *scaled_font,
&glyphs, &num_glyphs,
NULL, NULL,
NULL);
- if (status) {
+ if (unlikely (status)) {
status = _cairo_scaled_font_set_error (scaled_font, status);
goto ZERO_EXTENTS;
}
@@ -1299,7 +1304,7 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_METRICS,
&scaled_glyph);
- if (status) {
+ if (unlikely (status)) {
status = _cairo_scaled_font_set_error (scaled_font, status);
goto UNLOCK;
}
@@ -1516,7 +1521,7 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
cairo_text_cluster_t *orig_clusters;
status = scaled_font->status;
- if (status)
+ if (unlikely (status))
return status;
/* A slew of sanity checks */
@@ -1579,7 +1584,7 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
/* validate input so backend does not have to */
status = _cairo_utf8_to_ucs4 (utf8, utf8_len, NULL, &num_chars);
- if (status)
+ if (unlikely (status))
goto BAIL;
_cairo_scaled_font_freeze_cache (scaled_font);
@@ -1637,7 +1642,7 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
if (*num_glyphs < num_chars) {
*glyphs = cairo_glyph_allocate (num_chars);
- if (*glyphs == NULL) {
+ if (unlikely (*glyphs == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto DONE;
}
@@ -1647,7 +1652,7 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
if (clusters) {
if (*num_clusters < num_chars) {
*clusters = cairo_text_cluster_allocate (num_chars);
- if (*clusters == NULL) {
+ if (unlikely (*clusters == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto DONE;
}
@@ -1677,7 +1682,7 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
(*glyphs)[i].index,
CAIRO_SCALED_GLYPH_INFO_METRICS,
&scaled_glyph);
- if (status) {
+ if (unlikely (status)) {
goto DONE;
}
@@ -1688,7 +1693,7 @@ cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
DONE: /* error that should be logged on scaled_font happened */
_cairo_scaled_font_thaw_cache (scaled_font);
- if (status) {
+ if (unlikely (status)) {
*num_glyphs = 0;
if (*glyphs != orig_glyphs) {
cairo_glyph_free (*glyphs);
@@ -1747,7 +1752,7 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_METRICS,
&scaled_glyph);
- if (status)
+ if (unlikely (status))
break;
/* XXX glyph images are snapped to pixel locations */
@@ -1766,7 +1771,7 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font,
}
_cairo_scaled_font_thaw_cache (scaled_font);
- if (status)
+ if (unlikely (status))
return _cairo_scaled_font_set_error (scaled_font, status);
if (min.x < max.x && min.y < max.y) {
@@ -1848,7 +1853,7 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
- if (status)
+ if (unlikely (status))
goto CLEANUP_MASK;
glyph_surface = scaled_glyph->surface;
@@ -1859,10 +1864,9 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
mask_format = glyph_surface->format;
mask = cairo_image_surface_create (mask_format,
width, height);
- if (mask->status) {
- status = mask->status;
+ status = mask->status;
+ if (unlikely (status))
goto CLEANUP_MASK;
- }
}
/* If we have glyphs of different formats, we "upgrade" the mask
@@ -1907,7 +1911,7 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
_cairo_pattern_fini (&mask_pattern.base);
- if (status) {
+ if (unlikely (status)) {
cairo_surface_destroy (new_mask);
goto CLEANUP_MASK;
}
@@ -1935,7 +1939,7 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
_cairo_pattern_fini (&glyph_pattern.base);
- if (status)
+ if (unlikely (status))
goto CLEANUP_MASK;
}
@@ -2022,29 +2026,29 @@ _add_unit_rectangle_to_path (cairo_path_fixed_t *path, int x, int y)
status = _cairo_path_fixed_move_to (path,
_cairo_fixed_from_int (x),
_cairo_fixed_from_int (y));
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_path_fixed_rel_line_to (path,
_cairo_fixed_from_int (1),
_cairo_fixed_from_int (0));
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_path_fixed_rel_line_to (path,
_cairo_fixed_from_int (0),
_cairo_fixed_from_int (1));
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_path_fixed_rel_line_to (path,
_cairo_fixed_from_int (-1),
_cairo_fixed_from_int (0));
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_path_fixed_close_path (path);
- if (status)
+ if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
@@ -2084,7 +2088,7 @@ _trace_mask_to_path (cairo_image_surface_t *mask,
a1_mask = _cairo_image_surface_clone (mask, CAIRO_FORMAT_A1);
status = cairo_surface_status (&a1_mask->base);
- if (status) {
+ if (unlikely (status)) {
cairo_surface_destroy (&a1_mask->base);
return status;
}
@@ -2099,7 +2103,7 @@ _trace_mask_to_path (cairo_image_surface_t *mask,
if (byte & (1 << bit)) {
status = _add_unit_rectangle_to_path (path,
x - xoff, y - yoff);
- if (status)
+ if (unlikely (status))
goto BAIL;
}
}
@@ -2124,7 +2128,7 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
cairo_path_fixed_t *glyph_path;
status = scaled_font->status;
- if (status)
+ if (unlikely (status))
return status;
closure.path = path;
@@ -2148,17 +2152,17 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
- if (status)
+ if (unlikely (status))
goto BAIL;
glyph_path = _cairo_path_fixed_create ();
- if (glyph_path == NULL) {
+ if (unlikely (glyph_path == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL;
}
status = _trace_mask_to_path (scaled_glyph->surface, glyph_path);
- if (status) {
+ if (unlikely (status)) {
_cairo_path_fixed_destroy (glyph_path);
goto BAIL;
}
@@ -2177,7 +2181,7 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
if (glyph_path != scaled_glyph->path)
_cairo_path_fixed_destroy (glyph_path);
- if (status)
+ if (unlikely (status))
goto BAIL;
}
BAIL:
@@ -2208,6 +2212,8 @@ _cairo_scaled_glyph_set_metrics (cairo_scaled_glyph_t *scaled_glyph,
double min_device_x = 0.0, max_device_x = 0.0, min_device_y = 0.0, max_device_y = 0.0;
double device_x_advance, device_y_advance;
+ scaled_glyph->fs_metrics = *fs_metrics;
+
for (hm = 0.0; hm <= 1.0; hm += 1.0)
for (wm = 0.0; wm <= 1.0; wm += 1.0) {
double x, y;
@@ -2348,14 +2354,13 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
* Check cache for glyph
*/
info |= CAIRO_SCALED_GLYPH_INFO_METRICS;
- if (!_cairo_cache_lookup (scaled_font->glyphs, &key,
- (cairo_cache_entry_t **) &scaled_glyph))
- {
+ scaled_glyph = _cairo_cache_lookup (scaled_font->glyphs, &key);
+ if (scaled_glyph == NULL) {
/*
* On miss, create glyph and insert into cache
*/
scaled_glyph = malloc (sizeof (cairo_scaled_glyph_t));
- if (scaled_glyph == NULL) {
+ if (unlikely (scaled_glyph == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP;
}
@@ -2371,7 +2376,7 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
/* ask backend to initialize metrics and shape fields */
status = (*scaled_font->backend->
scaled_glyph_init) (scaled_font, scaled_glyph, info);
- if (status) {
+ if (unlikely (status)) {
_cairo_scaled_glyph_destroy (scaled_glyph);
goto CLEANUP;
}
@@ -2379,7 +2384,7 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
/* on success, the cache takes ownership of the scaled_glyph */
status = _cairo_cache_insert (scaled_font->glyphs,
&scaled_glyph->cache_entry);
- if (status) {
+ if (unlikely (status)) {
_cairo_scaled_glyph_destroy (scaled_glyph);
goto CLEANUP;
}
@@ -2404,7 +2409,7 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
if (need_info) {
status = (*scaled_font->backend->
scaled_glyph_init) (scaled_font, scaled_glyph, need_info);
- if (status)
+ if (unlikely (status))
goto CLEANUP;
/* Don't trust the scaled_glyph_init() return value, the font
@@ -2432,7 +2437,7 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
}
CLEANUP:
- if (status) {
+ if (unlikely (status)) {
/* It's not an error for the backend to not support the info we want. */
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
status = _cairo_scaled_font_set_error (scaled_font, status);
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
new file mode 100644
index 00000000..cf2809f5
--- /dev/null
+++ b/src/cairo-script-surface.c
@@ -0,0 +1,2600 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2008 Chris Wilson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Chris Wilson.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+/* The script surface is one that records all operations performed on
+ * it in the form of a procedural script, similar in fashion to
+ * PostScript but using Cairo's imaging model. In essence, this is
+ * equivalent to the meta-surface, but as there is no impedance mismatch
+ * between Cairo and CairoScript, we can generate output immediately
+ * without having to copy and hold the data in memory.
+ */
+
+#include "cairoint.h"
+
+#include "cairo-script.h"
+
+#include "cairo-analysis-surface-private.h"
+#include "cairo-ft-private.h"
+#include "cairo-meta-surface-private.h"
+#include "cairo-output-stream-private.h"
+
+#define _cairo_output_stream_puts(S, STR) \
+ _cairo_output_stream_write ((S), (STR), strlen (STR))
+
+#define static cairo_warn static
+
+typedef struct _cairo_script_vmcontext cairo_script_vmcontext_t;
+typedef struct _cairo_script_surface cairo_script_surface_t;
+typedef struct _cairo_script_implicit_context cairo_script_implicit_context_t;
+typedef struct _cairo_script_surface_font_private cairo_script_surface_font_private_t;
+
+struct _cairo_script_vmcontext {
+ int ref;
+
+ cairo_output_stream_t *stream;
+ cairo_script_mode_t mode;
+
+ struct _bitmap {
+ unsigned long min;
+ unsigned long count;
+ unsigned int map[64];
+ struct _bitmap *next;
+ } surface_id, font_id;
+
+ cairo_script_surface_t *current_target;
+
+ cairo_script_surface_font_private_t *fonts;
+};
+
+struct _cairo_script_surface_font_private {
+ cairo_script_vmcontext_t *ctx;
+ cairo_bool_t has_sfnt;
+ unsigned long id;
+ unsigned long subset_glyph_index;
+ cairo_script_surface_font_private_t *prev, *next;
+ cairo_scaled_font_t *parent;
+};
+
+struct _cairo_script_implicit_context {
+ cairo_operator_t current_operator;
+ cairo_fill_rule_t current_fill_rule;
+ double current_tolerance;
+ cairo_antialias_t current_antialias;
+ cairo_stroke_style_t current_style;
+ cairo_pattern_t *current_source;
+ cairo_matrix_t current_ctm;
+ cairo_matrix_t current_font_matrix;
+ cairo_font_options_t current_font_options;
+ cairo_scaled_font_t *current_scaled_font;
+ cairo_path_fixed_t current_path;
+};
+
+struct _cairo_script_surface {
+ cairo_surface_t base;
+
+ cairo_script_vmcontext_t *ctx;
+
+ unsigned long id;
+
+ double width, height;
+
+ /* implicit flattened context */
+ cairo_script_implicit_context_t cr;
+};
+
+static const cairo_surface_backend_t _cairo_script_surface_backend;
+
+static cairo_script_surface_t *
+_cairo_script_surface_create_internal (cairo_script_vmcontext_t *ctx,
+ double width,
+ double height);
+
+static void
+_cairo_script_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
+
+static void
+_cairo_script_implicit_context_init (cairo_script_implicit_context_t *cr);
+
+static void
+_bitmap_release_id (struct _bitmap *b, unsigned long token)
+{
+ struct _bitmap **prev = NULL;
+
+ do {
+ if (token < b->min + sizeof (b->map) * CHAR_BIT) {
+ unsigned int bit, elem;
+
+ token -= b->min;
+ elem = token / (sizeof (b->map[0]) * CHAR_BIT);
+ bit = token % (sizeof (b->map[0]) * CHAR_BIT);
+ b->map[elem] &= ~(1 << bit);
+ if (! --b->count && prev) {
+ *prev = b->next;
+ free (b);
+ }
+ return;
+ }
+ prev = &b->next;
+ b = b->next;
+ } while (b != NULL);
+}
+
+static cairo_status_t
+_bitmap_next_id (struct _bitmap *b,
+ unsigned long *id)
+{
+ struct _bitmap *bb, **prev = NULL;
+ unsigned long min = 0;
+
+ do {
+ if (b->min != min)
+ break;
+
+ if (b->count < sizeof (b->map) * CHAR_BIT) {
+ unsigned int n, m, bit;
+ for (n = 0; n < ARRAY_LENGTH (b->map); n++) {
+ if (b->map[n] == (unsigned int) -1)
+ continue;
+
+ for (m=0, bit=1; m<sizeof (b->map[0])*CHAR_BIT; m++, bit<<=1) {
+ if ((b->map[n] & bit) == 0) {
+ b->map[n] |= bit;
+ b->count++;
+ *id = n * sizeof (b->map[0])*CHAR_BIT + m + b->min;
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+ }
+ }
+ min += sizeof (b->map) * CHAR_BIT;
+
+ prev = &b->next;
+ b = b->next;
+ } while (b != NULL);
+
+ bb = malloc (sizeof (struct _bitmap));
+ if (unlikely (bb == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ *prev = bb;
+ bb->next = b;
+ bb->min = min;
+ bb->count = 1;
+ bb->map[0] = 0x1;
+ memset (bb->map + 1, 0, sizeof (bb->map) - sizeof (bb->map[0]));
+ *id = min;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static const char *
+_direction_to_string (cairo_bool_t backward)
+{
+ static const char *names[] = {
+ "FORWARD",
+ "BACKWARD"
+ };
+ assert (backward < ARRAY_LENGTH (names));
+ return names[backward];
+}
+
+static const char *
+_operator_to_string (cairo_operator_t op)
+{
+ static const char *names[] = {
+ "CLEAR", /* CAIRO_OPERATOR_CLEAR */
+
+ "SOURCE", /* CAIRO_OPERATOR_SOURCE */
+ "OVER", /* CAIRO_OPERATOR_OVER */
+ "IN", /* CAIRO_OPERATOR_IN */
+ "OUT", /* CAIRO_OPERATOR_OUT */
+ "ATOP", /* CAIRO_OPERATOR_ATOP */
+
+ "DEST", /* CAIRO_OPERATOR_DEST */
+ "DEST_OVER", /* CAIRO_OPERATOR_DEST_OVER */
+ "DEST_IN", /* CAIRO_OPERATOR_DEST_IN */
+ "DEST_OUT", /* CAIRO_OPERATOR_DEST_OUT */
+ "DEST_ATOP", /* CAIRO_OPERATOR_DEST_ATOP */
+
+ "XOR", /* CAIRO_OPERATOR_XOR */
+ "ADD", /* CAIRO_OPERATOR_ADD */
+ "SATURATE" /* CAIRO_OPERATOR_SATURATE */
+ };
+ assert (op < ARRAY_LENGTH (names));
+ return names[op];
+}
+
+static const char *
+_extend_to_string (cairo_extend_t extend)
+{
+ static const char *names[] = {
+ "EXTEND_NONE", /* CAIRO_EXTEND_NONE */
+ "EXTEND_REPEAT", /* CAIRO_EXTEND_REPEAT */
+ "EXTEND_REFLECT", /* CAIRO_EXTEND_REFLECT */
+ "EXTEND_PAD" /* CAIRO_EXTEND_PAD */
+ };
+ assert (extend < ARRAY_LENGTH (names));
+ return names[extend];
+}
+
+static const char *
+_filter_to_string (cairo_filter_t filter)
+{
+ static const char *names[] = {
+ "FILTER_FAST", /* CAIRO_FILTER_FAST */
+ "FILTER_GOOD", /* CAIRO_FILTER_GOOD */
+ "FILTER_BEST", /* CAIRO_FILTER_BEST */
+ "FILTER_NEAREST", /* CAIRO_FILTER_NEAREST */
+ "FILTER_BILINEAR", /* CAIRO_FILTER_BILINEAR */
+ "FILTER_GAUSSIAN", /* CAIRO_FILTER_GAUSSIAN */
+ };
+ assert (filter < ARRAY_LENGTH (names));
+ return names[filter];
+}
+
+static const char *
+_fill_rule_to_string (cairo_fill_rule_t rule)
+{
+ static const char *names[] = {
+ "WINDING", /* CAIRO_FILL_RULE_WINDING */
+ "EVEN_ODD" /* CAIRO_FILL_RILE_EVEN_ODD */
+ };
+ assert (rule < ARRAY_LENGTH (names));
+ return names[rule];
+}
+
+static const char *
+_antialias_to_string (cairo_antialias_t antialias)
+{
+ static const char *names[] = {
+ "ANTIALIAS_DEFAULT", /* CAIRO_ANTIALIAS_DEFAULT */
+ "ANTIALIAS_NONE", /* CAIRO_ANTIALIAS_NONE */
+ "ANTIALIAS_GRAY", /* CAIRO_ANTIALIAS_GRAY */
+ "ANTIALIAS_SUBPIXEL" /* CAIRO_ANTIALIAS_SUBPIXEL */
+ };
+ assert (antialias < ARRAY_LENGTH (names));
+ return names[antialias];
+}
+
+static const char *
+_line_cap_to_string (cairo_line_cap_t line_cap)
+{
+ static const char *names[] = {
+ "LINE_CAP_BUTT", /* CAIRO_LINE_CAP_BUTT */
+ "LINE_CAP_ROUND", /* CAIRO_LINE_CAP_ROUND */
+ "LINE_CAP_SQUARE" /* CAIRO_LINE_CAP_SQUARE */
+ };
+ assert (line_cap < ARRAY_LENGTH (names));
+ return names[line_cap];
+}
+
+static const char *
+_line_join_to_string (cairo_line_join_t line_join)
+{
+ static const char *names[] = {
+ "LINE_JOIN_MITER", /* CAIRO_LINE_JOIN_MITER */
+ "LINE_JOIN_ROUND", /* CAIRO_LINE_JOIN_ROUND */
+ "LINE_JOIN_BEVEL", /* CAIRO_LINE_JOIN_BEVEL */
+ };
+ assert (line_join < ARRAY_LENGTH (names));
+ return names[line_join];
+}
+
+static cairo_bool_t
+_cairo_script_surface_owns_context (cairo_script_surface_t *surface)
+{
+ return surface->ctx->current_target == surface;
+}
+
+static cairo_status_t
+_emit_context (cairo_script_surface_t *surface)
+{
+ if (_cairo_script_surface_owns_context (surface))
+ return CAIRO_STATUS_SUCCESS;
+
+ if (surface->ctx->current_target != NULL)
+ _cairo_output_stream_puts (surface->ctx->stream, "pop\n");
+
+ surface->ctx->current_target = surface;
+
+ if (surface->id == (unsigned long) -1) {
+ cairo_status_t status;
+
+ status = _bitmap_next_id (&surface->ctx->surface_id,
+ &surface->id);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "dict\n"
+ " /width %f set\n"
+ " /height %f set\n",
+ surface->width,
+ surface->height);
+ if (surface->base.x_fallback_resolution !=
+ CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT ||
+ surface->base.y_fallback_resolution !=
+ CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT)
+ {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ " /fallback-resolution [%f %f] set\n",
+ surface->base.x_fallback_resolution,
+ surface->base.y_fallback_resolution);
+ }
+ if (surface->base.device_transform.x0 != 0. ||
+ surface->base.device_transform.y0 != 0.)
+ {
+ /* XXX device offset is encoded into the pattern matrices etc. */
+ _cairo_output_stream_printf (surface->ctx->stream,
+ " %%/device-offset [%f %f] set\n",
+ surface->base.device_transform.x0,
+ surface->base.device_transform.y0);
+ }
+ _cairo_output_stream_printf (surface->ctx->stream,
+ " surface dup /s%lu exch def\n"
+ "context dup /c%lu exch def\n",
+ surface->id,
+ surface->id);
+ } else {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "c%lu\n",
+ surface->id);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_operator (cairo_script_surface_t *surface,
+ cairo_operator_t op)
+{
+ assert (_cairo_script_surface_owns_context (surface));
+
+ if (surface->cr.current_operator == op)
+ return CAIRO_STATUS_SUCCESS;
+
+ surface->cr.current_operator = op;
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "//%s set_operator\n",
+ _operator_to_string (op));
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_fill_rule (cairo_script_surface_t *surface,
+ cairo_fill_rule_t fill_rule)
+{
+ assert (_cairo_script_surface_owns_context (surface));
+
+ if (surface->cr.current_fill_rule == fill_rule)
+ return CAIRO_STATUS_SUCCESS;
+
+ surface->cr.current_fill_rule = fill_rule;
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "//%s set_fill_rule\n",
+ _fill_rule_to_string (fill_rule));
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_tolerance (cairo_script_surface_t *surface,
+ double tolerance,
+ cairo_bool_t force)
+{
+ assert (_cairo_script_surface_owns_context (surface));
+
+ if (! force && surface->cr.current_tolerance == tolerance)
+ return CAIRO_STATUS_SUCCESS;
+
+ surface->cr.current_tolerance = tolerance;
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "%f set_tolerance\n",
+ tolerance);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_antialias (cairo_script_surface_t *surface,
+ cairo_antialias_t antialias)
+{
+ assert (_cairo_script_surface_owns_context (surface));
+
+ if (surface->cr.current_antialias == antialias)
+ return CAIRO_STATUS_SUCCESS;
+
+ surface->cr.current_antialias = antialias;
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "//%s set_antialias\n",
+ _antialias_to_string (antialias));
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_line_width (cairo_script_surface_t *surface,
+ double line_width,
+ cairo_bool_t force)
+{
+ assert (_cairo_script_surface_owns_context (surface));
+
+ if (! force && surface->cr.current_style.line_width == line_width)
+ return CAIRO_STATUS_SUCCESS;
+
+ surface->cr.current_style.line_width = line_width;
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "%f set_line_width\n",
+ line_width);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_line_cap (cairo_script_surface_t *surface,
+ cairo_line_cap_t line_cap)
+{
+ assert (_cairo_script_surface_owns_context (surface));
+
+ if (surface->cr.current_style.line_cap == line_cap)
+ return CAIRO_STATUS_SUCCESS;
+
+ surface->cr.current_style.line_cap = line_cap;
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "//%s set_line_cap\n",
+ _line_cap_to_string (line_cap));
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_line_join (cairo_script_surface_t *surface,
+ cairo_line_join_t line_join)
+{
+ assert (_cairo_script_surface_owns_context (surface));
+
+ if (surface->cr.current_style.line_join == line_join)
+ return CAIRO_STATUS_SUCCESS;
+
+ surface->cr.current_style.line_join = line_join;
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "//%s set_line_join\n",
+ _line_join_to_string (line_join));
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_miter_limit (cairo_script_surface_t *surface,
+ double miter_limit,
+ cairo_bool_t force)
+{
+ assert (_cairo_script_surface_owns_context (surface));
+
+ if (! force && surface->cr.current_style.miter_limit == miter_limit)
+ return CAIRO_STATUS_SUCCESS;
+
+ surface->cr.current_style.miter_limit = miter_limit;
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "%f set_miter_limit\n",
+ miter_limit);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_dash (cairo_script_surface_t *surface,
+ const double *dash,
+ unsigned int num_dashes,
+ double offset,
+ cairo_bool_t force)
+{
+ unsigned int n;
+
+ assert (_cairo_script_surface_owns_context (surface));
+
+ if (force &&
+ num_dashes == 0 &&
+ surface->cr.current_style.num_dashes == 0)
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (! force &&
+ (surface->cr.current_style.num_dashes == num_dashes &&
+ (num_dashes == 0 ||
+ (surface->cr.current_style.dash_offset == offset &&
+ memcmp (surface->cr.current_style.dash, dash,
+ sizeof (double) * num_dashes)))))
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+
+ if (num_dashes) {
+ surface->cr.current_style.dash = _cairo_realloc_ab
+ (surface->cr.current_style.dash,
+ num_dashes,
+ sizeof (double));
+ memcpy (surface->cr.current_style.dash, dash,
+ sizeof (double) * num_dashes);
+ } else {
+ if (surface->cr.current_style.dash != NULL) {
+ free (surface->cr.current_style.dash);
+ surface->cr.current_style.dash = NULL;
+ }
+ }
+
+ surface->cr.current_style.num_dashes = num_dashes;
+ surface->cr.current_style.dash_offset = offset;
+
+ _cairo_output_stream_printf (surface->ctx->stream, "[");
+ for (n = 0; n < num_dashes; n++) {
+ _cairo_output_stream_printf (surface->ctx->stream, "%f", dash[n]);
+ if (n < num_dashes-1)
+ _cairo_output_stream_puts (surface->ctx->stream, " ");
+ }
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "] %f set_dash\n",
+ offset);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_stroke_style (cairo_script_surface_t *surface,
+ const cairo_stroke_style_t *style,
+ cairo_bool_t force)
+{
+ cairo_status_t status;
+
+ assert (_cairo_script_surface_owns_context (surface));
+
+ status = _emit_line_width (surface, style->line_width, force);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_line_cap (surface, style->line_cap);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_line_join (surface, style->line_join);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_miter_limit (surface, style->miter_limit, force);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_dash (surface,
+ style->dash, style->num_dashes, style->dash_offset,
+ force);
+ if (unlikely (status))
+ return status;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static const char *
+_format_to_string (cairo_format_t format)
+{
+ static const char *names[] = {
+ "ARGB32", /* CAIRO_FORMAT_ARGB32 */
+ "RGB24", /* CAIRO_FORMAT_RGB24 */
+ "A8", /* CAIRO_FORMAT_A8 */
+ "A1" /* CAIRO_FORMAT_A1 */
+ };
+ assert (format < ARRAY_LENGTH (names));
+ return names[format];
+}
+
+static cairo_status_t
+_emit_solid_pattern (cairo_script_surface_t *surface,
+ const cairo_pattern_t *pattern)
+{
+ cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
+
+ if (solid->content & CAIRO_CONTENT_ALPHA &&
+ ! CAIRO_COLOR_IS_OPAQUE (&solid->color))
+ {
+ if (! (solid->content & CAIRO_CONTENT_COLOR) ||
+ (solid->color.red_short == 0 &&
+ solid->color.green_short == 0 &&
+ solid->color.blue_short == 0))
+ {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "%f a",
+ solid->color.alpha);
+ }
+ else
+ {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "%f %f %f %f rgba",
+ solid->color.red,
+ solid->color.green,
+ solid->color.blue,
+ solid->color.alpha);
+ }
+ }
+ else
+ {
+ if (solid->color.red_short == solid->color.green_short &&
+ solid->color.red_short == solid->color.blue_short)
+ {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "%f g",
+ solid->color.red);
+ }
+ else
+ {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "%f %f %f rgb",
+ solid->color.red,
+ solid->color.green,
+ solid->color.blue);
+ }
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+static cairo_status_t
+_emit_gradient_color_stops (cairo_gradient_pattern_t *gradient,
+ cairo_output_stream_t *output)
+{
+ unsigned int n;
+
+ for (n = 0; n < gradient->n_stops; n++) {
+ _cairo_output_stream_printf (output,
+ " %f %f %f %f %f add_color_stop\n ",
+ gradient->stops[n].offset,
+ gradient->stops[n].color.red,
+ gradient->stops[n].color.green,
+ gradient->stops[n].color.blue,
+ gradient->stops[n].color.alpha);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_linear_pattern (cairo_script_surface_t *surface,
+ const cairo_pattern_t *pattern)
+{
+ cairo_linear_pattern_t *linear;
+
+ linear = (cairo_linear_pattern_t *) pattern;
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "%f %f %f %f linear\n ",
+ _cairo_fixed_to_double (linear->p1.x),
+ _cairo_fixed_to_double (linear->p1.y),
+ _cairo_fixed_to_double (linear->p2.x),
+ _cairo_fixed_to_double (linear->p2.y));
+ return _emit_gradient_color_stops (&linear->base, surface->ctx->stream);
+}
+
+static cairo_status_t
+_emit_radial_pattern (cairo_script_surface_t *surface,
+ const cairo_pattern_t *pattern)
+{
+ cairo_radial_pattern_t *radial;
+
+ radial = (cairo_radial_pattern_t *) pattern;
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "%f %f %f %f %f %f radial\n ",
+ _cairo_fixed_to_double (radial->c1.x),
+ _cairo_fixed_to_double (radial->c1.y),
+ _cairo_fixed_to_double (radial->r1),
+ _cairo_fixed_to_double (radial->c2.x),
+ _cairo_fixed_to_double (radial->c2.y),
+ _cairo_fixed_to_double (radial->r2));
+ return _emit_gradient_color_stops (&radial->base, surface->ctx->stream);
+}
+
+static cairo_status_t
+_emit_meta_surface_pattern (cairo_script_surface_t *surface,
+ const cairo_pattern_t *pattern)
+{
+ cairo_surface_pattern_t *surface_pattern;
+ cairo_surface_t *source;
+ cairo_surface_t *null_surface;
+ cairo_surface_t *analysis_surface;
+ cairo_surface_t *similar;
+ cairo_status_t status;
+ cairo_box_t bbox;
+
+ surface_pattern = (cairo_surface_pattern_t *) pattern;
+ source = surface_pattern->surface;
+
+ /* first measure the extents */
+ null_surface = _cairo_null_surface_create (source->content);
+ analysis_surface = _cairo_analysis_surface_create (null_surface, -1, -1);
+ cairo_surface_destroy (null_surface);
+
+ status = analysis_surface->status;
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_meta_surface_replay (source, analysis_surface);
+ _cairo_analysis_surface_get_bounding_box (analysis_surface, &bbox);
+ cairo_surface_destroy (analysis_surface);
+ if (unlikely (status))
+ return status;
+
+ similar = cairo_surface_create_similar (&surface->base,
+ source->content,
+ _cairo_fixed_to_double (bbox.p2.x-bbox.p1.x),
+ _cairo_fixed_to_double (bbox.p2.y-bbox.p1.y));
+ if (similar->status)
+ return similar->status;
+
+ status = _cairo_meta_surface_replay (source, similar);
+ if (unlikely (status)) {
+ cairo_surface_destroy (similar);
+ return status;
+ }
+
+ status = _emit_context (surface);
+ if (unlikely (status)) {
+ cairo_surface_destroy (similar);
+ return status;
+ }
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "s%lu pattern\n ",
+ ((cairo_script_surface_t *) similar)->id);
+ cairo_surface_destroy (similar);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_script_surface_pattern (cairo_script_surface_t *surface,
+ const cairo_pattern_t *pattern)
+{
+ cairo_surface_pattern_t *surface_pattern;
+ cairo_script_surface_t *source;
+
+ surface_pattern = (cairo_surface_pattern_t *) pattern;
+ source = (cairo_script_surface_t *) surface_pattern->surface;
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "s%lu pattern\n ", source->id);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_write_image_surface (cairo_output_stream_t *output,
+ const cairo_image_surface_t *image)
+{
+ int stride, row, width;
+ uint8_t row_stack[CAIRO_STACK_BUFFER_SIZE];
+ uint8_t *rowdata;
+ uint8_t *data;
+
+ stride = image->stride;
+ width = image->width;
+ data = image->data;
+#if WORDS_BIGENDIAN
+ switch (image->format) {
+ case CAIRO_FORMAT_A1:
+ for (row = image->height; row--; ) {
+ _cairo_output_stream_write (output, data, (width+7)/8);
+ data += stride;
+ }
+ break;
+ case CAIRO_FORMAT_A8:
+ for (row = image->height; row--; ) {
+ _cairo_output_stream_write (output, data, width);
+ data += stride;
+ }
+ break;
+ case CAIRO_FORMAT_RGB24:
+ for (row = image->height; row--; ) {
+ int col;
+ rowdata = data;
+ for (col = width; col--; ) {
+ _cairo_output_stream_write (output, rowdata, 3);
+ rowdata+=4;
+ }
+ data += stride;
+ }
+ break;
+ case CAIRO_FORMAT_ARGB32:
+ for (row = image->height; row--; ) {
+ _cairo_output_stream_write (output, data, 4*width);
+ data += stride;
+ }
+ break;
+ default:
+ ASSERT_NOT_REACHED;
+ break;
+ }
+#else
+ if (stride > ARRAY_LENGTH (row_stack)) {
+ rowdata = malloc (stride);
+ if (unlikely (rowdata == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ } else
+ rowdata = row_stack;
+
+ switch (image->format) {
+ case CAIRO_FORMAT_A1:
+ for (row = image->height; row--; ) {
+ int col;
+ for (col = 0; col < (width + 7)/8; col++)
+ rowdata[col] = CAIRO_BITSWAP8 (data[col]);
+ _cairo_output_stream_write (output, rowdata, (width+7)/8);
+ data += stride;
+ }
+ break;
+ case CAIRO_FORMAT_A8:
+ for (row = image->height; row--; ) {
+ _cairo_output_stream_write (output, data, width);
+ data += stride;
+ }
+ break;
+ case CAIRO_FORMAT_RGB24:
+ for (row = image->height; row--; ) {
+ uint8_t *src = data;
+ int col;
+ for (col = 0; col < width; col++) {
+ rowdata[3*col+2] = *src++;
+ rowdata[3*col+1] = *src++;
+ rowdata[3*col+0] = *src++;
+ src++;
+ }
+ _cairo_output_stream_write (output, rowdata, 3*width);
+ data += stride;
+ }
+ break;
+ case CAIRO_FORMAT_ARGB32:
+ for (row = image->height; row--; ) {
+ uint32_t *src = (uint32_t *) data;
+ uint32_t *dst = (uint32_t *) rowdata;
+ int col;
+ for (col = 0; col < width; col++)
+ dst[col] = bswap_32 (src[col]);
+ _cairo_output_stream_write (output, rowdata, 4*width);
+ data += stride;
+ }
+ break;
+ default:
+ ASSERT_NOT_REACHED;
+ break;
+ }
+ if (rowdata != row_stack)
+ free (rowdata);
+#endif
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_emit_png_surface (cairo_script_surface_t *surface,
+ cairo_image_surface_t *image)
+{
+ cairo_output_stream_t *base85_stream;
+ cairo_status_t status;
+ const uint8_t *mime_data;
+ unsigned int mime_data_length;
+
+ cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_PNG,
+ &mime_data, &mime_data_length);
+ if (mime_data == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "dict\n"
+ " /width %d set\n"
+ " /height %d set\n"
+ " /format //%s set\n"
+ " /mime-type (image/png) set\n"
+ " /source <~",
+ image->width, image->height,
+ _format_to_string (image->format));
+
+ base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
+ _cairo_output_stream_write (base85_stream, mime_data, mime_data_length);
+ status = _cairo_output_stream_destroy (base85_stream);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_puts (surface->ctx->stream,
+ " set\n image");
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_image_surface (cairo_script_surface_t *surface,
+ cairo_image_surface_t *image)
+{
+ cairo_output_stream_t *base85_stream;
+ cairo_output_stream_t *zlib_stream;
+ cairo_status_t status, status2;
+ const uint8_t *mime_data;
+ unsigned int mime_data_length;
+
+ status = _emit_png_surface (surface, image);
+ if (_cairo_status_is_error (status)) {
+ return status;
+ } else if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "dict\n"
+ " /width %d set\n"
+ " /height %d set\n"
+ " /format //%s set\n"
+ " /source <~",
+ image->width, image->height,
+ _format_to_string (image->format));
+
+ if (image->width * image->height > 8) {
+ base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
+ zlib_stream = _cairo_deflate_stream_create (base85_stream);
+
+ status = _write_image_surface (zlib_stream, image);
+
+ status2 = _cairo_output_stream_destroy (zlib_stream);
+ if (status == CAIRO_STATUS_SUCCESS)
+ status = status2;
+ status2 = _cairo_output_stream_destroy (base85_stream);
+ if (status == CAIRO_STATUS_SUCCESS)
+ status = status2;
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_puts (surface->ctx->stream,
+ " /deflate filter set\n image");
+ } else {
+ base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
+ status = _write_image_surface (base85_stream, image);
+ status2 = _cairo_output_stream_destroy (base85_stream);
+ if (status == CAIRO_STATUS_SUCCESS)
+ status = status2;
+
+ _cairo_output_stream_puts (surface->ctx->stream,
+ " set\n image");
+ }
+ }
+
+ cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_JPEG,
+ &mime_data, &mime_data_length);
+ if (mime_data != NULL) {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "\n (%s) <~",
+ CAIRO_MIME_TYPE_JPEG);
+
+ base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
+ _cairo_output_stream_write (base85_stream, mime_data, mime_data_length);
+ status = _cairo_output_stream_destroy (base85_stream);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_puts (surface->ctx->stream,
+ " set_mime_data\n ");
+ }
+
+ _cairo_output_stream_puts (surface->ctx->stream,
+ " pattern\n ");
+
+ return status;
+}
+
+static cairo_status_t
+_emit_image_surface_pattern (cairo_script_surface_t *surface,
+ const cairo_pattern_t *pattern)
+{
+ cairo_surface_pattern_t *surface_pattern;
+ cairo_surface_t *source;
+ cairo_image_surface_t *image;
+ void *image_extra;
+ cairo_status_t status;
+
+ surface_pattern = (cairo_surface_pattern_t *) pattern;
+ source = surface_pattern->surface;
+
+ /* XXX snapshot-cow */
+ status = _cairo_surface_acquire_source_image (source, &image, &image_extra);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_image_surface (surface, image);
+
+ _cairo_surface_release_source_image (source, image, image_extra);
+
+ return status;
+}
+
+static cairo_status_t
+_emit_surface_pattern (cairo_script_surface_t *surface,
+ const cairo_pattern_t *pattern)
+{
+ cairo_surface_pattern_t *surface_pattern;
+ cairo_surface_t *source;
+
+ surface_pattern = (cairo_surface_pattern_t *) pattern;
+ source = surface_pattern->surface;
+
+ switch ((int) source->type) {
+ case CAIRO_INTERNAL_SURFACE_TYPE_META:
+ return _emit_meta_surface_pattern (surface, pattern);
+ case CAIRO_SURFACE_TYPE_SCRIPT:
+ return _emit_script_surface_pattern (surface, pattern);
+ default:
+ return _emit_image_surface_pattern (surface, pattern);
+ }
+}
+
+static cairo_status_t
+_emit_pattern (cairo_script_surface_t *surface,
+ const cairo_pattern_t *pattern)
+{
+ cairo_status_t status;
+
+ switch (pattern->type) {
+ case CAIRO_PATTERN_TYPE_SOLID:
+ /* solid colors do not need filter/extend/matrix */
+ return _emit_solid_pattern (surface, pattern);
+
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ status = _emit_linear_pattern (surface, pattern);
+ break;
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ status = _emit_radial_pattern (surface, pattern);
+ break;
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ status = _emit_surface_pattern (surface, pattern);
+ break;
+
+ default:
+ ASSERT_NOT_REACHED;
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+ if (unlikely (status))
+ return status;
+
+ if (! _cairo_matrix_is_identity (&pattern->matrix)) {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ " [%f %f %f %f %f %f] set_matrix\n ",
+ pattern->matrix.xx, pattern->matrix.yx,
+ pattern->matrix.xy, pattern->matrix.yy,
+ pattern->matrix.x0, pattern->matrix.y0);
+ }
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ " //%s set_extend\n "
+ " //%s set_filter\n ",
+ _extend_to_string (pattern->extend),
+ _filter_to_string (pattern->filter));
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_identity (cairo_script_surface_t *surface,
+ cairo_bool_t *matrix_updated)
+{
+ assert (_cairo_script_surface_owns_context (surface));
+
+ if (_cairo_matrix_is_identity (&surface->cr.current_ctm))
+ return CAIRO_STATUS_SUCCESS;
+
+ _cairo_output_stream_puts (surface->ctx->stream,
+ "identity set_matrix\n");
+
+ *matrix_updated = TRUE;
+ cairo_matrix_init_identity (&surface->cr.current_ctm);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_source (cairo_script_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source)
+{
+ cairo_bool_t matrix_updated = FALSE;
+ cairo_status_t status;
+
+ assert (_cairo_script_surface_owns_context (surface));
+
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ /* the source is ignored, so don't change it */
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ if (surface->cr.current_source == source)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (_cairo_pattern_equal (surface->cr.current_source, source))
+ return CAIRO_STATUS_SUCCESS;
+
+ cairo_pattern_destroy (surface->cr.current_source);
+ status = _cairo_pattern_create_copy (&surface->cr.current_source,
+ source);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_identity (surface, &matrix_updated);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_pattern (surface, source);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_puts (surface->ctx->stream,
+ " set_source\n");
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_path_move_to (void *closure, cairo_point_t *point)
+{
+ _cairo_output_stream_printf (closure,
+ " %f %f m",
+ _cairo_fixed_to_double (point->x),
+ _cairo_fixed_to_double (point->y));
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_path_line_to (void *closure, cairo_point_t *point)
+{
+ _cairo_output_stream_printf (closure,
+ " %f %f l",
+ _cairo_fixed_to_double (point->x),
+ _cairo_fixed_to_double (point->y));
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_path_curve_to (void *closure,
+ cairo_point_t *p1,
+ cairo_point_t *p2,
+ cairo_point_t *p3)
+{
+ _cairo_output_stream_printf (closure,
+ " %f %f %f %f %f %f c",
+ _cairo_fixed_to_double (p1->x),
+ _cairo_fixed_to_double (p1->y),
+ _cairo_fixed_to_double (p2->x),
+ _cairo_fixed_to_double (p2->y),
+ _cairo_fixed_to_double (p3->x),
+ _cairo_fixed_to_double (p3->y));
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_path_close (void *closure)
+{
+ _cairo_output_stream_printf (closure,
+ " h");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_path (cairo_script_surface_t *surface,
+ cairo_path_fixed_t *path)
+{
+ cairo_box_t box;
+ cairo_status_t status;
+
+ assert (_cairo_script_surface_owns_context (surface));
+ assert (_cairo_matrix_is_identity (&surface->cr.current_ctm));
+
+ if (_cairo_path_fixed_equal (&surface->cr.current_path, path))
+ return CAIRO_STATUS_SUCCESS;
+
+ _cairo_path_fixed_fini (&surface->cr.current_path);
+
+ _cairo_output_stream_puts (surface->ctx->stream, "n");
+
+ if (path == NULL) {
+ _cairo_path_fixed_init (&surface->cr.current_path);
+ } else if (_cairo_path_fixed_is_rectangle (path, &box)) {
+ double x1 = _cairo_fixed_to_double (box.p1.x);
+ double y1 = _cairo_fixed_to_double (box.p1.y);
+ double x2 = _cairo_fixed_to_double (box.p2.x);
+ double y2 = _cairo_fixed_to_double (box.p2.y);
+
+ status = _cairo_path_fixed_init_copy (&surface->cr.current_path, path);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ " %f %f %f %f rectangle",
+ x1, y1, x2 - x1, y2 - y1);
+ } else {
+ cairo_status_t status;
+
+ status = _cairo_path_fixed_init_copy (&surface->cr.current_path, path);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_path_fixed_interpret (path,
+ CAIRO_DIRECTION_FORWARD,
+ _path_move_to,
+ _path_line_to,
+ _path_curve_to,
+ _path_close,
+ surface->ctx->stream);
+ if (unlikely (status))
+ return status;
+ }
+
+ _cairo_output_stream_puts (surface->ctx->stream, "\n");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_matrix (cairo_script_surface_t *surface,
+ const cairo_matrix_t *ctm,
+ cairo_bool_t *matrix_updated)
+{
+ assert (_cairo_script_surface_owns_context (surface));
+
+ if (memcmp (&surface->cr.current_ctm, ctm, sizeof (cairo_matrix_t)) == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ *matrix_updated = TRUE;
+ surface->cr.current_ctm = *ctm;
+
+ if (_cairo_matrix_is_identity (ctm)) {
+ _cairo_output_stream_puts (surface->ctx->stream,
+ "identity set_matrix\n");
+ } else {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "[%f %f %f %f %f %f] set_matrix\n",
+ ctm->xx, ctm->yx,
+ ctm->xy, ctm->yy,
+ ctm->x0, ctm->y0);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_font_matrix (cairo_script_surface_t *surface,
+ const cairo_matrix_t *font_matrix)
+{
+ assert (_cairo_script_surface_owns_context (surface));
+
+ if (memcmp (&surface->cr.current_font_matrix,
+ font_matrix,
+ sizeof (cairo_matrix_t)) == 0)
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ surface->cr.current_font_matrix = *font_matrix;
+
+ if (_cairo_matrix_is_identity (font_matrix)) {
+ _cairo_output_stream_puts (surface->ctx->stream,
+ "identity set_font_matrix\n");
+ } else {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "[%f %f %f %f %f %f] set_font_matrix\n",
+ font_matrix->xx, font_matrix->yx,
+ font_matrix->xy, font_matrix->yy,
+ font_matrix->x0, font_matrix->y0);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static const char *
+_content_to_string (cairo_content_t content)
+{
+ switch (content) {
+ case CAIRO_CONTENT_ALPHA: return "ALPHA";
+ case CAIRO_CONTENT_COLOR: return "COLOR";
+ default:
+ case CAIRO_CONTENT_COLOR_ALPHA: return "COLOR_ALPHA";
+ }
+}
+
+static cairo_surface_t *
+_cairo_script_surface_create_similar (void *abstract_surface,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ cairo_script_surface_t *surface, *other;
+ cairo_script_vmcontext_t *ctx;
+ cairo_status_t status;
+
+ other = abstract_surface;
+ ctx = other->ctx;
+
+ if (other->id == (unsigned long) -1) {
+ cairo_status_t status;
+
+ status = _bitmap_next_id (&ctx->surface_id,
+ &other->id);
+ if (unlikely (status))
+ return _cairo_surface_create_in_error (status);
+
+ _cairo_output_stream_printf (ctx->stream,
+ "dict\n"
+ " /width %f set\n"
+ " /height %f set\n"
+ " surface dup /s%lu exch def\n"
+ "context /c%lu exch def\n",
+ other->width,
+ other->height,
+ other->id,
+ other->id);
+ }
+
+
+ surface = _cairo_script_surface_create_internal (ctx, width, height);
+ if (surface->base.status)
+ return &surface->base;
+
+ status = _bitmap_next_id (&ctx->surface_id,
+ &surface->id);
+ if (unlikely (status)) {
+ cairo_surface_destroy (&surface->base);
+ return _cairo_surface_create_in_error (status);
+ }
+
+ if (ctx->current_target != NULL)
+ _cairo_output_stream_printf (ctx->stream, "pop\n");
+
+ _cairo_output_stream_printf (ctx->stream,
+ "s%lu %u %u //%s similar dup /s%lu exch def\n"
+ "context dup /c%lu exch def\n",
+ other->id, width, height,
+ _content_to_string (content),
+ surface->id,
+ surface->id);
+
+ ctx->current_target = surface;
+
+ return &surface->base;
+}
+
+static cairo_status_t
+_vmcontext_destroy (cairo_script_vmcontext_t *ctx)
+{
+ cairo_status_t status;
+
+ if (--ctx->ref)
+ return _cairo_output_stream_flush (ctx->stream);
+
+ while (ctx->fonts != NULL ){
+ cairo_script_surface_font_private_t *font = ctx->fonts;
+ ctx->fonts = font->next;
+ _cairo_script_surface_scaled_font_fini (font->parent);
+ }
+
+ status = _cairo_output_stream_destroy (ctx->stream);
+
+ free (ctx);
+
+ return status;
+}
+
+static cairo_status_t
+_cairo_script_surface_finish (void *abstract_surface)
+{
+ cairo_script_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ cairo_pattern_destroy (surface->cr.current_source);
+ _cairo_path_fixed_fini (&surface->cr.current_path);
+
+ if (surface->ctx->current_target == surface) {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "pop\n");
+ surface->ctx->current_target = NULL;
+ }
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "/c%lu undef\n"
+ "/s%lu undef\n",
+ surface->id,
+ surface->id);
+
+ _bitmap_release_id (&surface->ctx->surface_id, surface->id);
+
+ status = _vmcontext_destroy (surface->ctx);
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_script_surface_copy_page (void *abstract_surface)
+{
+ cairo_script_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ status = _emit_context (surface);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_puts (surface->ctx->stream, "copy_page\n");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_script_surface_show_page (void *abstract_surface)
+{
+ cairo_script_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ status = _emit_context (surface);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_puts (surface->ctx->stream, "show_page\n");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_script_surface_intersect_clip_path (void *abstract_surface,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ cairo_script_surface_t *surface = abstract_surface;
+ cairo_bool_t matrix_updated = FALSE;
+ cairo_status_t status;
+
+ status = _emit_context (surface);
+ if (unlikely (status))
+ return status;
+
+ if (path == NULL) {
+ _cairo_output_stream_puts (surface->ctx->stream, "reset_clip\n");
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ status = _emit_identity (surface, &matrix_updated);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_fill_rule (surface, fill_rule);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_tolerance (surface, tolerance, matrix_updated);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_antialias (surface, antialias);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_path (surface, path);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_puts (surface->ctx->stream, "clip+\n");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_script_surface_paint (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_rectangle_int_t *extents)
+{
+ cairo_script_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ status = _emit_context (surface);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_operator (surface, op);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_source (surface, op, source);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_puts (surface->ctx->stream,
+ "paint\n");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_script_surface_mask (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_rectangle_int_t *extents)
+{
+ cairo_script_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ status = _emit_context (surface);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_operator (surface, op);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_source (surface, op, source);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_pattern (surface, mask);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_puts (surface->ctx->stream,
+ " mask\n");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_script_surface_stroke (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_stroke_style_t *style,
+ cairo_matrix_t *ctm,
+ cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
+{
+ cairo_script_surface_t *surface = abstract_surface;
+ cairo_bool_t matrix_updated = FALSE;
+ cairo_status_t status;
+
+ status = _emit_context (surface);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_identity (surface, &matrix_updated);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_path (surface, path);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_source (surface, op, source);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_matrix (surface, ctm, &matrix_updated);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_operator (surface, op);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_stroke_style (surface, style, matrix_updated);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_tolerance (surface, tolerance, matrix_updated);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_antialias (surface, antialias);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_puts (surface->ctx->stream, "stroke+\n");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_script_surface_fill (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
+{
+ cairo_script_surface_t *surface = abstract_surface;
+ cairo_bool_t matrix_updated = FALSE;
+ cairo_status_t status;
+
+ status = _emit_context (surface);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_operator (surface, op);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_identity (surface, &matrix_updated);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_source (surface, op, source);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_fill_rule (surface, fill_rule);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_tolerance (surface, tolerance, matrix_updated);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_antialias (surface, antialias);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_path (surface, path);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_puts (surface->ctx->stream, "fill+\n");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_bool_t
+_cairo_script_surface_has_show_text_glyphs (void *abstract_surface)
+{
+ return TRUE;
+}
+
+static const char *
+_subpixel_order_to_string (cairo_subpixel_order_t subpixel_order)
+{
+ static const char *names[] = {
+ "SUBPIXEL_ORDER_DEFAULT", /* CAIRO_SUBPIXEL_ORDER_DEFAULT */
+ "SUBPIXEL_ORDER_RGB", /* CAIRO_SUBPIXEL_ORDER_RGB */
+ "SUBPIXEL_ORDER_BGR", /* CAIRO_SUBPIXEL_ORDER_BGR */
+ "SUBPIXEL_ORDER_VRGB", /* CAIRO_SUBPIXEL_ORDER_VRGB */
+ "SUBPIXEL_ORDER_VBGR" /* CAIRO_SUBPIXEL_ORDER_VBGR */
+ };
+ return names[subpixel_order];
+}
+static const char *
+_hint_style_to_string (cairo_hint_style_t hint_style)
+{
+ static const char *names[] = {
+ "HINT_STYLE_DEFAULT", /* CAIRO_HINT_STYLE_DEFAULT */
+ "HINT_STYLE_NONE", /* CAIRO_HINT_STYLE_NONE */
+ "HINT_STYLE_SLIGHT", /* CAIRO_HINT_STYLE_SLIGHT */
+ "HINT_STYLE_MEDIUM", /* CAIRO_HINT_STYLE_MEDIUM */
+ "HINT_STYLE_FULL" /* CAIRO_HINT_STYLE_FULL */
+ };
+ return names[hint_style];
+}
+static const char *
+_hint_metrics_to_string (cairo_hint_metrics_t hint_metrics)
+{
+ static const char *names[] = {
+ "HINT_METRICS_DEFAULT", /* CAIRO_HINT_METRICS_DEFAULT */
+ "HINT_METRICS_OFF", /* CAIRO_HINT_METRICS_OFF */
+ "HINT_METRICS_ON" /* CAIRO_HINT_METRICS_ON */
+ };
+ return names[hint_metrics];
+}
+
+static cairo_status_t
+_emit_font_options (cairo_script_surface_t *surface,
+ cairo_font_options_t *font_options)
+{
+ if (cairo_font_options_equal (&surface->cr.current_font_options,
+ font_options))
+ {
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ _cairo_output_stream_printf (surface->ctx->stream, "dict\n");
+
+ if (font_options->antialias != surface->cr.current_font_options.antialias) {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ " /antialias //%s set\n",
+ _antialias_to_string (font_options->antialias));
+ }
+
+ if (font_options->subpixel_order !=
+ surface->cr.current_font_options.subpixel_order)
+ {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ " /subpixel-order //%s set\n",
+ _subpixel_order_to_string (font_options->subpixel_order));
+ }
+
+ if (font_options->hint_style !=
+ surface->cr.current_font_options.hint_style)
+ {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ " /hint-style //%s set\n",
+ _hint_style_to_string (font_options->hint_style));
+ }
+
+ if (font_options->hint_metrics !=
+ surface->cr.current_font_options.hint_metrics)
+ {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ " /hint-metrics //%s set\n",
+ _hint_metrics_to_string (font_options->hint_metrics));
+ }
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ " set_font_options\n");
+
+ surface->cr.current_font_options = *font_options;
+
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_script_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
+{
+ cairo_script_surface_font_private_t *font_private;
+
+ font_private = scaled_font->surface_private;
+ if (font_private != NULL) {
+ _cairo_output_stream_printf (font_private->ctx->stream,
+ "/f%lu undef\n",
+ font_private->id);
+
+ _bitmap_release_id (&font_private->ctx->font_id, font_private->id);
+
+ if (font_private->prev != NULL)
+ font_private->prev = font_private->next;
+ else
+ font_private->ctx->fonts = font_private->next;
+
+ if (font_private->next != NULL)
+ font_private->next = font_private->prev;
+
+ free (font_private);
+
+ scaled_font->surface_private = NULL;
+ }
+}
+
+static cairo_status_t
+_emit_type42_font (cairo_script_surface_t *surface,
+ cairo_scaled_font_t *scaled_font)
+{
+ const cairo_scaled_font_backend_t *backend;
+ cairo_script_surface_font_private_t *font_private;
+ cairo_output_stream_t *base85_stream;
+ cairo_output_stream_t *zlib_stream;
+ cairo_status_t status, status2;
+ unsigned long size;
+ unsigned int load_flags;
+ uint8_t *buf;
+
+ backend = scaled_font->backend;
+ if (backend->load_truetype_table == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ size = 0;
+ status = backend->load_truetype_table (scaled_font, 0, 0, NULL, &size);
+ if (unlikely (status))
+ return status;
+
+ buf = malloc (size);
+ if (unlikely (buf == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ status = backend->load_truetype_table (scaled_font, 0, 0, buf, NULL);
+ if (unlikely (status)) {
+ free (buf);
+ return status;
+ }
+
+ load_flags = _cairo_ft_scaled_font_get_load_flags (scaled_font);
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "dict\n"
+ " /type 42 set\n"
+ " /size %lu set\n"
+ " /index 0 set\n"
+ " /flags %d set\n"
+ " /source <~",
+ size, load_flags);
+
+ base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
+ zlib_stream = _cairo_deflate_stream_create (base85_stream);
+
+ _cairo_output_stream_write (zlib_stream, buf, size);
+ free (buf);
+
+ status2 = _cairo_output_stream_destroy (zlib_stream);
+ if (status == CAIRO_STATUS_SUCCESS)
+ status = status2;
+
+ status2 = _cairo_output_stream_destroy (base85_stream);
+ if (status == CAIRO_STATUS_SUCCESS)
+ status = status2;
+
+ font_private = scaled_font->surface_private;
+ _cairo_output_stream_printf (surface->ctx->stream,
+ " /deflate filter set\n"
+ " font dup /f%lu exch def set_font_face\n",
+ font_private->id);
+
+ return status;
+}
+
+static cairo_status_t
+_emit_scaled_font_init (cairo_script_surface_t *surface,
+ cairo_scaled_font_t *scaled_font)
+{
+ cairo_script_surface_font_private_t *font_private;
+ cairo_status_t status;
+
+ font_private = malloc (sizeof (cairo_script_surface_font_private_t));
+ if (unlikely (font_private == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ font_private->ctx = surface->ctx;
+ font_private->parent = scaled_font;
+ font_private->subset_glyph_index = 0;
+ font_private->has_sfnt = TRUE;
+
+ font_private->next = font_private->ctx->fonts;
+ font_private->prev = NULL;
+ if (font_private->ctx->fonts != NULL)
+ font_private->ctx->fonts->prev = font_private;
+ font_private->ctx->fonts = font_private;
+
+ status = _bitmap_next_id (&surface->ctx->font_id,
+ &font_private->id);
+ if (unlikely (status)) {
+ free (font_private);
+ return status;
+ }
+
+ scaled_font->surface_private = font_private;
+ scaled_font->surface_backend = &_cairo_script_surface_backend;
+
+ status = _emit_context (surface);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_type42_font (surface, scaled_font);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
+ font_private->has_sfnt = FALSE;
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "dict\n"
+ " /type 3 set\n"
+ " /metrics [%f %f %f %f %f] set\n"
+ " /glyphs array set\n"
+ " font dup /f%lu exch def set_font_face\n",
+ scaled_font->fs_extents.ascent,
+ scaled_font->fs_extents.descent,
+ scaled_font->fs_extents.height,
+ scaled_font->fs_extents.max_x_advance,
+ scaled_font->fs_extents.max_y_advance,
+ font_private->id);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_scaled_font (cairo_script_surface_t *surface,
+ cairo_scaled_font_t *scaled_font)
+{
+ cairo_matrix_t matrix;
+ cairo_font_options_t options;
+ cairo_bool_t matrix_updated = FALSE;
+ cairo_status_t status;
+ cairo_script_surface_font_private_t *font_private;
+
+ cairo_scaled_font_get_ctm (scaled_font, &matrix);
+ status = _emit_matrix (surface, &matrix, &matrix_updated);
+ if (unlikely (status))
+ return status;
+
+ if (! matrix_updated && surface->cr.current_scaled_font == scaled_font)
+ return CAIRO_STATUS_SUCCESS;
+
+ cairo_scaled_font_get_font_matrix (scaled_font, &matrix);
+ status = _emit_font_matrix (surface, &matrix);
+ if (unlikely (status))
+ return status;
+
+ cairo_scaled_font_get_font_options (scaled_font, &options);
+ status = _emit_font_options (surface, &options);
+ if (unlikely (status))
+ return status;
+
+ surface->cr.current_scaled_font = scaled_font;
+
+ assert (scaled_font->surface_backend == NULL ||
+ scaled_font->surface_backend == &_cairo_script_surface_backend);
+
+ font_private = scaled_font->surface_private;
+ if (font_private == NULL) {
+ status = _emit_scaled_font_init (surface, scaled_font);
+ if (unlikely (status))
+ return status;
+ } else {
+ status = _emit_context (surface);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "f%lu set_font_face\n",
+ font_private->id);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_scaled_glyph_vector (cairo_script_surface_t *surface,
+ cairo_scaled_font_t *scaled_font,
+ cairo_scaled_glyph_t *scaled_glyph)
+{
+ cairo_script_surface_font_private_t *font_private;
+ cairo_script_implicit_context_t old_cr;
+ cairo_status_t status;
+ unsigned long index;
+
+ font_private = scaled_font->surface_private;
+ index = ++font_private->subset_glyph_index;
+ scaled_glyph->surface_private = (void *) index;
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "%lu dict\n"
+ " /metrics [%f %f %f %f %f %f] set\n"
+ " /render {\n",
+ index,
+ scaled_glyph->fs_metrics.x_bearing,
+ scaled_glyph->fs_metrics.y_bearing,
+ scaled_glyph->fs_metrics.width,
+ scaled_glyph->fs_metrics.height,
+ scaled_glyph->fs_metrics.x_advance,
+ scaled_glyph->fs_metrics.y_advance);
+
+ if (! _cairo_matrix_is_identity (&scaled_font->scale_inverse)) {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "[%f %f %f %f %f %f] transform\n",
+ scaled_font->scale_inverse.xx,
+ scaled_font->scale_inverse.yx,
+ scaled_font->scale_inverse.xy,
+ scaled_font->scale_inverse.yy,
+ scaled_font->scale_inverse.x0,
+ scaled_font->scale_inverse.y0);
+ }
+
+ old_cr = surface->cr;
+ _cairo_script_implicit_context_init (&surface->cr);
+ status = _cairo_meta_surface_replay (scaled_glyph->meta_surface,
+ &surface->base);
+ surface->cr = old_cr;
+
+ _cairo_output_stream_puts (surface->ctx->stream, "} set set\n");
+
+ return status;
+}
+
+static cairo_status_t
+_emit_scaled_glyph_bitmap (cairo_script_surface_t *surface,
+ cairo_scaled_font_t *scaled_font,
+ cairo_scaled_glyph_t *scaled_glyph)
+{
+ cairo_script_surface_font_private_t *font_private;
+ cairo_status_t status;
+ unsigned long index;
+
+ font_private = scaled_font->surface_private;
+ index = ++font_private->subset_glyph_index;
+ scaled_glyph->surface_private = (void *) index;
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "%lu dict\n"
+ " /metrics [%f %f %f %f %f %f] set\n"
+ " /render {\n"
+ "%f %f translate\n",
+ index,
+ scaled_glyph->fs_metrics.x_bearing,
+ scaled_glyph->fs_metrics.y_bearing,
+ scaled_glyph->fs_metrics.width,
+ scaled_glyph->fs_metrics.height,
+ scaled_glyph->fs_metrics.x_advance,
+ scaled_glyph->fs_metrics.y_advance,
+ scaled_glyph->fs_metrics.x_bearing,
+ scaled_glyph->fs_metrics.y_bearing);
+
+ status = _emit_image_surface (surface, scaled_glyph->surface);
+ if (unlikely (status))
+ return status;
+
+ if (! _cairo_matrix_is_identity (&scaled_font->font_matrix)) {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ " [%f %f %f %f %f %f] set_matrix\n",
+ scaled_font->font_matrix.xx,
+ scaled_font->font_matrix.yx,
+ scaled_font->font_matrix.xy,
+ scaled_font->font_matrix.yy,
+ scaled_font->font_matrix.x0,
+ scaled_font->font_matrix.y0);
+ }
+ _cairo_output_stream_puts (surface->ctx->stream,
+ "mask\n} set set\n");
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_scaled_glyph_prologue (cairo_script_surface_t *surface,
+ cairo_scaled_font_t *scaled_font)
+{
+ cairo_script_surface_font_private_t *font_private;
+
+ assert (scaled_font->surface_backend == &_cairo_script_surface_backend);
+
+ font_private = scaled_font->surface_private;
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "f%lu /glyphs get\n",
+ font_private->id);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_emit_scaled_glyphs (cairo_script_surface_t *surface,
+ cairo_scaled_font_t *scaled_font,
+ cairo_glyph_t *glyphs,
+ unsigned int num_glyphs)
+{
+ cairo_script_surface_font_private_t *font_private;
+ cairo_status_t status;
+ unsigned int n;
+ cairo_bool_t have_glyph_prologue = FALSE;
+
+ if (num_glyphs == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ font_private = scaled_font->surface_private;
+ if (font_private->has_sfnt)
+ return CAIRO_STATUS_SUCCESS;
+
+ _cairo_scaled_font_freeze_cache (scaled_font);
+ for (n = 0; n < num_glyphs; n++) {
+ cairo_scaled_glyph_t *scaled_glyph;
+
+ status = _cairo_scaled_glyph_lookup (scaled_font,
+ glyphs[n].index,
+ CAIRO_SCALED_GLYPH_INFO_METRICS,
+ &scaled_glyph);
+ if (unlikely (status))
+ break;
+
+ if (scaled_glyph->surface_private != NULL)
+ continue;
+
+ status = _cairo_scaled_glyph_lookup (scaled_font,
+ glyphs[n].index,
+ CAIRO_SCALED_GLYPH_INFO_META_SURFACE,
+ &scaled_glyph);
+ if (_cairo_status_is_error (status))
+ break;
+
+ if (status == CAIRO_STATUS_SUCCESS) {
+ if (! have_glyph_prologue) {
+ status = _emit_scaled_glyph_prologue (surface, scaled_font);
+ if (unlikely (status))
+ break;
+
+ have_glyph_prologue = TRUE;
+ }
+
+ status = _emit_scaled_glyph_vector (surface,
+ scaled_font,
+ scaled_glyph);
+ if (unlikely (status))
+ break;
+
+ continue;
+ }
+
+ status = _cairo_scaled_glyph_lookup (scaled_font,
+ glyphs[n].index,
+ CAIRO_SCALED_GLYPH_INFO_SURFACE,
+ &scaled_glyph);
+ if (_cairo_status_is_error (status))
+ break;
+
+ if (status == CAIRO_STATUS_SUCCESS) {
+ if (! have_glyph_prologue) {
+ status = _emit_scaled_glyph_prologue (surface, scaled_font);
+ if (unlikely (status))
+ break;
+
+ have_glyph_prologue = TRUE;
+ }
+
+ status = _emit_scaled_glyph_bitmap (surface,
+ scaled_font,
+ scaled_glyph);
+ if (unlikely (status))
+ break;
+
+ continue;
+ }
+ }
+ _cairo_scaled_font_thaw_cache (scaled_font);
+
+ if (have_glyph_prologue) {
+ _cairo_output_stream_puts (surface->ctx->stream, "pop pop\n");
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_script_surface_show_text_glyphs (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const char *utf8,
+ int utf8_len,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ const cairo_text_cluster_t *clusters,
+ int num_clusters,
+ cairo_text_cluster_flags_t backward,
+ cairo_scaled_font_t *scaled_font,
+ cairo_rectangle_int_t *extents)
+{
+ cairo_script_surface_t *surface = abstract_surface;
+ cairo_script_surface_font_private_t *font_private;
+ cairo_scaled_glyph_t *scaled_glyph;
+ cairo_matrix_t matrix;
+ cairo_status_t status;
+ double x, y, ix, iy;
+ int n;
+ cairo_output_stream_t *base85_stream = NULL;
+
+ status = _emit_context (surface);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_operator (surface, op);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_source (surface, op, source);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_scaled_font (surface, scaled_font);
+ if (unlikely (status))
+ return status;
+
+ status = _emit_scaled_glyphs (surface, scaled_font, glyphs, num_glyphs);
+ if (unlikely (status))
+ return status;
+
+ /* (utf8) [cx cy [glyphs]] [clusters] backward show_text_glyphs */
+ /* [cx cy [glyphs]] show_glyphs */
+
+ if (utf8 != NULL && clusters != NULL) {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "(%s) ",
+ utf8);
+ }
+
+ matrix = surface->cr.current_ctm;
+ status = cairo_matrix_invert (&matrix);
+ assert (status == CAIRO_STATUS_SUCCESS);
+
+ ix = x = glyphs[0].x;
+ iy = y = glyphs[0].y;
+ cairo_matrix_transform_point (&matrix, &ix, &iy);
+ ix -= scaled_font->font_matrix.x0;
+ iy -= scaled_font->font_matrix.y0;
+
+ _cairo_scaled_font_freeze_cache (scaled_font);
+ font_private = scaled_font->surface_private;
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "[%f %f ",
+ ix, iy);
+
+ for (n = 0; n < num_glyphs; n++) {
+ if (font_private->has_sfnt) {
+ if (glyphs[n].index > 256)
+ break;
+ } else {
+ status = _cairo_scaled_glyph_lookup (scaled_font,
+ glyphs[n].index,
+ CAIRO_SCALED_GLYPH_INFO_METRICS,
+ &scaled_glyph);
+ if (unlikely (status)) {
+ _cairo_scaled_font_thaw_cache (scaled_font);
+ return status;
+ }
+ }
+ }
+
+ if (n == num_glyphs) {
+ _cairo_output_stream_puts (surface->ctx->stream, "<~");
+ base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
+ } else
+ _cairo_output_stream_puts (surface->ctx->stream, "[");
+
+ for (n = 0; n < num_glyphs; n++) {
+ double dx, dy;
+
+ status = _cairo_scaled_glyph_lookup (scaled_font,
+ glyphs[n].index,
+ CAIRO_SCALED_GLYPH_INFO_METRICS,
+ &scaled_glyph);
+ if (unlikely (status))
+ break;
+
+ if (fabs (glyphs[n].x - x) > 1e-5 || fabs (glyphs[n].y - y) > 1e-5) {
+ ix = x = glyphs[n].x;
+ iy = y = glyphs[n].y;
+ cairo_matrix_transform_point (&matrix, &ix, &iy);
+ ix -= scaled_font->font_matrix.x0;
+ iy -= scaled_font->font_matrix.y0;
+ if (base85_stream != NULL) {
+ status = _cairo_output_stream_destroy (base85_stream);
+ if (unlikely (status)) {
+ base85_stream = NULL;
+ break;
+ }
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ " %f %f <~",
+ ix, iy);
+ base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
+ } else {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ " ] %f %f [ ",
+ ix, iy);
+ }
+ }
+ if (base85_stream != NULL) {
+ uint8_t c;
+
+ if (font_private->has_sfnt)
+ c = glyphs[n].index;
+ else
+ c = (uint8_t) (long unsigned) scaled_glyph->surface_private;
+
+ _cairo_output_stream_write (base85_stream, &c, 1);
+ } else {
+ if (font_private->has_sfnt)
+ _cairo_output_stream_printf (surface->ctx->stream, " %lu",
+ glyphs[n].index);
+ else
+ _cairo_output_stream_printf (surface->ctx->stream, " %lu",
+ (long unsigned) scaled_glyph->surface_private);
+ }
+
+ dx = scaled_glyph->metrics.x_advance;
+ dy = scaled_glyph->metrics.y_advance;
+ cairo_matrix_transform_distance (&scaled_font->ctm, &dx, &dy);
+ x += dx;
+ y += dy;
+ }
+ _cairo_scaled_font_thaw_cache (scaled_font);
+
+ if (base85_stream != NULL) {
+ cairo_status_t status2;
+
+ status2 = _cairo_output_stream_destroy (base85_stream);
+ if (status == CAIRO_STATUS_SUCCESS)
+ status = status2;
+ } else {
+ _cairo_output_stream_puts (surface->ctx->stream, " ]");
+ }
+ if (unlikely (status))
+ return status;
+
+ if (utf8 != NULL && clusters != NULL) {
+ for (n = 0; n < num_clusters; n++) {
+ if (clusters[n].num_bytes > UCHAR_MAX ||
+ clusters[n].num_glyphs > UCHAR_MAX)
+ {
+ break;
+ }
+ }
+
+ if (n < num_clusters) {
+ _cairo_output_stream_puts (surface->ctx->stream, "] [ ");
+ for (n = 0; n < num_clusters; n++) {
+ _cairo_output_stream_printf (surface->ctx->stream,
+ "%d %d ",
+ clusters[n].num_bytes,
+ clusters[n].num_glyphs);
+ }
+ _cairo_output_stream_puts (surface->ctx->stream, "]");
+ }
+ else
+ {
+ _cairo_output_stream_puts (surface->ctx->stream, "] <~");
+ base85_stream = _cairo_base85_stream_create (surface->ctx->stream);
+ for (n = 0; n < num_clusters; n++) {
+ uint8_t c[2];
+ c[0] = clusters[n].num_bytes;
+ c[1] = clusters[n].num_glyphs;
+ _cairo_output_stream_write (base85_stream, c, 2);
+ }
+ status = _cairo_output_stream_destroy (base85_stream);
+ if (unlikely (status))
+ return status;
+ }
+
+ _cairo_output_stream_printf (surface->ctx->stream,
+ " //%s show_text_glyphs\n",
+ _direction_to_string (backward));
+ } else {
+ _cairo_output_stream_puts (surface->ctx->stream,
+ "] show_glyphs\n");
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_script_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_int_t *rectangle)
+{
+ cairo_script_surface_t *surface = abstract_surface;
+
+ if (surface->width < 0 || surface->height < 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ rectangle->x = 0;
+ rectangle->y = 0;
+ rectangle->width = surface->width;
+ rectangle->height = surface->height;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t
+_cairo_script_surface_backend = {
+ CAIRO_SURFACE_TYPE_SCRIPT,
+ _cairo_script_surface_create_similar,
+ _cairo_script_surface_finish,
+ NULL, //_cairo_script_surface_acquire_source_image,
+ NULL, //_cairo_script_surface_release_source_image,
+ NULL, /* acquire_dest_image */
+ NULL, /* release_dest_image */
+ NULL, /* clone_similar */
+ 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 */
+ _cairo_script_surface_intersect_clip_path,
+ _cairo_script_surface_get_extents,
+ NULL, /* old_show_glyphs */
+ NULL, /* get_font_options */
+ NULL, /* flush */
+ NULL, /* mark_dirty_rectangle */
+ _cairo_script_surface_scaled_font_fini,
+ NULL, /* scaled_glyph_fini */
+
+ /* The 5 high level operations */
+ _cairo_script_surface_paint,
+ _cairo_script_surface_mask,
+ _cairo_script_surface_stroke,
+ _cairo_script_surface_fill,
+ NULL,
+
+ NULL, //_cairo_script_surface_snapshot,
+
+ NULL, /* is_similar */
+ NULL, /* reset */
+ NULL, /* fill_stroke */
+ NULL, /* create_solid_pattern_surface */
+
+ /* The alternate high-level text operation */
+ _cairo_script_surface_has_show_text_glyphs,
+ _cairo_script_surface_show_text_glyphs
+};
+
+static cairo_bool_t
+_cairo_surface_is_script (cairo_surface_t *surface)
+{
+ return surface->backend == &_cairo_script_surface_backend;
+}
+
+static cairo_script_vmcontext_t *
+_cairo_script_vmcontext_create (cairo_output_stream_t *stream)
+{
+ cairo_script_vmcontext_t *ctx;
+
+ ctx = malloc (sizeof (cairo_script_vmcontext_t));
+ if (unlikely (ctx == NULL))
+ return NULL;
+
+ memset (ctx, 0, sizeof (cairo_script_vmcontext_t));
+
+ ctx->stream = stream;
+ ctx->mode = CAIRO_SCRIPT_MODE_ASCII;
+
+ return ctx;
+}
+
+static void
+_cairo_script_implicit_context_init (cairo_script_implicit_context_t *cr)
+{
+ cr->current_operator = CAIRO_GSTATE_OPERATOR_DEFAULT;
+ cr->current_fill_rule = CAIRO_GSTATE_FILL_RULE_DEFAULT;
+ cr->current_tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT;
+ cr->current_antialias = CAIRO_ANTIALIAS_DEFAULT;
+ _cairo_stroke_style_init (&cr->current_style);
+ cr->current_source = (cairo_pattern_t *) &_cairo_pattern_black.base;
+ _cairo_path_fixed_init (&cr->current_path);
+ cairo_matrix_init_identity (&cr->current_ctm);
+ cairo_matrix_init_identity (&cr->current_font_matrix);
+ _cairo_font_options_init_default (&cr->current_font_options);
+ cr->current_scaled_font = NULL;
+}
+
+static cairo_script_surface_t *
+_cairo_script_surface_create_internal (cairo_script_vmcontext_t *ctx,
+ double width,
+ double height)
+{
+ cairo_script_surface_t *surface;
+
+ if (unlikely (ctx == NULL))
+ return (cairo_script_surface_t *) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ surface = malloc (sizeof (cairo_script_surface_t));
+ if (unlikely (surface == NULL))
+ return (cairo_script_surface_t *) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ _cairo_surface_init (&surface->base,
+ &_cairo_script_surface_backend,
+ CAIRO_CONTENT_COLOR_ALPHA);
+
+ surface->ctx = ctx;
+ ctx->ref++;
+
+ surface->width = width;
+ surface->height = height;
+
+ surface->id = (unsigned long) -1;
+
+ _cairo_script_implicit_context_init (&surface->cr);
+
+ return surface;
+}
+
+cairo_surface_t *
+cairo_script_surface_create (const char *filename,
+ double width,
+ double height)
+{
+ cairo_output_stream_t *stream;
+ cairo_script_surface_t *surface;
+
+ stream = _cairo_output_stream_create_for_filename (filename);
+ if (_cairo_output_stream_get_status (stream))
+ return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream));
+
+
+ surface = _cairo_script_surface_create_internal
+ (_cairo_script_vmcontext_create (stream), width, height);
+ if (surface->base.status)
+ return &surface->base;
+
+ _cairo_output_stream_puts (surface->ctx->stream, "%!CairoScript\n");
+ return &surface->base;
+}
+
+cairo_surface_t *
+cairo_script_surface_create_for_stream (cairo_write_func_t write_func,
+ void *closure,
+ double width,
+ double height)
+{
+ cairo_output_stream_t *stream;
+
+ stream = _cairo_output_stream_create (write_func, NULL, closure);
+ if (_cairo_output_stream_get_status (stream))
+ return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream));
+
+ return &_cairo_script_surface_create_internal
+ (_cairo_script_vmcontext_create (stream), width, height)->base;
+}
+
+void
+cairo_script_surface_set_mode (cairo_surface_t *abstract_surface,
+ cairo_script_mode_t mode)
+{
+ cairo_script_surface_t *surface;
+ cairo_status_t status_ignored;
+
+ if (! _cairo_surface_is_script (abstract_surface)) {
+ status_ignored = _cairo_surface_set_error (abstract_surface,
+ CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+ return;
+ }
+
+ if (abstract_surface->status)
+ return;
+
+ surface = (cairo_script_surface_t *) abstract_surface;
+ surface->ctx->mode = mode;
+}
+
+cairo_script_mode_t
+cairo_script_surface_get_mode (cairo_surface_t *abstract_surface)
+{
+ cairo_script_surface_t *surface;
+
+ if (! _cairo_surface_is_script (abstract_surface) ||
+ abstract_surface->status)
+ {
+ return CAIRO_SCRIPT_MODE_ASCII;
+ }
+
+ surface = (cairo_script_surface_t *) abstract_surface;
+ return surface->ctx->mode;
+}
diff --git a/src/cairo-script.h b/src/cairo-script.h
new file mode 100644
index 00000000..9c428e3b
--- /dev/null
+++ b/src/cairo-script.h
@@ -0,0 +1,74 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2008 Chris Wilson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Chris Wilson
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_SCRIPT_H
+#define CAIRO_SCRIPT_H
+
+#include "cairo.h"
+
+#if CAIRO_HAS_SCRIPT_SURFACE
+
+CAIRO_BEGIN_DECLS
+
+cairo_public cairo_surface_t *
+cairo_script_surface_create (const char *filename,
+ double width,
+ double height);
+
+cairo_public cairo_surface_t *
+cairo_script_surface_create_for_stream (cairo_write_func_t write_func,
+ void *closure,
+ double width,
+ double height);
+
+typedef enum {
+ CAIRO_SCRIPT_MODE_BINARY,
+ CAIRO_SCRIPT_MODE_ASCII
+} cairo_script_mode_t;
+
+cairo_public void
+cairo_script_surface_set_mode (cairo_surface_t *surface,
+ cairo_script_mode_t mode);
+
+cairo_public cairo_script_mode_t
+cairo_script_surface_get_mode (cairo_surface_t *surface);
+
+CAIRO_END_DECLS
+
+#else /*CAIRO_HAS_SCRIPT_SURFACE*/
+# error Cairo was not compiled with support for the CairoScript backend
+#endif /*CAIRO_HAS_SCRIPT_SURFACE*/
+
+#endif /*CAIRO_SCRIPT_H*/
diff --git a/src/cairo-sdl-surface.c b/src/cairo-sdl-surface.c
index b9d604e6..1f97fb47 100644
--- a/src/cairo-sdl-surface.c
+++ b/src/cairo-sdl-surface.c
@@ -52,7 +52,7 @@ _cairo_sdl_surface_create_internal (SDL_Surface *sdl,
cairo_sdl_surface_t *surface;
surface = malloc (sizeof (cairo_sdl_surface_t));
- if (surface == NULL)
+ if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_surface_init (&surface->base,
@@ -240,7 +240,7 @@ _cairo_sdl_surface_composite (cairo_operator_t op,
src_x, src_y, width, height,
(cairo_surface_t **) &src,
&src_attr);
- if (status)
+ if (unlikely (status))
return status;
is_integer_translation =
@@ -322,8 +322,9 @@ _cairo_sdl_surface_flush (void *abstract_surface)
int n_boxes, i;
cairo_status_t status;
+ n_boxes = 0;
status = _cairo_region_get_boxes (&surface->update, &n_boxes, &boxes);
- if (status)
+ if (unlikely (status))
return status;
if (n_boxes == 0)
return CAIRO_STATUS_SUCCESS;
@@ -356,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-skiplist.c b/src/cairo-skiplist.c
index e2b793e1..d03a6bfc 100644
--- a/src/cairo-skiplist.c
+++ b/src/cairo-skiplist.c
@@ -28,201 +28,23 @@
#define ELT_DATA(elt) (void *) ((char*) (elt) - list->data_size)
#define NEXT_TO_ELT(next) (skip_elt_t *) ((char *) (next) - offsetof (skip_elt_t, next))
-/* Four 256 element lookup tables back to back implementing a linear
- * feedback shift register of degree 32. */
-static unsigned const _cairo_lfsr_random_lut[1024] = {
- 0x00000000, 0x9a795537, 0xae8bff59, 0x34f2aa6e, 0xc76eab85, 0x5d17feb2,
- 0x69e554dc, 0xf39c01eb, 0x14a4023d, 0x8edd570a, 0xba2ffd64, 0x2056a853,
- 0xd3caa9b8, 0x49b3fc8f, 0x7d4156e1, 0xe73803d6, 0x2948047a, 0xb331514d,
- 0x87c3fb23, 0x1dbaae14, 0xee26afff, 0x745ffac8, 0x40ad50a6, 0xdad40591,
- 0x3dec0647, 0xa7955370, 0x9367f91e, 0x091eac29, 0xfa82adc2, 0x60fbf8f5,
- 0x5409529b, 0xce7007ac, 0x529008f4, 0xc8e95dc3, 0xfc1bf7ad, 0x6662a29a,
- 0x95fea371, 0x0f87f646, 0x3b755c28, 0xa10c091f, 0x46340ac9, 0xdc4d5ffe,
- 0xe8bff590, 0x72c6a0a7, 0x815aa14c, 0x1b23f47b, 0x2fd15e15, 0xb5a80b22,
- 0x7bd80c8e, 0xe1a159b9, 0xd553f3d7, 0x4f2aa6e0, 0xbcb6a70b, 0x26cff23c,
- 0x123d5852, 0x88440d65, 0x6f7c0eb3, 0xf5055b84, 0xc1f7f1ea, 0x5b8ea4dd,
- 0xa812a536, 0x326bf001, 0x06995a6f, 0x9ce00f58, 0xa52011e8, 0x3f5944df,
- 0x0babeeb1, 0x91d2bb86, 0x624eba6d, 0xf837ef5a, 0xccc54534, 0x56bc1003,
- 0xb18413d5, 0x2bfd46e2, 0x1f0fec8c, 0x8576b9bb, 0x76eab850, 0xec93ed67,
- 0xd8614709, 0x4218123e, 0x8c681592, 0x161140a5, 0x22e3eacb, 0xb89abffc,
- 0x4b06be17, 0xd17feb20, 0xe58d414e, 0x7ff41479, 0x98cc17af, 0x02b54298,
- 0x3647e8f6, 0xac3ebdc1, 0x5fa2bc2a, 0xc5dbe91d, 0xf1294373, 0x6b501644,
- 0xf7b0191c, 0x6dc94c2b, 0x593be645, 0xc342b372, 0x30deb299, 0xaaa7e7ae,
- 0x9e554dc0, 0x042c18f7, 0xe3141b21, 0x796d4e16, 0x4d9fe478, 0xd7e6b14f,
- 0x247ab0a4, 0xbe03e593, 0x8af14ffd, 0x10881aca, 0xdef81d66, 0x44814851,
- 0x7073e23f, 0xea0ab708, 0x1996b6e3, 0x83efe3d4, 0xb71d49ba, 0x2d641c8d,
- 0xca5c1f5b, 0x50254a6c, 0x64d7e002, 0xfeaeb535, 0x0d32b4de, 0x974be1e9,
- 0xa3b94b87, 0x39c01eb0, 0xd03976e7, 0x4a4023d0, 0x7eb289be, 0xe4cbdc89,
- 0x1757dd62, 0x8d2e8855, 0xb9dc223b, 0x23a5770c, 0xc49d74da, 0x5ee421ed,
- 0x6a168b83, 0xf06fdeb4, 0x03f3df5f, 0x998a8a68, 0xad782006, 0x37017531,
- 0xf971729d, 0x630827aa, 0x57fa8dc4, 0xcd83d8f3, 0x3e1fd918, 0xa4668c2f,
- 0x90942641, 0x0aed7376, 0xedd570a0, 0x77ac2597, 0x435e8ff9, 0xd927dace,
- 0x2abbdb25, 0xb0c28e12, 0x8430247c, 0x1e49714b, 0x82a97e13, 0x18d02b24,
- 0x2c22814a, 0xb65bd47d, 0x45c7d596, 0xdfbe80a1, 0xeb4c2acf, 0x71357ff8,
- 0x960d7c2e, 0x0c742919, 0x38868377, 0xa2ffd640, 0x5163d7ab, 0xcb1a829c,
- 0xffe828f2, 0x65917dc5, 0xabe17a69, 0x31982f5e, 0x056a8530, 0x9f13d007,
- 0x6c8fd1ec, 0xf6f684db, 0xc2042eb5, 0x587d7b82, 0xbf457854, 0x253c2d63,
- 0x11ce870d, 0x8bb7d23a, 0x782bd3d1, 0xe25286e6, 0xd6a02c88, 0x4cd979bf,
- 0x7519670f, 0xef603238, 0xdb929856, 0x41ebcd61, 0xb277cc8a, 0x280e99bd,
- 0x1cfc33d3, 0x868566e4, 0x61bd6532, 0xfbc43005, 0xcf369a6b, 0x554fcf5c,
- 0xa6d3ceb7, 0x3caa9b80, 0x085831ee, 0x922164d9, 0x5c516375, 0xc6283642,
- 0xf2da9c2c, 0x68a3c91b, 0x9b3fc8f0, 0x01469dc7, 0x35b437a9, 0xafcd629e,
- 0x48f56148, 0xd28c347f, 0xe67e9e11, 0x7c07cb26, 0x8f9bcacd, 0x15e29ffa,
- 0x21103594, 0xbb6960a3, 0x27896ffb, 0xbdf03acc, 0x890290a2, 0x137bc595,
- 0xe0e7c47e, 0x7a9e9149, 0x4e6c3b27, 0xd4156e10, 0x332d6dc6, 0xa95438f1,
- 0x9da6929f, 0x07dfc7a8, 0xf443c643, 0x6e3a9374, 0x5ac8391a, 0xc0b16c2d,
- 0x0ec16b81, 0x94b83eb6, 0xa04a94d8, 0x3a33c1ef, 0xc9afc004, 0x53d69533,
- 0x67243f5d, 0xfd5d6a6a, 0x1a6569bc, 0x801c3c8b, 0xb4ee96e5, 0x2e97c3d2,
- 0xdd0bc239, 0x4772970e, 0x73803d60, 0xe9f96857, 0x00000000, 0x3a0bb8f9,
- 0x741771f2, 0x4e1cc90b, 0xe82ee3e4, 0xd2255b1d, 0x9c399216, 0xa6322aef,
- 0x4a2492ff, 0x702f2a06, 0x3e33e30d, 0x04385bf4, 0xa20a711b, 0x9801c9e2,
- 0xd61d00e9, 0xec16b810, 0x944925fe, 0xae429d07, 0xe05e540c, 0xda55ecf5,
- 0x7c67c61a, 0x466c7ee3, 0x0870b7e8, 0x327b0f11, 0xde6db701, 0xe4660ff8,
- 0xaa7ac6f3, 0x90717e0a, 0x364354e5, 0x0c48ec1c, 0x42542517, 0x785f9dee,
- 0xb2eb1ecb, 0x88e0a632, 0xc6fc6f39, 0xfcf7d7c0, 0x5ac5fd2f, 0x60ce45d6,
- 0x2ed28cdd, 0x14d93424, 0xf8cf8c34, 0xc2c434cd, 0x8cd8fdc6, 0xb6d3453f,
- 0x10e16fd0, 0x2aead729, 0x64f61e22, 0x5efda6db, 0x26a23b35, 0x1ca983cc,
- 0x52b54ac7, 0x68bef23e, 0xce8cd8d1, 0xf4876028, 0xba9ba923, 0x809011da,
- 0x6c86a9ca, 0x568d1133, 0x1891d838, 0x229a60c1, 0x84a84a2e, 0xbea3f2d7,
- 0xf0bf3bdc, 0xcab48325, 0xffaf68a1, 0xc5a4d058, 0x8bb81953, 0xb1b3a1aa,
- 0x17818b45, 0x2d8a33bc, 0x6396fab7, 0x599d424e, 0xb58bfa5e, 0x8f8042a7,
- 0xc19c8bac, 0xfb973355, 0x5da519ba, 0x67aea143, 0x29b26848, 0x13b9d0b1,
- 0x6be64d5f, 0x51edf5a6, 0x1ff13cad, 0x25fa8454, 0x83c8aebb, 0xb9c31642,
- 0xf7dfdf49, 0xcdd467b0, 0x21c2dfa0, 0x1bc96759, 0x55d5ae52, 0x6fde16ab,
- 0xc9ec3c44, 0xf3e784bd, 0xbdfb4db6, 0x87f0f54f, 0x4d44766a, 0x774fce93,
- 0x39530798, 0x0358bf61, 0xa56a958e, 0x9f612d77, 0xd17de47c, 0xeb765c85,
- 0x0760e495, 0x3d6b5c6c, 0x73779567, 0x497c2d9e, 0xef4e0771, 0xd545bf88,
- 0x9b597683, 0xa152ce7a, 0xd90d5394, 0xe306eb6d, 0xad1a2266, 0x97119a9f,
- 0x3123b070, 0x0b280889, 0x4534c182, 0x7f3f797b, 0x9329c16b, 0xa9227992,
- 0xe73eb099, 0xdd350860, 0x7b07228f, 0x410c9a76, 0x0f10537d, 0x351beb84,
- 0x65278475, 0x5f2c3c8c, 0x1130f587, 0x2b3b4d7e, 0x8d096791, 0xb702df68,
- 0xf91e1663, 0xc315ae9a, 0x2f03168a, 0x1508ae73, 0x5b146778, 0x611fdf81,
- 0xc72df56e, 0xfd264d97, 0xb33a849c, 0x89313c65, 0xf16ea18b, 0xcb651972,
- 0x8579d079, 0xbf726880, 0x1940426f, 0x234bfa96, 0x6d57339d, 0x575c8b64,
- 0xbb4a3374, 0x81418b8d, 0xcf5d4286, 0xf556fa7f, 0x5364d090, 0x696f6869,
- 0x2773a162, 0x1d78199b, 0xd7cc9abe, 0xedc72247, 0xa3dbeb4c, 0x99d053b5,
- 0x3fe2795a, 0x05e9c1a3, 0x4bf508a8, 0x71feb051, 0x9de80841, 0xa7e3b0b8,
- 0xe9ff79b3, 0xd3f4c14a, 0x75c6eba5, 0x4fcd535c, 0x01d19a57, 0x3bda22ae,
- 0x4385bf40, 0x798e07b9, 0x3792ceb2, 0x0d99764b, 0xabab5ca4, 0x91a0e45d,
- 0xdfbc2d56, 0xe5b795af, 0x09a12dbf, 0x33aa9546, 0x7db65c4d, 0x47bde4b4,
- 0xe18fce5b, 0xdb8476a2, 0x9598bfa9, 0xaf930750, 0x9a88ecd4, 0xa083542d,
- 0xee9f9d26, 0xd49425df, 0x72a60f30, 0x48adb7c9, 0x06b17ec2, 0x3cbac63b,
- 0xd0ac7e2b, 0xeaa7c6d2, 0xa4bb0fd9, 0x9eb0b720, 0x38829dcf, 0x02892536,
- 0x4c95ec3d, 0x769e54c4, 0x0ec1c92a, 0x34ca71d3, 0x7ad6b8d8, 0x40dd0021,
- 0xe6ef2ace, 0xdce49237, 0x92f85b3c, 0xa8f3e3c5, 0x44e55bd5, 0x7eeee32c,
- 0x30f22a27, 0x0af992de, 0xaccbb831, 0x96c000c8, 0xd8dcc9c3, 0xe2d7713a,
- 0x2863f21f, 0x12684ae6, 0x5c7483ed, 0x667f3b14, 0xc04d11fb, 0xfa46a902,
- 0xb45a6009, 0x8e51d8f0, 0x624760e0, 0x584cd819, 0x16501112, 0x2c5ba9eb,
- 0x8a698304, 0xb0623bfd, 0xfe7ef2f6, 0xc4754a0f, 0xbc2ad7e1, 0x86216f18,
- 0xc83da613, 0xf2361eea, 0x54043405, 0x6e0f8cfc, 0x201345f7, 0x1a18fd0e,
- 0xf60e451e, 0xcc05fde7, 0x821934ec, 0xb8128c15, 0x1e20a6fa, 0x242b1e03,
- 0x6a37d708, 0x503c6ff1, 0x00000000, 0xca4f08ea, 0x0ee744e3, 0xc4a84c09,
- 0x1dce89c6, 0xd781812c, 0x1329cd25, 0xd966c5cf, 0x3b9d138c, 0xf1d21b66,
- 0x357a576f, 0xff355f85, 0x26539a4a, 0xec1c92a0, 0x28b4dea9, 0xe2fbd643,
- 0x773a2718, 0xbd752ff2, 0x79dd63fb, 0xb3926b11, 0x6af4aede, 0xa0bba634,
- 0x6413ea3d, 0xae5ce2d7, 0x4ca73494, 0x86e83c7e, 0x42407077, 0x880f789d,
- 0x5169bd52, 0x9b26b5b8, 0x5f8ef9b1, 0x95c1f15b, 0xee744e30, 0x243b46da,
- 0xe0930ad3, 0x2adc0239, 0xf3bac7f6, 0x39f5cf1c, 0xfd5d8315, 0x37128bff,
- 0xd5e95dbc, 0x1fa65556, 0xdb0e195f, 0x114111b5, 0xc827d47a, 0x0268dc90,
- 0xc6c09099, 0x0c8f9873, 0x994e6928, 0x530161c2, 0x97a92dcb, 0x5de62521,
- 0x8480e0ee, 0x4ecfe804, 0x8a67a40d, 0x4028ace7, 0xa2d37aa4, 0x689c724e,
- 0xac343e47, 0x667b36ad, 0xbf1df362, 0x7552fb88, 0xb1fab781, 0x7bb5bf6b,
- 0x4691c957, 0x8cdec1bd, 0x48768db4, 0x8239855e, 0x5b5f4091, 0x9110487b,
- 0x55b80472, 0x9ff70c98, 0x7d0cdadb, 0xb743d231, 0x73eb9e38, 0xb9a496d2,
- 0x60c2531d, 0xaa8d5bf7, 0x6e2517fe, 0xa46a1f14, 0x31abee4f, 0xfbe4e6a5,
- 0x3f4caaac, 0xf503a246, 0x2c656789, 0xe62a6f63, 0x2282236a, 0xe8cd2b80,
- 0x0a36fdc3, 0xc079f529, 0x04d1b920, 0xce9eb1ca, 0x17f87405, 0xddb77cef,
- 0x191f30e6, 0xd350380c, 0xa8e58767, 0x62aa8f8d, 0xa602c384, 0x6c4dcb6e,
- 0xb52b0ea1, 0x7f64064b, 0xbbcc4a42, 0x718342a8, 0x937894eb, 0x59379c01,
- 0x9d9fd008, 0x57d0d8e2, 0x8eb61d2d, 0x44f915c7, 0x805159ce, 0x4a1e5124,
- 0xdfdfa07f, 0x1590a895, 0xd138e49c, 0x1b77ec76, 0xc21129b9, 0x085e2153,
- 0xccf66d5a, 0x06b965b0, 0xe442b3f3, 0x2e0dbb19, 0xeaa5f710, 0x20eafffa,
- 0xf98c3a35, 0x33c332df, 0xf76b7ed6, 0x3d24763c, 0x8d2392ae, 0x476c9a44,
- 0x83c4d64d, 0x498bdea7, 0x90ed1b68, 0x5aa21382, 0x9e0a5f8b, 0x54455761,
- 0xb6be8122, 0x7cf189c8, 0xb859c5c1, 0x7216cd2b, 0xab7008e4, 0x613f000e,
- 0xa5974c07, 0x6fd844ed, 0xfa19b5b6, 0x3056bd5c, 0xf4fef155, 0x3eb1f9bf,
- 0xe7d73c70, 0x2d98349a, 0xe9307893, 0x237f7079, 0xc184a63a, 0x0bcbaed0,
- 0xcf63e2d9, 0x052cea33, 0xdc4a2ffc, 0x16052716, 0xd2ad6b1f, 0x18e263f5,
- 0x6357dc9e, 0xa918d474, 0x6db0987d, 0xa7ff9097, 0x7e995558, 0xb4d65db2,
- 0x707e11bb, 0xba311951, 0x58cacf12, 0x9285c7f8, 0x562d8bf1, 0x9c62831b,
- 0x450446d4, 0x8f4b4e3e, 0x4be30237, 0x81ac0add, 0x146dfb86, 0xde22f36c,
- 0x1a8abf65, 0xd0c5b78f, 0x09a37240, 0xc3ec7aaa, 0x074436a3, 0xcd0b3e49,
- 0x2ff0e80a, 0xe5bfe0e0, 0x2117ace9, 0xeb58a403, 0x323e61cc, 0xf8716926,
- 0x3cd9252f, 0xf6962dc5, 0xcbb25bf9, 0x01fd5313, 0xc5551f1a, 0x0f1a17f0,
- 0xd67cd23f, 0x1c33dad5, 0xd89b96dc, 0x12d49e36, 0xf02f4875, 0x3a60409f,
- 0xfec80c96, 0x3487047c, 0xede1c1b3, 0x27aec959, 0xe3068550, 0x29498dba,
- 0xbc887ce1, 0x76c7740b, 0xb26f3802, 0x782030e8, 0xa146f527, 0x6b09fdcd,
- 0xafa1b1c4, 0x65eeb92e, 0x87156f6d, 0x4d5a6787, 0x89f22b8e, 0x43bd2364,
- 0x9adbe6ab, 0x5094ee41, 0x943ca248, 0x5e73aaa2, 0x25c615c9, 0xef891d23,
- 0x2b21512a, 0xe16e59c0, 0x38089c0f, 0xf24794e5, 0x36efd8ec, 0xfca0d006,
- 0x1e5b0645, 0xd4140eaf, 0x10bc42a6, 0xdaf34a4c, 0x03958f83, 0xc9da8769,
- 0x0d72cb60, 0xc73dc38a, 0x52fc32d1, 0x98b33a3b, 0x5c1b7632, 0x96547ed8,
- 0x4f32bb17, 0x857db3fd, 0x41d5fff4, 0x8b9af71e, 0x6961215d, 0xa32e29b7,
- 0x678665be, 0xadc96d54, 0x74afa89b, 0xbee0a071, 0x7a48ec78, 0xb007e492,
- 0x00000000, 0x803e706b, 0x9a05b5e1, 0x1a3bc58a, 0xae723ef5, 0x2e4c4e9e,
- 0x34778b14, 0xb449fb7f, 0xc69d28dd, 0x46a358b6, 0x5c989d3c, 0xdca6ed57,
- 0x68ef1628, 0xe8d16643, 0xf2eaa3c9, 0x72d4d3a2, 0x1743048d, 0x977d74e6,
- 0x8d46b16c, 0x0d78c107, 0xb9313a78, 0x390f4a13, 0x23348f99, 0xa30afff2,
- 0xd1de2c50, 0x51e05c3b, 0x4bdb99b1, 0xcbe5e9da, 0x7fac12a5, 0xff9262ce,
- 0xe5a9a744, 0x6597d72f, 0x2e86091a, 0xaeb87971, 0xb483bcfb, 0x34bdcc90,
- 0x80f437ef, 0x00ca4784, 0x1af1820e, 0x9acff265, 0xe81b21c7, 0x682551ac,
- 0x721e9426, 0xf220e44d, 0x46691f32, 0xc6576f59, 0xdc6caad3, 0x5c52dab8,
- 0x39c50d97, 0xb9fb7dfc, 0xa3c0b876, 0x23fec81d, 0x97b73362, 0x17894309,
- 0x0db28683, 0x8d8cf6e8, 0xff58254a, 0x7f665521, 0x655d90ab, 0xe563e0c0,
- 0x512a1bbf, 0xd1146bd4, 0xcb2fae5e, 0x4b11de35, 0x5d0c1234, 0xdd32625f,
- 0xc709a7d5, 0x4737d7be, 0xf37e2cc1, 0x73405caa, 0x697b9920, 0xe945e94b,
- 0x9b913ae9, 0x1baf4a82, 0x01948f08, 0x81aaff63, 0x35e3041c, 0xb5dd7477,
- 0xafe6b1fd, 0x2fd8c196, 0x4a4f16b9, 0xca7166d2, 0xd04aa358, 0x5074d333,
- 0xe43d284c, 0x64035827, 0x7e389dad, 0xfe06edc6, 0x8cd23e64, 0x0cec4e0f,
- 0x16d78b85, 0x96e9fbee, 0x22a00091, 0xa29e70fa, 0xb8a5b570, 0x389bc51b,
- 0x738a1b2e, 0xf3b46b45, 0xe98faecf, 0x69b1dea4, 0xddf825db, 0x5dc655b0,
- 0x47fd903a, 0xc7c3e051, 0xb51733f3, 0x35294398, 0x2f128612, 0xaf2cf679,
- 0x1b650d06, 0x9b5b7d6d, 0x8160b8e7, 0x015ec88c, 0x64c91fa3, 0xe4f76fc8,
- 0xfeccaa42, 0x7ef2da29, 0xcabb2156, 0x4a85513d, 0x50be94b7, 0xd080e4dc,
- 0xa254377e, 0x226a4715, 0x3851829f, 0xb86ff2f4, 0x0c26098b, 0x8c1879e0,
- 0x9623bc6a, 0x161dcc01, 0xba182468, 0x3a265403, 0x201d9189, 0xa023e1e2,
- 0x146a1a9d, 0x94546af6, 0x8e6faf7c, 0x0e51df17, 0x7c850cb5, 0xfcbb7cde,
- 0xe680b954, 0x66bec93f, 0xd2f73240, 0x52c9422b, 0x48f287a1, 0xc8ccf7ca,
- 0xad5b20e5, 0x2d65508e, 0x375e9504, 0xb760e56f, 0x03291e10, 0x83176e7b,
- 0x992cabf1, 0x1912db9a, 0x6bc60838, 0xebf87853, 0xf1c3bdd9, 0x71fdcdb2,
- 0xc5b436cd, 0x458a46a6, 0x5fb1832c, 0xdf8ff347, 0x949e2d72, 0x14a05d19,
- 0x0e9b9893, 0x8ea5e8f8, 0x3aec1387, 0xbad263ec, 0xa0e9a666, 0x20d7d60d,
- 0x520305af, 0xd23d75c4, 0xc806b04e, 0x4838c025, 0xfc713b5a, 0x7c4f4b31,
- 0x66748ebb, 0xe64afed0, 0x83dd29ff, 0x03e35994, 0x19d89c1e, 0x99e6ec75,
- 0x2daf170a, 0xad916761, 0xb7aaa2eb, 0x3794d280, 0x45400122, 0xc57e7149,
- 0xdf45b4c3, 0x5f7bc4a8, 0xeb323fd7, 0x6b0c4fbc, 0x71378a36, 0xf109fa5d,
- 0xe714365c, 0x672a4637, 0x7d1183bd, 0xfd2ff3d6, 0x496608a9, 0xc95878c2,
- 0xd363bd48, 0x535dcd23, 0x21891e81, 0xa1b76eea, 0xbb8cab60, 0x3bb2db0b,
- 0x8ffb2074, 0x0fc5501f, 0x15fe9595, 0x95c0e5fe, 0xf05732d1, 0x706942ba,
- 0x6a528730, 0xea6cf75b, 0x5e250c24, 0xde1b7c4f, 0xc420b9c5, 0x441ec9ae,
- 0x36ca1a0c, 0xb6f46a67, 0xaccfafed, 0x2cf1df86, 0x98b824f9, 0x18865492,
- 0x02bd9118, 0x8283e173, 0xc9923f46, 0x49ac4f2d, 0x53978aa7, 0xd3a9facc,
- 0x67e001b3, 0xe7de71d8, 0xfde5b452, 0x7ddbc439, 0x0f0f179b, 0x8f3167f0,
- 0x950aa27a, 0x1534d211, 0xa17d296e, 0x21435905, 0x3b789c8f, 0xbb46ece4,
- 0xded13bcb, 0x5eef4ba0, 0x44d48e2a, 0xc4eafe41, 0x70a3053e, 0xf09d7555,
- 0xeaa6b0df, 0x6a98c0b4, 0x184c1316, 0x9872637d, 0x8249a6f7, 0x0277d69c,
- 0xb63e2de3, 0x36005d88, 0x2c3b9802, 0xac05e869};
-
-static unsigned _cairo_lfsr_random_state = 0x12345678;
-
-static unsigned
-lfsr_random(void)
+static uint32_t
+hars_petruska_f54_1_random (void)
{
- unsigned next;
- next = _cairo_lfsr_random_lut[((_cairo_lfsr_random_state>> 0) & 0xFF) + 0*256];
- next ^= _cairo_lfsr_random_lut[((_cairo_lfsr_random_state>> 8) & 0xFF) + 1*256];
- next ^= _cairo_lfsr_random_lut[((_cairo_lfsr_random_state>>16) & 0xFF) + 2*256];
- next ^= _cairo_lfsr_random_lut[((_cairo_lfsr_random_state>>24) & 0xFF) + 3*256];
- return _cairo_lfsr_random_state = next;
+# define rol(x,k) ((x << k) | (x >> (32-k)))
+ static uint32_t x = 0;
+ x = (x ^ rol(x, 5) ^ rol(x, 24)) + 0x37798849;
+ return x;
+# undef rol
}
/*
* Initialize an empty skip list
*/
void
-_cairo_skip_list_init (cairo_skip_list_t *list,
- cairo_skip_list_compare_t compare,
- size_t elt_size)
+_cairo_skip_list_init (cairo_skip_list_t *list,
+ cairo_skip_list_compare_t compare,
+ size_t elt_size)
{
int i;
@@ -269,20 +91,22 @@ _cairo_skip_list_fini (cairo_skip_list_t *list)
static int
random_level (void)
{
- int level = 0;
/* tricky bit -- each bit is '1' 75% of the time.
* This works because we only use the lower MAX_LEVEL
* bits, and MAX_LEVEL < 16 */
- long int bits = lfsr_random();
- bits |= bits >> 16;
-
- while (++level < MAX_LEVEL)
- {
- if (bits & 1)
- break;
+ uint32_t bits = hars_petruska_f54_1_random ();
+#if HAVE_FFS
+ return ffs (-(1<<MAX_LEVEL) | bits | bits >> 16);
+#else
+ int level = 1;
+
+ bits |= -(1<<MAX_LEVEL) | bits >> 16;
+ while ((bits & 1) == 0) {
+ level++;
bits >>= 1;
}
return level;
+#endif
}
static void *
@@ -359,7 +183,7 @@ _cairo_skip_list_insert (cairo_skip_list_t *list, void *data, int unique)
}
data_and_elt = alloc_node_for_level (list, level);
- if (data_and_elt == NULL) {
+ if (unlikely (data_and_elt == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
@@ -483,3 +307,39 @@ _cairo_skip_list_delete_given (cairo_skip_list_t *list, skip_elt_t *given)
list->max_level--;
free_elt (list, elt);
}
+
+#if MAIN
+typedef struct {
+ int n;
+ skip_elt_t elt;
+} test_elt_t;
+
+static int
+test_cmp (void *list, void *A, void *B)
+{
+ const test_elt_t *a = A, *b = B;
+ return a->n - b->n;
+}
+
+int
+main (void)
+{
+ cairo_skip_list_t list;
+ test_elt_t elt;
+ int n;
+
+ _cairo_skip_list_init (&list, test_cmp, sizeof (test_elt_t));
+ for (n = 0; n < 10000000; n++) {
+ void *elt_and_data;
+ elt.n = n;
+ elt_and_data = _cairo_skip_list_insert (&list, &elt, TRUE);
+ assert (elt_and_data != NULL);
+ }
+ _cairo_skip_list_fini (&list);
+
+ return 0;
+}
+
+/* required supporting stubs */
+cairo_status_t _cairo_error (cairo_status_t status) { return status; }
+#endif
diff --git a/src/cairo-spans-private.h b/src/cairo-spans-private.h
new file mode 100644
index 00000000..c285f949
--- /dev/null
+++ b/src/cairo-spans-private.h
@@ -0,0 +1,144 @@
+/* -*- 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;
+};
+
+/* 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 *
+_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);
+
+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
new file mode 100644
index 00000000..e441143b
--- /dev/null
+++ b/src/cairo-spans.c
@@ -0,0 +1,395 @@
+/* -*- 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"
+
+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)
+{
+ 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
+_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)
+{
+ (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/cairo-spline.c b/src/cairo-spline.c
index b39257e2..b5285447 100644
--- a/src/cairo-spline.c
+++ b/src/cairo-spline.c
@@ -36,29 +36,16 @@
#include "cairoint.h"
-static cairo_status_t
-_cairo_spline_grow (cairo_spline_t *spline);
-
-static cairo_status_t
-_cairo_spline_add_point (cairo_spline_t *spline, const cairo_point_t *point);
-
-static void
-_lerp_half (const cairo_point_t *a, const cairo_point_t *b, cairo_point_t *result);
-
-static void
-_de_casteljau (cairo_spline_knots_t *s1, cairo_spline_knots_t *s2);
-
-static double
-_cairo_spline_error_squared (const cairo_spline_knots_t *spline);
-
-static cairo_status_t
-_cairo_spline_decompose_into (cairo_spline_knots_t *spline, double tolerance_squared, cairo_spline_t *result);
-
-cairo_int_status_t
+cairo_bool_t
_cairo_spline_init (cairo_spline_t *spline,
+ void (*add_point_func) (void*, const cairo_point_t *),
+ void *closure,
const cairo_point_t *a, const cairo_point_t *b,
const cairo_point_t *c, const cairo_point_t *d)
{
+ spline->add_point_func = add_point_func;
+ spline->closure = closure;
+
spline->knots.a = *a;
spline->knots.b = *b;
spline->knots.c = *c;
@@ -71,7 +58,7 @@ _cairo_spline_init (cairo_spline_t *spline,
else if (a->x != d->x || a->y != d->y)
_cairo_slope_init (&spline->initial_slope, &spline->knots.a, &spline->knots.d);
else
- return CAIRO_INT_STATUS_DEGENERATE;
+ return FALSE;
if (c->x != d->x || c->y != d->y)
_cairo_slope_init (&spline->final_slope, &spline->knots.c, &spline->knots.d);
@@ -80,74 +67,25 @@ _cairo_spline_init (cairo_spline_t *spline,
else
_cairo_slope_init (&spline->final_slope, &spline->knots.a, &spline->knots.d);
- spline->points = spline->points_embedded;
- spline->points_size = ARRAY_LENGTH (spline->points_embedded);
- spline->num_points = 0;
-
- return CAIRO_STATUS_SUCCESS;
+ return TRUE;
}
void
_cairo_spline_fini (cairo_spline_t *spline)
{
- if (spline->points != spline->points_embedded)
- free (spline->points);
-
- spline->points = spline->points_embedded;
- spline->points_size = ARRAY_LENGTH (spline->points_embedded);
- spline->num_points = 0;
}
-/* make room for at least one more point */
-static cairo_status_t
-_cairo_spline_grow (cairo_spline_t *spline)
-{
- cairo_point_t *new_points;
- int old_size = spline->points_size;
- int new_size = 2 * MAX (old_size, 16);
-
- assert (spline->num_points <= spline->points_size);
-
- if (spline->points == spline->points_embedded) {
- new_points = _cairo_malloc_ab (new_size, sizeof (cairo_point_t));
- if (new_points)
- memcpy (new_points, spline->points, old_size * sizeof (cairo_point_t));
- } else {
- new_points = _cairo_realloc_ab (spline->points,
- new_size, sizeof (cairo_point_t));
- }
-
- if (new_points == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- spline->points = new_points;
- spline->points_size = new_size;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
+static void
_cairo_spline_add_point (cairo_spline_t *spline, const cairo_point_t *point)
{
- cairo_status_t status;
cairo_point_t *prev;
- if (spline->num_points) {
- prev = &spline->points[spline->num_points - 1];
- if (prev->x == point->x && prev->y == point->y)
- return CAIRO_STATUS_SUCCESS;
- }
-
- if (spline->num_points >= spline->points_size) {
- status = _cairo_spline_grow (spline);
- if (status)
- return status;
- }
-
- spline->points[spline->num_points] = *point;
- spline->num_points++;
+ prev = &spline->last_point;
+ if (prev->x == point->x && prev->y == point->y)
+ return;
- return CAIRO_STATUS_SUCCESS;
+ spline->add_point_func (spline->closure, point);
+ spline->last_point = *point;
}
static void
@@ -243,45 +181,30 @@ _cairo_spline_error_squared (const cairo_spline_knots_t *knots)
return cerr;
}
-static cairo_status_t
+static void
_cairo_spline_decompose_into (cairo_spline_knots_t *s1, double tolerance_squared, cairo_spline_t *result)
{
cairo_spline_knots_t s2;
- cairo_status_t status;
- if (_cairo_spline_error_squared (s1) < tolerance_squared)
- return _cairo_spline_add_point (result, &s1->a);
+ if (_cairo_spline_error_squared (s1) < tolerance_squared) {
+ _cairo_spline_add_point (result, &s1->a);
+ return;
+ }
_de_casteljau (s1, &s2);
- status = _cairo_spline_decompose_into (s1, tolerance_squared, result);
- if (status)
- return status;
-
- status = _cairo_spline_decompose_into (&s2, tolerance_squared, result);
- if (status)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
+ _cairo_spline_decompose_into (s1, tolerance_squared, result);
+ _cairo_spline_decompose_into (&s2, tolerance_squared, result);
}
-cairo_status_t
+void
_cairo_spline_decompose (cairo_spline_t *spline, double tolerance)
{
- cairo_status_t status;
cairo_spline_knots_t s1;
- /* reset the spline, but keep the buffer */
- spline->num_points = 0;
-
s1 = spline->knots;
- status = _cairo_spline_decompose_into (&s1, tolerance * tolerance, spline);
- if (status)
- return status;
-
- status = _cairo_spline_add_point (spline, &spline->knots.d);
- if (status)
- return status;
+ spline->last_point = s1.a;
+ _cairo_spline_decompose_into (&s1, tolerance * tolerance, spline);
- return CAIRO_STATUS_SUCCESS;
+ _cairo_spline_add_point (spline, &spline->knots.d);
}
diff --git a/src/cairo-stroke-style.c b/src/cairo-stroke-style.c
index 3bc234e9..edc4f889 100644
--- a/src/cairo-stroke-style.c
+++ b/src/cairo-stroke-style.c
@@ -63,7 +63,7 @@ _cairo_stroke_style_init_copy (cairo_stroke_style_t *style,
style->dash = NULL;
} else {
style->dash = _cairo_malloc_ab (style->num_dashes, sizeof (double));
- if (style->dash == NULL)
+ if (unlikely (style->dash == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (style->dash, other->dash,
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index a5dcd57a..88975e9a 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -79,7 +79,7 @@ _fallback_init (fallback_state_t *state,
status = _cairo_surface_acquire_dest_image (dst, &state->extents,
&state->image, &state->image_rect,
&state->image_extra);
- if (status)
+ if (unlikely (status))
return status;
/* XXX: This NULL value tucked away in state->image is a rather
@@ -131,7 +131,7 @@ _create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern,
NULL, mask,
extents->x, extents->y,
extents);
- if (status)
+ if (unlikely (status))
goto CLEANUP_SURFACE;
if (clip && clip->surface)
@@ -139,7 +139,7 @@ _create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern,
mask,
extents->x, extents->y,
extents);
- if (status)
+ if (unlikely (status))
goto CLEANUP_SURFACE;
_cairo_pattern_init_for_surface (mask_pattern, mask);
@@ -169,7 +169,7 @@ _clip_and_composite_with_mask (cairo_clip_t *clip,
clip,
draw_func, draw_closure,
dst, extents);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_surface_composite (op,
@@ -226,14 +226,14 @@ _clip_and_composite_combine (cairo_clip_t *clip,
_cairo_pattern_fini (&dst_pattern.base);
- if (status)
+ if (unlikely (status))
goto CLEANUP_SURFACE;
status = (*draw_func) (draw_closure, op,
src, intermediate,
extents->x, extents->y,
extents);
- if (status)
+ if (unlikely (status))
goto CLEANUP_SURFACE;
/* Combine that with the clip
@@ -242,7 +242,7 @@ _clip_and_composite_combine (cairo_clip_t *clip,
intermediate,
extents->x, extents->y,
extents);
- if (status)
+ if (unlikely (status))
goto CLEANUP_SURFACE;
/* Punch the clip out of the destination
@@ -251,7 +251,7 @@ _clip_and_composite_combine (cairo_clip_t *clip,
dst,
0, 0,
extents);
- if (status)
+ if (unlikely (status))
goto CLEANUP_SURFACE;
/* Now add the two results together
@@ -293,7 +293,7 @@ _clip_and_composite_source (cairo_clip_t *clip,
clip,
draw_func, draw_closure,
dst, extents);
- if (status)
+ if (unlikely (status))
return status;
/* Compute dest' = dest OUT (mask IN clip)
@@ -305,7 +305,7 @@ _clip_and_composite_source (cairo_clip_t *clip,
extents->x, extents->y,
extents->width, extents->height);
- if (status)
+ if (unlikely (status))
goto CLEANUP_MASK_PATTERN;
/* Now compute (src IN (mask IN clip)) ADD dest'
@@ -439,7 +439,7 @@ _composite_trap_region (cairo_clip_t *clip,
status = _cairo_surface_set_clip_region (dst,
trap_region,
clip_serial);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -531,7 +531,7 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src,
return CAIRO_STATUS_SUCCESS;
status = _cairo_surface_get_extents (dst, &extents);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_traps_extract_region (traps, &trap_region);
@@ -548,7 +548,7 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src,
if (has_trap_region) {
status = _cairo_clip_intersect_to_region (clip, &trap_region);
- if (status)
+ if (unlikely (status))
goto out;
_cairo_region_get_extents (&trap_region, &trap_extents);
@@ -564,7 +564,7 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src,
}
status = _cairo_clip_intersect_to_rectangle (clip, &extents);
- if (status)
+ if (unlikely (status))
goto out;
} else {
cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
@@ -579,13 +579,13 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src,
has_clear_region = TRUE;
status = _cairo_clip_intersect_to_region (clip, &clear_region);
- if (status)
+ if (unlikely (status))
goto out;
_cairo_region_get_extents (&clear_region, &extents);
status = _cairo_region_subtract (&clear_region, &clear_region, &trap_region);
- if (status)
+ if (unlikely (status))
goto out;
if (!_cairo_region_not_empty (&clear_region)) {
@@ -597,7 +597,7 @@ _clip_and_composite_trapezoids (const cairo_pattern_t *src,
}
}
- if (status)
+ if (unlikely (status))
goto out;
if (has_trap_region) {
@@ -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,
@@ -681,14 +728,14 @@ _cairo_surface_fallback_paint (cairo_surface_t *surface,
cairo_traps_t traps;
status = _cairo_surface_get_extents (surface, &extents);
- if (status)
+ if (unlikely (status))
return status;
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
- if (status)
+ if (unlikely (status))
return status;
if (! _cairo_rectangle_intersect (&extents, &source_extents))
@@ -696,7 +743,7 @@ _cairo_surface_fallback_paint (cairo_surface_t *surface,
}
status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
- if (status)
+ if (unlikely (status))
return status;
_cairo_box_from_rectangle (&box, &extents);
@@ -752,12 +799,12 @@ _cairo_surface_fallback_mask (cairo_surface_t *surface,
cairo_rectangle_int_t extents, source_extents, mask_extents;
status = _cairo_surface_get_extents (surface, &extents);
- if (status)
+ if (unlikely (status))
return status;
if (_cairo_operator_bounded_by_source (op)) {
status = _cairo_pattern_get_extents (source, &source_extents);
- if (status)
+ if (unlikely (status))
return status;
if (! _cairo_rectangle_intersect (&extents, &source_extents))
@@ -766,7 +813,7 @@ _cairo_surface_fallback_mask (cairo_surface_t *surface,
if (_cairo_operator_bounded_by_mask (op)) {
status = _cairo_pattern_get_extents (mask, &mask_extents);
- if (status)
+ if (unlikely (status))
return status;
if (! _cairo_rectangle_intersect (&extents, &mask_extents))
@@ -774,7 +821,7 @@ _cairo_surface_fallback_mask (cairo_surface_t *surface,
}
status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
- if (status)
+ if (unlikely (status))
return status;
status = _clip_and_composite (surface->clip, op,
@@ -804,13 +851,13 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface,
cairo_rectangle_int_t extents;
status = _cairo_surface_get_extents (surface, &extents);
- if (status)
+ if (unlikely (status))
return status;
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
- if (status)
+ if (unlikely (status))
return status;
if (! _cairo_rectangle_intersect (&extents, &source_extents))
@@ -818,7 +865,7 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface,
}
status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
- if (status)
+ if (unlikely (status))
return status;
if (extents.width == 0 || extents.height == 0)
@@ -834,7 +881,7 @@ _cairo_surface_fallback_stroke (cairo_surface_t *surface,
ctm, ctm_inverse,
tolerance,
&traps);
- if (status)
+ if (unlikely (status))
goto FAIL;
status = _clip_and_composite_trapezoids (source,
@@ -865,14 +912,14 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
cairo_rectangle_int_t extents;
status = _cairo_surface_get_extents (surface, &extents);
- if (status)
+ if (unlikely (status))
return status;
if (_cairo_operator_bounded_by_source (op)) {
cairo_rectangle_int_t source_extents;
status = _cairo_pattern_get_extents (source, &source_extents);
- if (status)
+ if (unlikely (status))
return status;
if (! _cairo_rectangle_intersect (&extents, &source_extents))
@@ -880,14 +927,51 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
}
status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
- if (status)
+ if (unlikely (status))
return status;
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);
@@ -895,7 +979,7 @@ _cairo_surface_fallback_fill (cairo_surface_t *surface,
fill_rule,
tolerance,
&traps);
- if (status) {
+ if (unlikely (status)) {
_cairo_traps_fini (&traps);
return status;
}
@@ -992,7 +1076,7 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
cairo_show_glyphs_info_t glyph_info;
status = _cairo_surface_get_extents (surface, &extents);
- if (status)
+ if (unlikely (status))
return status;
if (_cairo_operator_bounded_by_mask (op)) {
@@ -1002,7 +1086,7 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
glyphs,
num_glyphs,
&glyph_extents);
- if (status)
+ if (unlikely (status))
return status;
if (! _cairo_rectangle_intersect (&extents, &glyph_extents))
@@ -1010,7 +1094,7 @@ _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
}
status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
- if (status)
+ if (unlikely (status))
return status;
glyph_info.font = scaled_font;
@@ -1036,10 +1120,16 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
cairo_surface_pattern_t pattern;
cairo_image_surface_t *image;
void *image_extra;
+ const char *mime_types[] = {
+ CAIRO_MIME_TYPE_JPEG,
+ CAIRO_MIME_TYPE_PNG,
+ CAIRO_MIME_TYPE_JP2,
+ NULL
+ }, **mime_type;
status = _cairo_surface_acquire_source_image (surface,
&image, &image_extra);
- if (status)
+ if (unlikely (status))
return _cairo_surface_create_in_error (status);
snapshot = cairo_image_surface_create (image->format,
@@ -1067,7 +1157,7 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
_cairo_surface_release_source_image (surface,
image, image_extra);
- if (status) {
+ if (unlikely (status)) {
cairo_surface_destroy (snapshot);
return _cairo_surface_create_in_error (status);
}
@@ -1075,6 +1165,14 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
snapshot->device_transform = surface->device_transform;
snapshot->device_transform_inverse = surface->device_transform_inverse;
+ for (mime_type = mime_types; *mime_type; mime_type++) {
+ status = _cairo_surface_copy_mime_data (snapshot, surface, *mime_type);
+ if (unlikely (status)) {
+ cairo_surface_destroy (snapshot);
+ return _cairo_surface_create_in_error (status);
+ }
+ }
+
snapshot->is_snapshot = TRUE;
return snapshot;
@@ -1098,7 +1196,7 @@ _cairo_surface_fallback_composite (cairo_operator_t op,
cairo_status_t status;
status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
- if (status) {
+ if (unlikely (status)) {
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
return status;
@@ -1159,7 +1257,7 @@ _cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface,
}
status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1);
- if (status) {
+ if (unlikely (status)) {
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
return status;
@@ -1169,7 +1267,7 @@ _cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface,
if (state.image_rect.x != 0 || state.image_rect.y != 0) {
offset_rects = _cairo_malloc_ab (num_rects, sizeof (cairo_rectangle_int_t));
- if (offset_rects == NULL) {
+ if (unlikely (offset_rects == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto DONE;
}
@@ -1215,7 +1313,7 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op,
cairo_status_t status;
status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
- if (status) {
+ if (unlikely (status)) {
if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
return CAIRO_STATUS_SUCCESS;
return status;
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index ff75cc2f..077af5b4 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -40,28 +40,19 @@
#include "cairo-surface-fallback-private.h"
#include "cairo-clip-private.h"
+#include "cairo-meta-surface-private.h"
#define DEFINE_NIL_SURFACE(status, name) \
const cairo_surface_t name = { \
- &_cairo_image_surface_backend, /* backend */ \
- CAIRO_SURFACE_TYPE_IMAGE, \
- CAIRO_CONTENT_COLOR, \
+ NULL, /* backend */ \
+ CAIRO_SURFACE_TYPE_IMAGE, /* type */ \
+ CAIRO_CONTENT_COLOR, /* content */ \
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ \
status, /* status */ \
FALSE, /* finished */ \
- { 0, /* size */ \
- 0, /* num_elements */ \
- 0, /* element_size */ \
- NULL, /* elements */ \
- }, /* user_data */ \
- { 1.0, 0.0, \
- 0.0, 1.0, \
- 0.0, 0.0 \
- }, /* device_transform */ \
- { 1.0, 0.0, \
- 0.0, 1.0, \
- 0.0, 0.0 \
- }, /* device_transform_inverse */ \
+ { 0, 0, 0, NULL, }, /* user_data */ \
+ { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, /* device_transform */ \
+ { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, /* device_transform_inverse */ \
0.0, /* x_resolution */ \
0.0, /* y_resolution */ \
0.0, /* x_fallback_resolution */ \
@@ -246,7 +237,7 @@ _cairo_surface_create_similar_scratch (cairo_surface_t *other,
}
/* If any error occurred, then return the nil surface we received. */
- if (surface->status)
+ if (unlikely (surface->status))
return surface;
if (other->has_font_options || other->backend != surface->backend) {
@@ -327,11 +318,11 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other,
status = _cairo_surface_paint (surface,
color == CAIRO_COLOR_TRANSPARENT ?
CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE,
- &solid_pattern.base);
+ &solid_pattern.base, NULL);
_cairo_pattern_fini (&solid_pattern.base);
- if (status) {
+ if (unlikely (status)) {
cairo_surface_destroy (surface);
return _cairo_surface_create_in_error (status);
}
@@ -373,7 +364,7 @@ _cairo_surface_repaint_solid_pattern_surface (cairo_surface_t *other,
*/
return CAIRO_INT_STATUS_UNSUPPORTED;
- return _cairo_surface_paint (solid_surface, CAIRO_OPERATOR_SOURCE, &solid_pattern->base);
+ return _cairo_surface_paint (solid_surface, CAIRO_OPERATOR_SOURCE, &solid_pattern->base, NULL);
}
cairo_clip_mode_t
@@ -464,7 +455,7 @@ _cairo_surface_reset (cairo_surface_t *surface)
if (surface->backend->reset != NULL) {
cairo_status_t status = surface->backend->reset (surface);
- if (status)
+ if (unlikely (status))
return _cairo_surface_set_error (surface, status);
}
@@ -532,7 +523,7 @@ cairo_surface_finish (cairo_surface_t *surface)
/* call finish even if in error mode */
if (surface->backend->finish) {
status = surface->backend->finish (surface);
- if (status)
+ if (unlikely (status))
status = _cairo_surface_set_error (surface, status);
}
@@ -590,6 +581,163 @@ cairo_surface_set_user_data (cairo_surface_t *surface,
}
/**
+ * cairo_surface_get_mime_data:
+ * @surface: a #cairo_surface_t
+ * @mime_type: the mime type of the image data
+ * @data: the image data to attached to the surface
+ * @length: the length of the image data
+ *
+ * Return mime data previously attached to @surface using the
+ * specified mime type. If no data has been attached with the given
+ * mime type, @data is set %NULL.
+ *
+ * Since: 1.10
+ **/
+void
+cairo_surface_get_mime_data (cairo_surface_t *surface,
+ const char *mime_type,
+ const unsigned char **data,
+ unsigned int *length)
+{
+ cairo_status_t status;
+ cairo_mime_data_t *mime_data;
+
+ *data = NULL;
+ *length = 0;
+ if (surface->status)
+ return;
+
+ status = _cairo_intern_string (&mime_type, -1);
+ if (unlikely (status)) {
+ status = _cairo_surface_set_error (surface, status);
+ return;
+ }
+
+ mime_data = _cairo_user_data_array_get_data (&surface->user_data,
+ (cairo_user_data_key_t *) mime_type);
+ if (mime_data == NULL)
+ return;
+
+ *data = mime_data->data;
+ *length = mime_data->length;
+}
+slim_hidden_def (cairo_surface_get_mime_data);
+
+static void
+_cairo_mime_data_destroy (void *ptr)
+{
+ cairo_mime_data_t *mime_data = ptr;
+
+ if (! _cairo_reference_count_dec_and_test (&mime_data->ref_count))
+ return;
+
+ if (mime_data->destroy && mime_data->closure)
+ mime_data->destroy (mime_data->closure);
+
+ free (mime_data);
+}
+
+/**
+ * cairo_surface_set_mime_data:
+ * @surface: a #cairo_surface_t
+ * @mime_type: the mime type of the image data
+ * @data: the image data to attach to the surface
+ * @length: the length of the image data
+ * @destroy: a #cairo_destroy_func_t which will be called when the
+ * surface is destroyed or when new image data is attached using the
+ * same mime type.
+ * @closure: the data to be passed to the @destroy notifier
+ *
+ * Attach an image in the format @mime_type to @surface. To remove
+ * the data from a surface, call this function with same mime type
+ * and %NULL for @data.
+ *
+ * Since: 1.10
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
+ * slot could not be allocated for the user data.
+ **/
+cairo_status_t
+cairo_surface_set_mime_data (cairo_surface_t *surface,
+ const char *mime_type,
+ const unsigned char *data,
+ unsigned int length,
+ cairo_destroy_func_t destroy,
+ void *closure)
+{
+ cairo_status_t status;
+ cairo_mime_data_t *mime_data;
+
+ if (surface->status)
+ return surface->status;
+
+ status = _cairo_intern_string (&mime_type, -1);
+ if (unlikely (status))
+ return _cairo_surface_set_error (surface, status);
+
+ if (data != NULL) {
+ mime_data = malloc (sizeof (cairo_mime_data_t));
+ if (unlikely (mime_data == NULL))
+ return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+ CAIRO_REFERENCE_COUNT_INIT (&mime_data->ref_count, 1);
+
+ mime_data->data = (unsigned char *) data;
+ mime_data->length = length;
+ mime_data->destroy = destroy;
+ mime_data->closure = closure;
+ } else
+ mime_data = NULL;
+
+ status = _cairo_user_data_array_set_data (&surface->user_data,
+ (cairo_user_data_key_t *) mime_type,
+ mime_data,
+ _cairo_mime_data_destroy);
+ if (unlikely (status))
+ return _cairo_surface_set_error (surface, status);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+slim_hidden_def (cairo_surface_set_mime_data);
+
+cairo_status_t
+_cairo_surface_copy_mime_data (cairo_surface_t *dst,
+ cairo_surface_t *src,
+ const char *mime_type)
+{
+ cairo_status_t status;
+ cairo_mime_data_t *mime_data;
+
+ if (dst->status)
+ return dst->status;
+
+ if (src->status)
+ return _cairo_surface_set_error (dst, src->status);
+
+ status = _cairo_intern_string (&mime_type, -1);
+ if (unlikely (status))
+ return _cairo_surface_set_error (dst, status);
+
+ mime_data = _cairo_user_data_array_get_data (&src->user_data,
+ (cairo_user_data_key_t *) mime_type);
+ if (mime_data == NULL)
+ return CAIRO_STATUS_SUCCESS;
+
+ _cairo_reference_count_inc (&mime_data->ref_count);
+
+ status = _cairo_user_data_array_set_data (&dst->user_data,
+ (cairo_user_data_key_t *) mime_type,
+ mime_data,
+ _cairo_mime_data_destroy);
+ if (unlikely (status)) {
+ _cairo_mime_data_destroy (mime_data);
+ return _cairo_surface_set_error (dst, status);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/**
* _cairo_surface_set_font_options:
* @surface: a #cairo_surface_t
* @options: a #cairo_font_options_t object that contains the
@@ -691,7 +839,7 @@ cairo_surface_flush (cairo_surface_t *surface)
if (surface->backend->flush) {
status = surface->backend->flush (surface);
- if (status)
+ if (unlikely (status))
status = _cairo_surface_set_error (surface, status);
}
}
@@ -769,7 +917,7 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
y + surface->device_transform.y0,
width, height);
- if (status)
+ if (unlikely (status))
status = _cairo_surface_set_error (surface, status);
}
}
@@ -1140,10 +1288,10 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
cairo_image_surface_t *image;
void *image_extra;
- if (surface->status)
+ if (unlikely (surface->status))
return surface->status;
- if (surface->finished)
+ if (unlikely (surface->finished))
return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
if (surface->backend->clone_similar) {
@@ -1155,6 +1303,31 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
clone_out);
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ /* First check to see if we can replay to a similar surface */
+ if (_cairo_surface_is_meta (src)) {
+ cairo_surface_t *similar;
+
+ similar = cairo_surface_create_similar (surface,
+ src->content,
+ width, height);
+ status = similar->status;
+ if (unlikely (status))
+ return status;
+
+ cairo_surface_set_device_offset (similar, -src_x, -src_y);
+
+ status = _cairo_meta_surface_replay (src, similar);
+ if (unlikely (status)) {
+ cairo_surface_destroy (similar);
+ return status;
+ }
+
+ *clone_out = similar;
+ *clone_offset_x = src_x;
+ *clone_offset_y = src_y;
+ return CAIRO_STATUS_SUCCESS;
+ }
+
/* If we failed, try again with an image surface */
status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
if (status == CAIRO_STATUS_SUCCESS) {
@@ -1182,7 +1355,7 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
clone_out);
/* We should never get UNSUPPORTED here, so if we have an error, bail. */
- if (status)
+ if (unlikely (status))
return status;
/* Update the clone's device_transform (which the underlying surface
@@ -1362,6 +1535,7 @@ _cairo_surface_fill_rectangle (cairo_surface_t *surface,
*
* Return value: %CAIRO_STATUS_SUCCESS or the error that occurred
**/
+COMPILE_TIME_ASSERT (sizeof (cairo_box_int_t) <= sizeof (cairo_rectangle_int_t));
cairo_status_t
_cairo_surface_fill_region (cairo_surface_t *surface,
cairo_operator_t op,
@@ -1369,8 +1543,8 @@ _cairo_surface_fill_region (cairo_surface_t *surface,
cairo_region_t *region)
{
int num_boxes;
- cairo_box_int_t *boxes = NULL;
cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
+ cairo_box_int_t *boxes = (cairo_box_int_t *) stack_rects;
cairo_rectangle_int_t *rects = stack_rects;
cairo_status_t status;
int i;
@@ -1381,31 +1555,31 @@ _cairo_surface_fill_region (cairo_surface_t *surface,
assert (! surface->is_snapshot);
num_boxes = _cairo_region_num_boxes (region);
-
if (num_boxes == 0)
return CAIRO_STATUS_SUCCESS;
/* handle the common case of a single box without allocation */
if (num_boxes > 1) {
+ num_boxes = sizeof (stack_rects) / sizeof (cairo_box_int_t);
status = _cairo_region_get_boxes (region, &num_boxes, &boxes);
- if (status)
+ if (unlikely (status))
return status;
if (num_boxes > ARRAY_LENGTH (stack_rects)) {
rects = _cairo_malloc_ab (num_boxes,
sizeof (cairo_rectangle_int_t));
- if (!rects) {
+ if (rects == NULL) {
_cairo_region_boxes_fini (region, boxes);
return _cairo_surface_set_error (surface,
- CAIRO_STATUS_NO_MEMORY);
+ _cairo_error (CAIRO_STATUS_NO_MEMORY));
}
}
for (i = 0; i < num_boxes; i++) {
rects[i].x = boxes[i].p1.x;
rects[i].y = boxes[i].p1.y;
- rects[i].width = boxes[i].p2.x - boxes[i].p1.x;
- rects[i].height = boxes[i].p2.y - boxes[i].p1.y;
+ rects[i].width = boxes[i].p2.x - rects[i].x;
+ rects[i].height = boxes[i].p2.y - rects[i].y;
}
} else
_cairo_region_get_extents (region, &rects[0]);
@@ -1413,7 +1587,7 @@ _cairo_surface_fill_region (cairo_surface_t *surface,
status = _cairo_surface_fill_rectangles (surface, op,
color, rects, num_boxes);
- if (boxes != NULL)
+ if (boxes != (cairo_box_int_t *) stack_rects)
_cairo_region_boxes_fini (region, boxes);
if (rects != stack_rects)
@@ -1473,7 +1647,8 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface,
cairo_status_t
_cairo_surface_paint (cairo_surface_t *surface,
cairo_operator_t op,
- const cairo_pattern_t *source)
+ const cairo_pattern_t *source,
+ cairo_rectangle_int_t *extents)
{
cairo_status_t status;
cairo_pattern_union_t dev_source;
@@ -1486,11 +1661,11 @@ _cairo_surface_paint (cairo_surface_t *surface,
status = _cairo_surface_copy_pattern_for_destination (&source,
surface,
&dev_source.base);
- if (status)
+ if (unlikely (status))
return _cairo_surface_set_error (surface, status);
if (surface->backend->paint) {
- status = surface->backend->paint (surface, op, source);
+ status = surface->backend->paint (surface, op, source, extents);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto FINISH;
}
@@ -1508,7 +1683,8 @@ cairo_status_t
_cairo_surface_mask (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- const cairo_pattern_t *mask)
+ const cairo_pattern_t *mask,
+ cairo_rectangle_int_t *extents)
{
cairo_status_t status;
cairo_pattern_union_t dev_source;
@@ -1522,17 +1698,17 @@ _cairo_surface_mask (cairo_surface_t *surface,
status = _cairo_surface_copy_pattern_for_destination (&source,
surface,
&dev_source.base);
- if (status)
+ if (unlikely (status))
goto FINISH;
status = _cairo_surface_copy_pattern_for_destination (&mask,
surface,
&dev_mask.base);
- if (status)
+ if (unlikely (status))
goto CLEANUP_SOURCE;
if (surface->backend->mask) {
- status = surface->backend->mask (surface, op, source, mask);
+ status = surface->backend->mask (surface, op, source, mask, extents);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto CLEANUP_MASK;
}
@@ -1564,7 +1740,8 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface,
cairo_matrix_t *stroke_ctm,
cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
- cairo_antialias_t stroke_antialias)
+ cairo_antialias_t stroke_antialias,
+ cairo_rectangle_int_t *extents)
{
cairo_status_t status;
@@ -1580,13 +1757,13 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface,
status = _cairo_surface_copy_pattern_for_destination (&stroke_source,
surface,
&dev_stroke_source.base);
- if (status)
+ if (unlikely (status))
return _cairo_surface_set_error (surface, status);
status = _cairo_surface_copy_pattern_for_destination (&fill_source,
surface,
&dev_fill_source.base);
- if (status) {
+ if (unlikely (status)) {
if (stroke_source == &dev_stroke_source.base)
_cairo_pattern_fini (&dev_stroke_source.base);
@@ -1600,7 +1777,8 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface,
stroke_op, stroke_source,
stroke_style,
&dev_ctm, &dev_ctm_inverse,
- stroke_tolerance, stroke_antialias);
+ stroke_tolerance, stroke_antialias,
+ extents);
if (stroke_source == &dev_stroke_source.base)
_cairo_pattern_fini (&dev_stroke_source.base);
@@ -1613,14 +1791,14 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface,
}
status = _cairo_surface_fill (surface, fill_op, fill_source, path,
- fill_rule, fill_tolerance, fill_antialias);
- if (status)
+ fill_rule, fill_tolerance, fill_antialias, NULL);
+ if (unlikely (status))
return _cairo_surface_set_error (surface, status);
status = _cairo_surface_stroke (surface, stroke_op, stroke_source, path,
stroke_style, stroke_ctm, stroke_ctm_inverse,
- stroke_tolerance, stroke_antialias);
- if (status)
+ stroke_tolerance, stroke_antialias, NULL);
+ if (unlikely (status))
return _cairo_surface_set_error (surface, status);
return CAIRO_STATUS_SUCCESS;
@@ -1635,7 +1813,8 @@ _cairo_surface_stroke (cairo_surface_t *surface,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
cairo_status_t status;
cairo_pattern_union_t dev_source;
@@ -1652,14 +1831,14 @@ _cairo_surface_stroke (cairo_surface_t *surface,
status = _cairo_surface_copy_pattern_for_destination (&source,
surface,
&dev_source.base);
- if (status)
+ if (unlikely (status))
return _cairo_surface_set_error (surface, status);
if (surface->backend->stroke) {
status = surface->backend->stroke (surface, op, source,
path, stroke_style,
&dev_ctm, &dev_ctm_inverse,
- tolerance, antialias);
+ tolerance, antialias, extents);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto FINISH;
@@ -1687,7 +1866,8 @@ _cairo_surface_fill (cairo_surface_t *surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
cairo_status_t status;
cairo_pattern_union_t dev_source;
@@ -1700,13 +1880,13 @@ _cairo_surface_fill (cairo_surface_t *surface,
status = _cairo_surface_copy_pattern_for_destination (&source,
surface,
&dev_source.base);
- if (status)
+ if (unlikely (status))
return _cairo_surface_set_error (surface, status);
if (surface->backend->fill) {
status = surface->backend->fill (surface, op, source,
path, fill_rule,
- tolerance, antialias);
+ tolerance, antialias, extents);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
goto FINISH;
@@ -1773,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
@@ -1917,13 +2150,13 @@ _cairo_surface_reset_clip (cairo_surface_t *surface)
CAIRO_FILL_RULE_WINDING,
0,
CAIRO_ANTIALIAS_DEFAULT);
- if (status)
+ if (unlikely (status))
return _cairo_surface_set_error (surface, status);
}
if (surface->backend->set_clip_region != NULL) {
status = surface->backend->set_clip_region (surface, NULL);
- if (status)
+ if (unlikely (status))
return _cairo_surface_set_error (surface, status);
}
@@ -1952,11 +2185,13 @@ _cairo_surface_set_clip_region (cairo_surface_t *surface,
assert (surface->backend->set_clip_region != NULL);
- surface->current_clip_serial = serial;
-
status = surface->backend->set_clip_region (surface, region);
+ if (unlikely (status))
+ return _cairo_surface_set_error (surface, status);
- return _cairo_surface_set_error (surface, status);
+ surface->current_clip_serial = serial;
+
+ return CAIRO_STATUS_SUCCESS;
}
cairo_int_status_t
@@ -1999,7 +2234,7 @@ _cairo_surface_set_clip_path_recursive (cairo_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
status = _cairo_surface_set_clip_path_recursive (surface, clip_path->prev);
- if (status)
+ if (unlikely (status))
return status;
return _cairo_surface_intersect_clip_path (surface,
@@ -2038,11 +2273,11 @@ _cairo_surface_set_clip_path (cairo_surface_t *surface,
CAIRO_FILL_RULE_WINDING,
0,
CAIRO_ANTIALIAS_DEFAULT);
- if (status)
+ if (unlikely (status))
return _cairo_surface_set_error (surface, status);
status = _cairo_surface_set_clip_path_recursive (surface, clip_path);
- if (status)
+ if (unlikely (status))
return _cairo_surface_set_error (surface, status);
surface->current_clip_serial = serial;
@@ -2258,7 +2493,8 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
- cairo_scaled_font_t *scaled_font)
+ cairo_scaled_font_t *scaled_font,
+ cairo_rectangle_int_t *extents)
{
cairo_status_t status;
cairo_scaled_font_t *dev_scaled_font = scaled_font;
@@ -2275,7 +2511,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
status = _cairo_surface_copy_pattern_for_destination (&source,
surface,
&dev_source.base);
- if (status)
+ if (unlikely (status))
return _cairo_surface_set_error (surface, status);
if (_cairo_surface_has_device_transform (surface) &&
@@ -2294,7 +2530,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
&font_options);
}
status = cairo_scaled_font_status (dev_scaled_font);
- if (status) {
+ if (unlikely (status)) {
if (source == &dev_source.base)
_cairo_pattern_fini (&dev_source.base);
@@ -2314,7 +2550,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters, cluster_flags,
- dev_scaled_font);
+ dev_scaled_font, extents);
}
if (status == CAIRO_INT_STATUS_UNSUPPORTED && surface->backend->show_glyphs) {
int remaining_glyphs = num_glyphs;
@@ -2322,7 +2558,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
source,
glyphs, num_glyphs,
dev_scaled_font,
- &remaining_glyphs);
+ &remaining_glyphs, extents);
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (status == CAIRO_INT_STATUS_UNSUPPORTED && remaining_glyphs == 0)
@@ -2336,7 +2572,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
source,
glyphs, num_glyphs,
dev_scaled_font,
- &remaining_glyphs);
+ &remaining_glyphs, extents);
glyphs += num_glyphs - remaining_glyphs;
num_glyphs = remaining_glyphs;
if (status == CAIRO_INT_STATUS_UNSUPPORTED && remaining_glyphs == 0)
@@ -2355,7 +2591,7 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters, cluster_flags,
- dev_scaled_font);
+ dev_scaled_font, extents);
}
}
@@ -2461,7 +2697,7 @@ _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t *dst,
status = _cairo_region_subtract (&clear_region,
&clear_region,
&drawn_region);
- if (status)
+ if (unlikely (status))
goto CLEANUP_REGIONS;
EMPTY:
@@ -2650,7 +2886,7 @@ _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t **pattern,
return CAIRO_STATUS_SUCCESS;
status = _cairo_pattern_init_copy (pattern_copy, *pattern);
- if (status)
+ if (unlikely (status))
return status;
_cairo_pattern_transform (pattern_copy,
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index a50f13b8..cfd9a2d5 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -43,12 +43,13 @@
#include "cairoint.h"
#include "cairo-svg.h"
#include "cairo-analysis-surface-private.h"
-#include "cairo-svg-surface-private.h"
+#include "cairo-image-info-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-output-stream-private.h"
#include "cairo-path-fixed-private.h"
#include "cairo-paginated-private.h"
#include "cairo-scaled-font-subsets-private.h"
+#include "cairo-svg-surface-private.h"
typedef struct cairo_svg_page cairo_svg_page_t;
@@ -284,7 +285,7 @@ cairo_svg_surface_restrict_to_version (cairo_surface_t *abstract_surface,
cairo_status_t status;
status = _extract_svg_surface (abstract_surface, &surface);
- if (status) {
+ if (unlikely (status)) {
status = _cairo_surface_set_error (abstract_surface, status);
return;
}
@@ -346,7 +347,7 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
cairo_status_t status, status_ignored;
surface = malloc (sizeof (cairo_svg_surface_t));
- if (surface == NULL)
+ if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_surface_init (&surface->base, &cairo_svg_surface_backend,
@@ -365,7 +366,7 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
surface->xml_node = _cairo_memory_stream_create ();
status = _cairo_output_stream_get_status (surface->xml_node);
- if (status)
+ if (unlikely (status))
goto CLEANUP;
_cairo_array_init (&surface->page_set, sizeof (cairo_svg_page_t));
@@ -377,7 +378,7 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
"fill:rgb(0,0,0);\"/>\n",
width, height);
status = _cairo_output_stream_get_status (surface->xml_node);
- if (status)
+ if (unlikely (status))
goto CLEANUP;
}
@@ -420,7 +421,7 @@ _cairo_svg_surface_create_for_stream_internal (cairo_output_stream_t *stream,
status = _cairo_svg_document_create (stream,
width, height, version,
&document);
- if (status) {
+ if (unlikely (status)) {
surface = _cairo_surface_create_in_error (status);
/* consume the output stream on behalf of caller */
status = _cairo_output_stream_destroy (stream);
@@ -481,7 +482,7 @@ _cairo_svg_surface_copy_page (void *abstract_surface)
cairo_svg_page_t *page;
page = _cairo_svg_surface_store_page (surface);
- if (page == NULL)
+ if (unlikely (page == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_cairo_memory_stream_copy (page->xml_node, surface->xml_node);
@@ -495,7 +496,7 @@ _cairo_svg_surface_show_page (void *abstract_surface)
{
cairo_svg_surface_t *surface = abstract_surface;
- if (_cairo_svg_surface_store_page (surface) == NULL)
+ if (unlikely (_cairo_svg_surface_store_page (surface) == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_SUCCESS;
@@ -613,7 +614,7 @@ _cairo_svg_surface_emit_path (cairo_output_stream_t *output,
_cairo_svg_path_curve_to,
_cairo_svg_path_close_path,
&info);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (output, "\"");
@@ -634,14 +635,14 @@ _cairo_svg_document_emit_outline_glyph_data (cairo_svg_document_t *document,
CAIRO_SCALED_GLYPH_INFO_METRICS|
CAIRO_SCALED_GLYPH_INFO_PATH,
&scaled_glyph);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (document->xml_node_glyphs,
"<path style=\"stroke:none;\" ");
status = _cairo_svg_surface_emit_path (document->xml_node_glyphs, scaled_glyph->path, NULL);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (document->xml_node_glyphs,
@@ -667,7 +668,7 @@ _cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document,
CAIRO_SCALED_GLYPH_INFO_METRICS|
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
- if (status)
+ if (unlikely (status))
return status;
image = scaled_glyph->surface;
@@ -723,7 +724,7 @@ _cairo_svg_document_emit_glyph (cairo_svg_document_t *document,
status = _cairo_svg_document_emit_bitmap_glyph_data (document,
scaled_font,
scaled_font_glyph_index);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (document->xml_node_glyphs, "</symbol>\n");
@@ -745,7 +746,7 @@ _cairo_svg_document_emit_font_subset (cairo_scaled_font_subset_t *font_subset,
font_subset->scaled_font,
font_subset->glyphs[i],
font_subset->font_id, i);
- if (status)
+ if (unlikely (status))
break;
}
_cairo_scaled_font_thaw_cache (font_subset->scaled_font);
@@ -761,7 +762,7 @@ _cairo_svg_document_emit_font_subsets (cairo_svg_document_t *document)
status = _cairo_scaled_font_subsets_foreach_scaled (document->font_subsets,
_cairo_svg_document_emit_font_subset,
document);
- if (status)
+ if (unlikely (status))
goto FAIL;
status = _cairo_scaled_font_subsets_foreach_user (document->font_subsets,
@@ -976,12 +977,92 @@ base64_write_func (void *closure,
}
static cairo_int_status_t
+_cairo_surface_base64_encode_jpeg (cairo_surface_t *surface,
+ cairo_output_stream_t *output)
+{
+ const unsigned char *mime_data;
+ unsigned int mime_data_length;
+ cairo_image_info_t image_info;
+ base64_write_closure_t info;
+ cairo_status_t status;
+
+ cairo_surface_get_mime_data (surface, CAIRO_MIME_TYPE_JPEG,
+ &mime_data, &mime_data_length);
+ if (mime_data == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_image_info_get_jpeg_info (&image_info, mime_data, mime_data_length);
+ if (unlikely (status))
+ return status;
+
+ _cairo_output_stream_printf (output, "data:image/jpeg;base64,");
+
+ info.output = output;
+ info.in_mem = 0;
+ info.trailing = 0;
+
+ status = base64_write_func (&info, mime_data, mime_data_length);
+ if (unlikely (status))
+ return status;
+
+ if (info.in_mem > 0) {
+ memset (info.src + info.in_mem, 0, 3 - info.in_mem);
+ info.trailing = 3 - info.in_mem;
+ info.in_mem = 3;
+ status = base64_write_func (&info, NULL, 0);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_surface_base64_encode_png (cairo_surface_t *surface,
+ cairo_output_stream_t *output)
+{
+ const unsigned char *mime_data;
+ unsigned int mime_data_length;
+ base64_write_closure_t info;
+ cairo_status_t status;
+
+ cairo_surface_get_mime_data (surface, CAIRO_MIME_TYPE_PNG,
+ &mime_data, &mime_data_length);
+ if (mime_data == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ _cairo_output_stream_printf (output, "data:image/png;base64,");
+
+ info.output = output;
+ info.in_mem = 0;
+ info.trailing = 0;
+
+ status = base64_write_func (&info, mime_data, mime_data_length);
+ if (unlikely (status))
+ return status;
+
+ if (info.in_mem > 0) {
+ memset (info.src + info.in_mem, 0, 3 - info.in_mem);
+ info.trailing = 3 - info.in_mem;
+ info.in_mem = 3;
+ status = base64_write_func (&info, NULL, 0);
+ }
+
+ return status;
+}
+
+static cairo_int_status_t
_cairo_surface_base64_encode (cairo_surface_t *surface,
cairo_output_stream_t *output)
{
cairo_status_t status;
base64_write_closure_t info;
- unsigned int i;
+
+ status = _cairo_surface_base64_encode_jpeg (surface, output);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
+ status = _cairo_surface_base64_encode_png (surface, output);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
info.output = output;
info.in_mem = 0;
@@ -992,12 +1073,11 @@ _cairo_surface_base64_encode (cairo_surface_t *surface,
status = cairo_surface_write_to_png_stream (surface, base64_write_func,
(void *) &info);
- if (status)
+ if (unlikely (status))
return status;
if (info.in_mem > 0) {
- for (i = info.in_mem; i < 3; i++)
- info.src[i] = '\x0';
+ memset (info.src + info.in_mem, 0, 3 - info.in_mem);
info.trailing = 3 - info.in_mem;
info.in_mem = 3;
status = base64_write_func (&info, NULL, 0);
@@ -1046,7 +1126,7 @@ _cairo_svg_surface_emit_composite_image_pattern (cairo_output_stream_t *output
cairo_matrix_t p2u;
status = _cairo_surface_get_extents (pattern->surface, &extents);
- if (status)
+ if (unlikely (status))
return status;
p2u = pattern->base.matrix;
@@ -1134,7 +1214,7 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document,
document->owner->y_fallback_resolution);
status = _cairo_meta_surface_replay (&meta->base, paginated_surface);
- if (status) {
+ if (unlikely (status)) {
cairo_surface_destroy (&meta->base);
cairo_surface_destroy (paginated_surface);
return status;
@@ -1142,7 +1222,7 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document,
cairo_surface_show_page (paginated_surface);
status = cairo_surface_status (paginated_surface);
- if (status) {
+ if (unlikely (status)) {
cairo_surface_destroy (&meta->base);
cairo_surface_destroy (paginated_surface);
return status;
@@ -1151,7 +1231,7 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document,
new_snapshot.meta = meta;
new_snapshot.id = svg_surface->id;
status = _cairo_array_append (&document->meta_snapshots, &new_snapshot);
- if (status) {
+ if (unlikely (status)) {
cairo_surface_destroy (&meta->base);
cairo_surface_destroy (paginated_surface);
return status;
@@ -1188,7 +1268,7 @@ _cairo_svg_surface_emit_meta_surface (cairo_svg_document_t *document,
page_set = &svg_surface->page_set;
if (_cairo_memory_stream_length (contents) > 0) {
- if (_cairo_svg_surface_store_page (svg_surface) == NULL) {
+ if (unlikely (_cairo_svg_surface_store_page (svg_surface) == NULL)) {
cairo_surface_destroy (paginated_surface);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -1241,7 +1321,7 @@ _cairo_svg_surface_emit_composite_meta_pattern (cairo_output_stream_t *output,
meta_surface = (cairo_meta_surface_t *) pattern->surface;
status = _cairo_svg_surface_emit_meta_surface (document, meta_surface, &id);
- if (status)
+ if (unlikely (status))
return status;
if (pattern_id != invalid_pattern_id) {
@@ -1327,7 +1407,7 @@ _cairo_svg_surface_emit_surface_pattern (cairo_svg_surface_t *surface,
status = _cairo_svg_surface_emit_composite_pattern (document->xml_node_defs,
surface, CAIRO_OPERATOR_SOURCE, pattern,
pattern_id, parent_matrix, NULL);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (style,
@@ -1369,7 +1449,7 @@ _cairo_svg_surface_emit_pattern_stops (cairo_output_stream_t *output,
if (emulate_reflect || reverse_stops) {
n_stops = emulate_reflect ? pattern->n_stops * 2 - 2: pattern->n_stops;
stops = _cairo_malloc_ab (n_stops, sizeof (cairo_gradient_stop_t));
- if (stops == NULL)
+ if (unlikely (stops == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
for (i = 0; i < pattern->n_stops; i++) {
@@ -1554,7 +1634,7 @@ _cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t *surface,
status = _cairo_svg_surface_emit_pattern_stops (document->xml_node_defs,
&pattern->base, 0.0,
FALSE, FALSE);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (document->xml_node_defs,
@@ -1732,7 +1812,7 @@ _cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface,
&pattern->base, offset,
reverse_stops,
emulate_reflect);
- if (status)
+ if (unlikely (status))
return status;
if (pattern->base.base.extend == CAIRO_EXTEND_NONE)
@@ -1847,7 +1927,7 @@ _cairo_svg_surface_emit_stroke_style (cairo_output_stream_t *output,
line_join);
status = _cairo_svg_surface_emit_pattern (surface, source, output, TRUE, parent_matrix);
- if (status)
+ if (unlikely (status))
return status;
_cairo_svg_surface_emit_operator_for_style (output, surface, op);
@@ -1890,7 +1970,8 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface,
cairo_matrix_t *stroke_ctm,
cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
- cairo_antialias_t stroke_antialias)
+ cairo_antialias_t stroke_antialias,
+ cairo_rectangle_int_t *extents)
{
cairo_svg_surface_t *surface = abstract_surface;
cairo_status_t status;
@@ -1898,18 +1979,18 @@ _cairo_svg_surface_fill_stroke (void *abstract_surface,
_cairo_output_stream_printf (surface->xml_node, "<path style=\"");
status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, fill_op,
fill_source, fill_rule, stroke_ctm_inverse);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface, stroke_op,
stroke_source, stroke_style, stroke_ctm_inverse);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->xml_node, "\" ");
status = _cairo_svg_surface_emit_path (surface->xml_node, path, stroke_ctm_inverse);
- if (status)
+ if (unlikely (status))
return status;
_cairo_svg_surface_emit_transform (surface->xml_node, " transform", stroke_ctm, NULL);
@@ -1925,7 +2006,8 @@ _cairo_svg_surface_fill (void *abstract_surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
cairo_svg_surface_t *surface = abstract_surface;
cairo_status_t status;
@@ -1937,13 +2019,13 @@ _cairo_svg_surface_fill (void *abstract_surface,
_cairo_output_stream_printf (surface->xml_node, "<path style=\" stroke:none;");
status = _cairo_svg_surface_emit_fill_style (surface->xml_node, surface, op, source, fill_rule, NULL);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->xml_node, "\" ");
status = _cairo_svg_surface_emit_path (surface->xml_node, path, NULL);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->xml_node, "/>\n");
@@ -1997,7 +2079,7 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
surface->width, surface->height);
_cairo_svg_surface_emit_operator_for_style (output, surface, op);
status = _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, NULL);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (output, "stroke:none;\"");
@@ -2013,7 +2095,8 @@ _cairo_svg_surface_emit_paint (cairo_output_stream_t *output,
static cairo_int_status_t
_cairo_svg_surface_paint (void *abstract_surface,
cairo_operator_t op,
- const cairo_pattern_t *source)
+ const cairo_pattern_t *source,
+ cairo_rectangle_int_t *extents)
{
cairo_status_t status;
cairo_svg_surface_t *surface = abstract_surface;
@@ -2033,7 +2116,7 @@ _cairo_svg_surface_paint (void *abstract_surface,
* and an optimization in meta surface. */
if (surface->clip_level == 0 && op == CAIRO_OPERATOR_CLEAR) {
status = _cairo_output_stream_destroy (surface->xml_node);
- if (status) {
+ if (unlikely (status)) {
surface->xml_node = NULL;
return status;
}
@@ -2065,9 +2148,10 @@ _cairo_svg_surface_paint (void *abstract_surface,
static cairo_int_status_t
_cairo_svg_surface_mask (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_pattern_t *mask)
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_rectangle_int_t *extents)
{
cairo_status_t status;
cairo_svg_surface_t *surface = abstract_surface;
@@ -2120,7 +2204,7 @@ _cairo_svg_surface_mask (void *abstract_surface,
mask_id,
discard_filter ? "" : " <g filter=\"url(#alpha)\">\n");
status = _cairo_svg_surface_emit_paint (mask_stream, surface, CAIRO_OPERATOR_OVER, mask, source, NULL);
- if (status) {
+ if (unlikely (status)) {
cairo_status_t ignore = _cairo_output_stream_destroy (mask_stream);
return status;
(void) ignore;
@@ -2133,13 +2217,13 @@ _cairo_svg_surface_mask (void *abstract_surface,
_cairo_memory_stream_copy (mask_stream, document->xml_node_defs);
status = _cairo_output_stream_destroy (mask_stream);
- if (status)
+ if (unlikely (status))
return status;
snprintf (buffer, sizeof buffer, "mask=\"url(#mask%d)\"",
mask_id);
status = _cairo_svg_surface_emit_paint (surface->xml_node, surface, op, source, 0, buffer);
- if (status)
+ if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
@@ -2154,7 +2238,8 @@ _cairo_svg_surface_stroke (void *abstract_dst,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
cairo_svg_surface_t *surface = abstract_dst;
cairo_status_t status;
@@ -2167,13 +2252,13 @@ _cairo_svg_surface_stroke (void *abstract_dst,
_cairo_output_stream_printf (surface->xml_node, "<path style=\"fill:none;");
status = _cairo_svg_surface_emit_stroke_style (surface->xml_node, surface, op,
source, stroke_style, ctm_inverse);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->xml_node, "\" ");
status = _cairo_svg_surface_emit_path (surface->xml_node, path, ctm_inverse);
- if (status)
+ if (unlikely (status))
return status;
_cairo_svg_surface_emit_transform (surface->xml_node, " transform", ctm, NULL);
@@ -2189,7 +2274,8 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs)
+ int *remaining_glyphs,
+ cairo_rectangle_int_t *extents)
{
cairo_svg_surface_t *surface = abstract_surface;
cairo_svg_document_t *document = surface->document;
@@ -2215,7 +2301,7 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
_cairo_output_stream_printf (surface->xml_node, "<g style=\"");
status = _cairo_svg_surface_emit_pattern (surface, pattern,
surface->xml_node, FALSE, NULL);
- if (status)
+ if (unlikely (status))
return status;
_cairo_svg_surface_emit_operator_for_style (surface->xml_node, surface, op);
@@ -2235,7 +2321,7 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
goto FALLBACK;
}
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->xml_node,
@@ -2255,13 +2341,13 @@ FALLBACK:
status = _cairo_scaled_font_glyph_path (scaled_font,(cairo_glyph_t *) glyphs, num_glyphs, &path);
- if (status) {
+ if (unlikely (status)) {
_cairo_path_fixed_fini (&path);
return status;
}
status = _cairo_svg_surface_fill (abstract_surface, op, pattern,
- &path, CAIRO_FILL_RULE_WINDING, 0.0, CAIRO_ANTIALIAS_SUBPIXEL);
+ &path, CAIRO_FILL_RULE_WINDING, 0.0, CAIRO_ANTIALIAS_SUBPIXEL, NULL);
_cairo_path_fixed_fini (&path);
@@ -2293,7 +2379,7 @@ _cairo_svg_surface_intersect_clip_path (void *dst,
" <path ",
document->clip_id);
status = _cairo_svg_surface_emit_path (document->xml_node_defs, path, NULL);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_printf (document->xml_node_defs,
@@ -2336,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 */
@@ -2372,12 +2460,12 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream,
return output_stream->status;
document = malloc (sizeof (cairo_svg_document_t));
- if (document == NULL)
+ if (unlikely (document == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
/* The use of defs for font glyphs imposes no per-subset limit. */
document->font_subsets = _cairo_scaled_font_subsets_create_scaled ();
- if (document->font_subsets == NULL) {
+ if (unlikely (document->font_subsets == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_DOCUMENT;
}
@@ -2399,12 +2487,12 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream,
document->xml_node_defs = _cairo_memory_stream_create ();
status = _cairo_output_stream_get_status (document->xml_node_defs);
- if (status)
+ if (unlikely (status))
goto CLEANUP_NODE_DEFS;
document->xml_node_glyphs = _cairo_memory_stream_create ();
status = _cairo_output_stream_get_status (document->xml_node_glyphs);
- if (status)
+ if (unlikely (status))
goto CLEANUP_NODE_GLYPHS;
document->alpha_filter = FALSE;
@@ -2521,7 +2609,7 @@ _cairo_svg_document_finish (cairo_svg_document_t *document)
surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (document->owner);
if (surface->xml_node != NULL &&
_cairo_memory_stream_length (surface->xml_node) > 0) {
- if (_cairo_svg_surface_store_page (surface) == NULL) {
+ if (unlikely (_cairo_svg_surface_store_page (surface) == NULL)) {
if (status == CAIRO_STATUS_SUCCESS)
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
diff --git a/src/cairo-tor-scan-converter.c b/src/cairo-tor-scan-converter.c
new file mode 100644
index 00000000..20104a7f
--- /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);
+}
diff --git a/src/cairo-traps.c b/src/cairo-traps.c
index 5cf13d9c..2494696c 100644
--- a/src/cairo-traps.c
+++ b/src/cairo-traps.c
@@ -140,7 +140,7 @@ _cairo_traps_grow (cairo_traps_t *traps)
new_size, sizeof (cairo_trapezoid_t));
}
- if (new_traps == NULL) {
+ if (unlikely (new_traps == NULL)) {
traps->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return FALSE;
}
@@ -690,7 +690,7 @@ _cairo_traps_extract_region (const cairo_traps_t *traps,
if (traps->num_traps > ARRAY_LENGTH (stack_boxes)) {
boxes = _cairo_malloc_ab (traps->num_traps, sizeof (cairo_box_int_t));
- if (boxes == NULL)
+ if (unlikely (boxes == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -721,7 +721,7 @@ _cairo_traps_extract_region (const cairo_traps_t *traps,
if (boxes != stack_boxes)
free (boxes);
- if (status)
+ if (unlikely (status))
_cairo_region_fini (region);
return status;
@@ -760,15 +760,15 @@ _cairo_traps_path (const cairo_traps_t *traps,
_sanitize_trap (&trap);
status = _cairo_path_fixed_move_to (path, trap.left.p1.x, trap.top);
- if (status) return status;
+ if (unlikely (status)) return status;
status = _cairo_path_fixed_line_to (path, trap.right.p1.x, trap.top);
- if (status) return status;
+ if (unlikely (status)) return status;
status = _cairo_path_fixed_line_to (path, trap.right.p2.x, trap.bottom);
- if (status) return status;
+ if (unlikely (status)) return status;
status = _cairo_path_fixed_line_to (path, trap.left.p2.x, trap.bottom);
- if (status) return status;
+ if (unlikely (status)) return status;
status = _cairo_path_fixed_close_path (path);
- if (status) return status;
+ if (unlikely (status)) return status;
}
return CAIRO_STATUS_SUCCESS;
diff --git a/src/cairo-truetype-subset.c b/src/cairo-truetype-subset.c
index e8be4b44..4662eaa3 100644
--- a/src/cairo-truetype-subset.c
+++ b/src/cairo-truetype-subset.c
@@ -146,7 +146,7 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
TT_TAG_head, 0,
(unsigned char *) &head,
&size);
- if (status)
+ if (unlikely (status))
return status;
size = sizeof (tt_maxp_t);
@@ -154,7 +154,7 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
TT_TAG_maxp, 0,
(unsigned char *) &maxp,
&size);
- if (status)
+ if (unlikely (status))
return status;
size = sizeof (tt_hhea_t);
@@ -162,7 +162,7 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
TT_TAG_hhea, 0,
(unsigned char *) &hhea,
&size);
- if (status)
+ if (unlikely (status))
return status;
size = 0;
@@ -170,22 +170,22 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
TT_TAG_name, 0,
NULL,
&size);
- if (status)
+ if (unlikely (status))
return status;
- name = malloc(size);
- if (name == NULL)
+ name = malloc (size);
+ if (unlikely (name == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = backend->load_truetype_table (scaled_font_subset->scaled_font,
TT_TAG_name, 0,
(unsigned char *) name,
&size);
- if (status)
+ if (unlikely (status))
goto fail0;
font = malloc (sizeof (cairo_truetype_font_t));
- if (font == NULL) {
+ if (unlikely (font == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail0;
}
@@ -198,17 +198,17 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
font->last_boundary = 0;
_cairo_array_init (&font->output, sizeof (char));
status = _cairo_array_grow_by (&font->output, 4096);
- if (status)
+ if (unlikely (status))
goto fail1;
font->glyphs = calloc (font->num_glyphs_in_face + 1, sizeof (subset_glyph_t));
- if (font->glyphs == NULL) {
+ if (unlikely (font->glyphs == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail1;
}
font->parent_to_subset = calloc (font->num_glyphs_in_face, sizeof (int));
- if (font->parent_to_subset == NULL) {
+ if (unlikely (font->parent_to_subset == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2;
}
@@ -252,7 +252,7 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
if (font->base.base_font == NULL) {
font->base.base_font = malloc (30);
- if (font->base.base_font == NULL) {
+ if (unlikely (font->base.base_font == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3;
}
@@ -270,14 +270,14 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
font->base.base_font[i] = '\0';
font->base.widths = calloc (font->num_glyphs_in_face, sizeof (int));
- if (font->base.widths == NULL) {
+ if (unlikely (font->base.widths == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail4;
}
_cairo_array_init (&font->string_offsets, sizeof (unsigned long));
status = _cairo_array_grow_by (&font->string_offsets, 10);
- if (status)
+ if (unlikely (status))
goto fail5;
font->status = CAIRO_STATUS_SUCCESS;
@@ -328,7 +328,7 @@ cairo_truetype_font_allocate_write_buffer (cairo_truetype_font_t *font,
return font->status;
status = _cairo_array_allocate (&font->output, length, (void **) buffer);
- if (status)
+ if (unlikely (status))
return _cairo_truetype_font_set_error (font, status);
return CAIRO_STATUS_SUCCESS;
@@ -345,7 +345,7 @@ cairo_truetype_font_write (cairo_truetype_font_t *font,
return;
status = _cairo_array_append_multiple (&font->output, data, length);
- if (status)
+ if (unlikely (status))
status = _cairo_truetype_font_set_error (font, status);
}
@@ -391,7 +391,7 @@ cairo_truetype_font_align_output (cairo_truetype_font_t *font,
status = cairo_truetype_font_allocate_write_buffer (font, pad,
&padding);
- if (status)
+ if (unlikely (status))
return status;
memset (padding, 0, pad);
@@ -413,7 +413,7 @@ cairo_truetype_font_check_boundary (cairo_truetype_font_t *font,
{
status = _cairo_array_append (&font->string_offsets,
&font->last_boundary);
- if (status)
+ if (unlikely (status))
return _cairo_truetype_font_set_error (font, status);
font->last_offset = font->last_boundary;
@@ -486,16 +486,16 @@ cairo_truetype_font_write_generic_table (cairo_truetype_font_t *font,
size = 0;
status = font->backend->load_truetype_table(font->scaled_font_subset->scaled_font,
tag, 0, NULL, &size);
- if (status)
+ if (unlikely (status))
return _cairo_truetype_font_set_error (font, status);
status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer);
- if (status)
+ if (unlikely (status))
return _cairo_truetype_font_set_error (font, status);
status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
tag, 0, buffer, &size);
- if (status)
+ if (unlikely (status))
return _cairo_truetype_font_set_error (font, status);
return CAIRO_STATUS_SUCCESS;
@@ -533,7 +533,7 @@ cairo_truetype_font_remap_composite_glyph (cairo_truetype_font_t *font,
flags = be16_to_cpu (composite_glyph->flags);
has_more_components = flags & TT_MORE_COMPONENTS;
status = cairo_truetype_font_use_glyph (font, be16_to_cpu (composite_glyph->index), &index);
- if (status)
+ if (unlikely (status))
return status;
composite_glyph->index = cpu_to_be16 (index);
@@ -575,21 +575,21 @@ cairo_truetype_font_write_glyf_table (cairo_truetype_font_t *font,
status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_head, 0,
(unsigned char*) &header, &size);
- if (status)
+ if (unlikely (status))
return _cairo_truetype_font_set_error (font, status);
-
+
if (be16_to_cpu (header.index_to_loc_format) == 0)
size = sizeof (int16_t) * (font->num_glyphs_in_face + 1);
else
size = sizeof (int32_t) * (font->num_glyphs_in_face + 1);
u.bytes = malloc (size);
- if (u.bytes == NULL)
+ if (unlikely (u.bytes == NULL))
return _cairo_truetype_font_set_error (font, CAIRO_STATUS_NO_MEMORY);
status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_loca, 0, u.bytes, &size);
- if (status)
+ if (unlikely (status))
return _cairo_truetype_font_set_error (font, status);
start_offset = _cairo_array_num_elements (&font->output);
@@ -612,33 +612,33 @@ cairo_truetype_font_write_glyf_table (cairo_truetype_font_t *font,
size = end - begin;
status = cairo_truetype_font_align_output (font, &next);
- if (status)
+ if (unlikely (status))
goto FAIL;
status = cairo_truetype_font_check_boundary (font, next);
- if (status)
+ if (unlikely (status))
goto FAIL;
font->glyphs[i].location = next - start_offset;
status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer);
- if (status)
+ if (unlikely (status))
goto FAIL;
if (size != 0) {
status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_glyf, begin, buffer, &size);
- if (status)
+ if (unlikely (status))
goto FAIL;
status = cairo_truetype_font_remap_composite_glyph (font, buffer, size);
- if (status)
+ if (unlikely (status))
goto FAIL;
}
}
status = cairo_truetype_font_align_output (font, &next);
- if (status)
+ if (unlikely (status))
goto FAIL;
font->glyphs[i].location = next - start_offset;
@@ -664,17 +664,17 @@ cairo_truetype_font_write_head_table (cairo_truetype_font_t *font,
size = 0;
status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
tag, 0, NULL, &size);
- if (status)
+ if (unlikely (status))
return _cairo_truetype_font_set_error (font, status);
font->checksum_index = _cairo_array_num_elements (&font->output) + 8;
status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer);
- if (status)
+ if (unlikely (status))
return _cairo_truetype_font_set_error (font, status);
status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
tag, 0, buffer, &size);
- if (status)
+ if (unlikely (status))
return _cairo_truetype_font_set_error (font, status);
/* set checkSumAdjustment to 0 for table checksum calcualtion */
@@ -695,12 +695,12 @@ cairo_truetype_font_write_hhea_table (cairo_truetype_font_t *font, unsigned long
size = sizeof (tt_hhea_t);
status = cairo_truetype_font_allocate_write_buffer (font, size, (unsigned char **) &hhea);
- if (status)
+ if (unlikely (status))
return _cairo_truetype_font_set_error (font, status);
status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
tag, 0, (unsigned char *) hhea, &size);
- if (status)
+ if (unlikely (status))
return _cairo_truetype_font_set_error (font, status);
hhea->num_hmetrics = cpu_to_be16 ((uint16_t)(font->base.num_glyphs));
@@ -728,7 +728,7 @@ cairo_truetype_font_write_hmtx_table (cairo_truetype_font_t *font,
status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_hhea, 0,
(unsigned char*) &hhea, &size);
- if (status)
+ if (unlikely (status))
return _cairo_truetype_font_set_error (font, status);
num_hmetrics = be16_to_cpu(hhea.num_hmetrics);
@@ -739,7 +739,7 @@ cairo_truetype_font_write_hmtx_table (cairo_truetype_font_t *font,
status = cairo_truetype_font_allocate_write_buffer (font,
long_entry_size,
(unsigned char **) &p);
- if (status)
+ if (unlikely (status))
return _cairo_truetype_font_set_error (font, status);
if (font->glyphs[i].parent_index < num_hmetrics) {
@@ -747,7 +747,7 @@ cairo_truetype_font_write_hmtx_table (cairo_truetype_font_t *font,
TT_TAG_hmtx,
font->glyphs[i].parent_index * long_entry_size,
(unsigned char *) p, &long_entry_size);
- if (status)
+ if (unlikely (status))
return _cairo_truetype_font_set_error (font, status);
}
else
@@ -756,7 +756,7 @@ cairo_truetype_font_write_hmtx_table (cairo_truetype_font_t *font,
TT_TAG_hmtx,
(num_hmetrics - 1) * long_entry_size,
(unsigned char *) p, &short_entry_size);
- if (status)
+ if (unlikely (status))
return _cairo_truetype_font_set_error (font, status);
status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
@@ -764,7 +764,7 @@ cairo_truetype_font_write_hmtx_table (cairo_truetype_font_t *font,
num_hmetrics * long_entry_size +
(font->glyphs[i].parent_index - num_hmetrics) * short_entry_size,
(unsigned char *) (p + 1), &short_entry_size);
- if (status)
+ if (unlikely (status))
return _cairo_truetype_font_set_error (font, status);
}
font->base.widths[i] = be16_to_cpu (p[0]);
@@ -789,7 +789,7 @@ cairo_truetype_font_write_loca_table (cairo_truetype_font_t *font,
status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_head, 0,
(unsigned char*) &header, &size);
- if (status)
+ if (unlikely (status))
return _cairo_truetype_font_set_error (font, status);
if (be16_to_cpu (header.index_to_loc_format) == 0)
@@ -817,12 +817,12 @@ cairo_truetype_font_write_maxp_table (cairo_truetype_font_t *font,
size = sizeof (tt_maxp_t);
status = cairo_truetype_font_allocate_write_buffer (font, size, (unsigned char **) &maxp);
- if (status)
+ if (unlikely (status))
return _cairo_truetype_font_set_error (font, status);
status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
tag, 0, (unsigned char *) maxp, &size);
- if (status)
+ if (unlikely (status))
return _cairo_truetype_font_set_error (font, status);
maxp->num_glyphs = cpu_to_be16 (font->base.num_glyphs);
@@ -862,7 +862,7 @@ cairo_truetype_font_write_offset_table (cairo_truetype_font_t *font)
table_buffer_length = font->num_tables * 16;
status = cairo_truetype_font_allocate_write_buffer (font, table_buffer_length,
&table_buffer);
- if (status)
+ if (unlikely (status))
return _cairo_truetype_font_set_error (font, status);
return CAIRO_STATUS_SUCCESS;
@@ -920,28 +920,28 @@ cairo_truetype_font_generate (cairo_truetype_font_t *font,
return font->status;
status = cairo_truetype_font_write_offset_table (font);
- if (status)
+ if (unlikely (status))
goto FAIL;
status = cairo_truetype_font_align_output (font, &start);
- if (status)
+ if (unlikely (status))
goto FAIL;
end = 0;
for (i = 0; i < font->num_tables; i++) {
status = font->truetype_tables[i].write (font, font->truetype_tables[i].tag);
- if (status)
+ if (unlikely (status))
goto FAIL;
end = _cairo_array_num_elements (&font->output);
status = cairo_truetype_font_align_output (font, &next);
- if (status)
+ if (unlikely (status))
goto FAIL;
cairo_truetype_font_update_entry (font, font->truetype_tables[i].pos,
font->truetype_tables[i].tag, start, end);
status = cairo_truetype_font_check_boundary (font, next);
- if (status)
+ if (unlikely (status))
goto FAIL;
start = next;
@@ -1081,24 +1081,24 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset,
unsigned long num_strings = 0;
status = _cairo_truetype_font_create (font_subset, &font);
- if (status)
+ if (unlikely (status))
return status;
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
unsigned short parent_glyph = font->scaled_font_subset->glyphs[i];
status = cairo_truetype_font_use_glyph (font, parent_glyph, &parent_glyph);
- if (status)
+ if (unlikely (status))
goto fail1;
}
cairo_truetype_font_create_truetype_table_list (font);
status = cairo_truetype_font_generate (font, &data, &length,
&string_offsets, &num_strings);
- if (status)
+ if (unlikely (status))
goto fail1;
truetype_subset->base_font = strdup (font->base.base_font);
- if (truetype_subset->base_font == NULL) {
+ if (unlikely (truetype_subset->base_font == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail1;
}
@@ -1108,7 +1108,7 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset,
* font_subset->num_glyphs are omitted. */
truetype_subset->widths = calloc (sizeof (double),
font->scaled_font_subset->num_glyphs);
- if (truetype_subset->widths == NULL) {
+ if (unlikely (truetype_subset->widths == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2;
}
@@ -1124,7 +1124,7 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset,
if (length) {
truetype_subset->data = malloc (length);
- if (truetype_subset->data == NULL) {
+ if (unlikely (truetype_subset->data == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3;
}
@@ -1137,7 +1137,7 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset,
if (num_strings) {
offsets_length = num_strings * sizeof (unsigned long);
truetype_subset->string_offsets = malloc (offsets_length);
- if (truetype_subset->string_offsets == NULL) {
+ if (unlikely (truetype_subset->string_offsets == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail4;
}
@@ -1199,7 +1199,7 @@ _cairo_truetype_reverse_cmap (cairo_scaled_font_t *scaled_font,
TT_TAG_cmap, table_offset,
(unsigned char *) &buf,
&size);
- if (status)
+ if (unlikely (status))
return status;
/* All table formats have the same first two words */
@@ -1209,14 +1209,14 @@ _cairo_truetype_reverse_cmap (cairo_scaled_font_t *scaled_font,
size = be16_to_cpu (map->length);
map = malloc (size);
- if (map == NULL)
+ if (unlikely (map == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = backend->load_truetype_table (scaled_font,
TT_TAG_cmap, table_offset,
(unsigned char *) map,
&size);
- if (status)
+ if (unlikely (status))
goto fail;
num_segments = be16_to_cpu (map->segCountX2)/2;
@@ -1299,21 +1299,21 @@ _cairo_truetype_index_to_ucs4 (cairo_scaled_font_t *scaled_font,
TT_TAG_cmap, 0,
(unsigned char *) &buf,
&size);
- if (status)
+ if (unlikely (status))
return status;
cmap = (tt_cmap_t *) buf;
num_tables = be16_to_cpu (cmap->num_tables);
size = 4 + num_tables*sizeof(tt_cmap_index_t);
cmap = _cairo_malloc_ab_plus_c (num_tables, sizeof (tt_cmap_index_t), 4);
- if (cmap == NULL)
+ if (unlikely (cmap == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = backend->load_truetype_table (scaled_font,
TT_TAG_cmap, 0,
(unsigned char *) cmap,
&size);
- if (status)
+ if (unlikely (status))
goto cleanup;
/* Find a table with Unicode mapping */
diff --git a/src/cairo-type1-fallback.c b/src/cairo-type1-fallback.c
index 83ddc448..91c00542 100644
--- a/src/cairo-type1-fallback.c
+++ b/src/cairo-type1-fallback.c
@@ -85,12 +85,11 @@ cairo_type1_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
cairo_status_t status;
font = calloc (1, sizeof (cairo_type1_font_t));
- if (font == NULL)
+ if (unlikely (font == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- font->widths = calloc (scaled_font_subset->num_glyphs,
- sizeof (int));
- if (font->widths == NULL) {
+ font->widths = calloc (scaled_font_subset->num_glyphs, sizeof (int));
+ if (unlikely (font->widths == NULL)) {
free (font);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -112,7 +111,7 @@ cairo_type1_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
&ctm,
&font_options);
status = font->type1_scaled_font->status;
- if (status)
+ if (unlikely (status))
goto fail;
_cairo_array_init (&font->contents, sizeof (unsigned char));
@@ -227,7 +226,7 @@ _charstring_move_to (void *closure,
cairo_status_t status;
status = _cairo_array_grow_by (path_info->data, 12);
- if (status)
+ if (unlikely (status))
return status;
dx = _cairo_fixed_integer_part (point->x) - path_info->current_x;
@@ -251,7 +250,7 @@ _charstring_line_to (void *closure,
cairo_status_t status;
status = _cairo_array_grow_by (path_info->data, 12);
- if (status)
+ if (unlikely (status))
return status;
dx = _cairo_fixed_integer_part (point->x) - path_info->current_x;
@@ -277,7 +276,7 @@ _charstring_curve_to (void *closure,
cairo_status_t status;
status = _cairo_array_grow_by (path_info->data, 32);
- if (status)
+ if (unlikely (status))
return status;
dx1 = _cairo_fixed_integer_part (point1->x) - path_info->current_x;
@@ -309,7 +308,7 @@ _charstring_close_path (void *closure)
return CAIRO_STATUS_SUCCESS;
status = _cairo_array_grow_by (path_info->data, 2);
- if (status)
+ if (unlikely (status))
return status;
charstring_encode_command (path_info->data, CHARSTRING_closepath);
@@ -363,7 +362,7 @@ cairo_type1_font_create_charstring (cairo_type1_font_t *font,
CAIRO_SCALED_GLYPH_INFO_METRICS,
&scaled_glyph);
}
- if (status)
+ if (unlikely (status))
return status;
metrics = &scaled_glyph->metrics;
@@ -385,7 +384,7 @@ cairo_type1_font_create_charstring (cairo_type1_font_t *font,
font->widths[subset_index] = metrics->x_advance;
status = _cairo_array_grow_by (data, 30);
- if (status)
+ if (unlikely (status))
return status;
if (type == CAIRO_CHARSTRING_TYPE1) {
@@ -413,12 +412,12 @@ cairo_type1_font_create_charstring (cairo_type1_font_t *font,
_charstring_curve_to,
_charstring_close_path,
&path_info);
- if (status)
+ if (unlikely (status))
return status;
}
status = _cairo_array_grow_by (data, 1);
- if (status)
+ if (unlikely (status))
return status;
charstring_encode_command (path_info.data, CHARSTRING_endchar);
@@ -437,7 +436,7 @@ cairo_type1_font_write_charstrings (cairo_type1_font_t *font,
_cairo_array_init (&data, sizeof (unsigned char));
status = _cairo_array_grow_by (&data, 1024);
- if (status)
+ if (unlikely (status))
goto fail;
_cairo_output_stream_printf (encrypted_output,
@@ -449,14 +448,14 @@ cairo_type1_font_write_charstrings (cairo_type1_font_t *font,
_cairo_array_truncate (&data, 0);
/* four "random" bytes required by encryption algorithm */
status = _cairo_array_append_multiple (&data, zeros, 4);
- if (status)
+ if (unlikely (status))
goto fail;
status = cairo_type1_font_create_charstring (font, i,
font->scaled_font_subset->glyphs[i],
CAIRO_CHARSTRING_TYPE1,
&data);
- if (status)
+ if (unlikely (status))
goto fail;
charstring_encrypt (&data);
@@ -590,7 +589,7 @@ cairo_type1_font_write_private_dict (cairo_type1_font_t *font,
_cairo_output_stream_printf (encrypted_output,
" dup /Private 9 dict dup begin\n"
"/RD {string currentfile exch readstring pop}"
- " executeonly def\n"
+ " bind executeonly def\n"
"/ND {noaccess def} executeonly def\n"
"/NP {noaccess put} executeonly def\n"
"/BlueValues [] def\n"
@@ -599,7 +598,7 @@ cairo_type1_font_write_private_dict (cairo_type1_font_t *font,
"/password 5839 def\n");
status = cairo_type1_font_write_charstrings (font, encrypted_output);
- if (status)
+ if (unlikely (status))
goto fail;
_cairo_output_stream_printf (encrypted_output,
@@ -651,7 +650,7 @@ cairo_type1_font_write (cairo_type1_font_t *font,
font->header_size = _cairo_output_stream_get_position (font->output);
status = cairo_type1_font_write_private_dict (font, name);
- if (status)
+ if (unlikely (status))
return status;
font->data_size = _cairo_output_stream_get_position (font->output) -
@@ -671,7 +670,7 @@ cairo_type1_font_generate (cairo_type1_font_t *font, const char *name)
cairo_int_status_t status;
status = _cairo_array_grow_by (&font->contents, 4096);
- if (status)
+ if (unlikely (status))
return status;
font->output = _cairo_output_stream_create (cairo_type1_write_stream, NULL, font);
@@ -679,7 +678,7 @@ cairo_type1_font_generate (cairo_type1_font_t *font, const char *name)
return _cairo_output_stream_destroy (font->output);
status = cairo_type1_font_write (font, name);
- if (status)
+ if (unlikely (status))
return status;
font->data = _cairo_array_index (&font->contents, 0);
@@ -714,21 +713,21 @@ _cairo_type1_fallback_init_internal (cairo_type1_subset_t *type1_subset,
unsigned int i, len;
status = cairo_type1_font_create (scaled_font_subset, &font, hex_encode);
- if (status)
+ if (unlikely (status))
return status;
status = cairo_type1_font_generate (font, name);
- if (status)
+ if (unlikely (status))
goto fail1;
type1_subset->base_font = strdup (name);
- if (type1_subset->base_font == NULL) {
+ if (unlikely (type1_subset->base_font == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail1;
}
type1_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs);
- if (type1_subset->widths == NULL) {
+ if (unlikely (type1_subset->widths == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2;
}
@@ -745,7 +744,7 @@ _cairo_type1_fallback_init_internal (cairo_type1_subset_t *type1_subset,
length = font->header_size + font->data_size +
font->trailer_size;
type1_subset->data = malloc (length);
- if (type1_subset->data == NULL) {
+ if (unlikely (type1_subset->data == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3;
}
@@ -816,13 +815,13 @@ _cairo_type2_charstrings_init (cairo_type2_charstrings_t *type2_subset,
cairo_array_t charstring;
status = cairo_type1_font_create (scaled_font_subset, &font, FALSE);
- if (status)
+ if (unlikely (status))
return status;
_cairo_array_init (&type2_subset->charstrings, sizeof (cairo_array_t));
type2_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs);
- if (type2_subset->widths == NULL) {
+ if (unlikely (type2_subset->widths == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail1;
}
@@ -831,18 +830,18 @@ _cairo_type2_charstrings_init (cairo_type2_charstrings_t *type2_subset,
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
_cairo_array_init (&charstring, sizeof (unsigned char));
status = _cairo_array_grow_by (&charstring, 32);
- if (status)
+ if (unlikely (status))
goto fail2;
status = cairo_type1_font_create_charstring (font, i,
font->scaled_font_subset->glyphs[i],
CAIRO_CHARSTRING_TYPE2,
&charstring);
- if (status)
+ if (unlikely (status))
goto fail2;
status = _cairo_array_append (&type2_subset->charstrings, &charstring);
- if (status)
+ if (unlikely (status))
goto fail2;
}
_cairo_scaled_font_thaw_cache (font->type1_scaled_font);
diff --git a/src/cairo-type1-subset.c b/src/cairo-type1-subset.c
index ddc4ce76..fe74dc6c 100644
--- a/src/cairo-type1-subset.c
+++ b/src/cairo-type1-subset.c
@@ -126,7 +126,7 @@ _cairo_type1_font_subset_init (cairo_type1_font_subset_t *font,
ft_unscaled_font = (cairo_ft_unscaled_font_t *) unscaled_font;
face = _cairo_ft_unscaled_font_lock_face (ft_unscaled_font);
- if (face == NULL)
+ if (unlikely (face == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (FT_Get_PS_Font_Info(face, &font_info) != 0) {
@@ -154,7 +154,7 @@ _cairo_type1_font_subset_init (cairo_type1_font_subset_t *font,
if (face->family_name) {
font->base.base_font = strdup (face->family_name);
- if (font->base.base_font == NULL) {
+ if (unlikely (font->base.base_font == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2;
}
@@ -167,7 +167,7 @@ _cairo_type1_font_subset_init (cairo_type1_font_subset_t *font,
}
font->glyphs = calloc (face->num_glyphs, sizeof font->glyphs[0]);
- if (font->glyphs == NULL) {
+ if (unlikely (font->glyphs == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3;
}
@@ -467,7 +467,7 @@ cairo_type1_font_subset_decrypt_eexec_segment (cairo_type1_font_subset_t *font)
end = (unsigned char *) in + font->eexec_segment_size;
font->cleartext = malloc (font->eexec_segment_size);
- if (font->cleartext == NULL)
+ if (unlikely (font->cleartext == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
out = font->cleartext;
@@ -553,21 +553,27 @@ cairo_type1_font_subset_get_glyph_names_and_widths (cairo_type1_font_subset_t *f
error = FT_Load_Glyph (font->face, i,
FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING |
FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM);
- if (error != 0) {
- printf ("could not load glyph %d\n", i);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ if (error != FT_Err_Ok) {
+ /* propagate fatal errors from FreeType */
+ if (error == FT_Err_Out_Of_Memory)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
font->glyphs[i].width = font->face->glyph->metrics.horiAdvance;
error = FT_Get_Glyph_Name(font->face, i, buffer, sizeof buffer);
- if (error != 0) {
- printf ("could not get glyph name for glyph %d\n", i);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ if (error != FT_Err_Ok) {
+ /* propagate fatal errors from FreeType */
+ if (error == FT_Err_Out_Of_Memory)
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
font->glyphs[i].name = strdup (buffer);
- if (font->glyphs[i].name == NULL)
+ if (unlikely (font->glyphs[i].name == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -832,7 +838,7 @@ cairo_type1_font_subset_look_for_seac(cairo_type1_font_subset_t *font,
int command;
charstring = malloc (encrypted_charstring_length);
- if (charstring == NULL)
+ if (unlikely (charstring == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
cairo_type1_font_subset_decrypt_charstring ((const unsigned char *)
@@ -860,11 +866,11 @@ cairo_type1_font_subset_look_for_seac(cairo_type1_font_subset_t *font,
* make sure those glyphs are present in the subset
* under their standard names. */
status = use_standard_encoding_glyph (font, stack[3]);
- if (status)
+ if (unlikely (status))
return status;
status = use_standard_encoding_glyph (font, stack[4]);
- if (status)
+ if (unlikely (status))
return status;
sp = 0;
@@ -900,18 +906,18 @@ write_used_glyphs (cairo_type1_font_subset_t *font,
"/%.*s %d %s ",
name_length, name, charstring_length, font->rd);
status = cairo_type1_font_subset_write_encrypted (font, buffer, length);
- if (status)
+ if (unlikely (status))
return status;
status = cairo_type1_font_subset_write_encrypted (font,
charstring,
charstring_length);
- if (status)
+ if (unlikely (status))
return status;
length = snprintf (buffer, sizeof buffer, "%s\n", font->nd);
status = cairo_type1_font_subset_write_encrypted (font, buffer, length);
- if (status)
+ if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
@@ -977,7 +983,7 @@ cairo_type1_font_subset_for_each_glyph (cairo_type1_font_subset_t *font,
cairo_status_t status = func (font,
name, name_length,
charstring, charstring_length);
- if (status)
+ if (unlikely (status))
return status;
}
}
@@ -1034,7 +1040,7 @@ cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font,
dict_start = p;
status = cairo_type1_font_subset_get_glyph_names_and_widths (font);
- if (status)
+ if (unlikely (status))
return status;
/* Now that we have the private dictionary broken down in
@@ -1046,7 +1052,7 @@ cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font,
font->cleartext_end,
cairo_type1_font_subset_look_for_seac,
&p);
- if (status)
+ if (unlikely (status))
return status;
closefile_token = find_token (p, font->cleartext_end, "closefile");
@@ -1054,13 +1060,13 @@ cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font,
return CAIRO_INT_STATUS_UNSUPPORTED;
status = cairo_type1_font_subset_get_glyph_names_and_widths (font);
- if (status)
+ if (unlikely (status))
return status;
/* We're ready to start outputting. First write the header,
* i.e. the public part of the font dict.*/
status = cairo_type1_font_subset_write_header (font, name);
- if (status)
+ if (unlikely (status))
return status;
font->base.header_size = _cairo_output_stream_get_position (font->output);
@@ -1070,21 +1076,21 @@ cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font,
* to the /CharStrings token. */
status = cairo_type1_font_subset_write_encrypted (font, font->cleartext,
charstrings - font->cleartext);
- if (status)
+ if (unlikely (status))
return status;
/* Write out new charstring count */
length = snprintf (buffer, sizeof buffer,
"/CharStrings %d", font->num_glyphs);
status = cairo_type1_font_subset_write_encrypted (font, buffer, length);
- if (status)
+ if (unlikely (status))
return status;
/* Write out text between the charstring count and the first
* charstring definition */
status = cairo_type1_font_subset_write_encrypted (font, glyph_count_end,
dict_start - glyph_count_end);
- if (status)
+ if (unlikely (status))
return status;
/* Write out the charstring definitions for each of the glyphs in
@@ -1094,14 +1100,14 @@ cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font,
font->cleartext_end,
write_used_glyphs,
&p);
- if (status)
+ if (unlikely (status))
return status;
/* Output what's left between the end of the glyph definitions and
* the end of the private dict to the output. */
status = cairo_type1_font_subset_write_encrypted (font, p,
closefile_token - p + strlen ("closefile") + 1);
- if (status)
+ if (unlikely (status))
return status;
_cairo_output_stream_write (font->output, "\n", 1);
@@ -1152,11 +1158,11 @@ cairo_type1_font_subset_write (cairo_type1_font_subset_t *font,
cairo_status_t status;
status = cairo_type1_font_subset_find_segments (font);
- if (status)
+ if (unlikely (status))
return status;
status = cairo_type1_font_subset_decrypt_eexec_segment (font);
- if (status)
+ if (unlikely (status))
return status;
/* Determine which glyph definition delimiters to use. */
@@ -1175,14 +1181,14 @@ cairo_type1_font_subset_write (cairo_type1_font_subset_t *font,
font->hex_column = 0;
status = cairo_type1_font_subset_write_private_dict (font, name);
- if (status)
+ if (unlikely (status))
return status;
font->base.data_size = _cairo_output_stream_get_position (font->output) -
font->base.header_size;
status = cairo_type1_font_subset_write_trailer (font);
- if (status)
+ if (unlikely (status))
return status;
font->base.trailer_size =
@@ -1204,12 +1210,12 @@ cairo_type1_font_subset_generate (void *abstract_font,
ft_unscaled_font = (cairo_ft_unscaled_font_t *) font->base.unscaled_font;
font->face = _cairo_ft_unscaled_font_lock_face (ft_unscaled_font);
- if (font->face == NULL)
+ if (unlikely (font->face == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font->type1_length = font->face->stream->size;
font->type1_data = malloc (font->type1_length);
- if (font->type1_data == NULL) {
+ if (unlikely (font->type1_data == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail;
}
@@ -1233,7 +1239,7 @@ cairo_type1_font_subset_generate (void *abstract_font,
}
status = _cairo_array_grow_by (&font->contents, 4096);
- if (status)
+ if (unlikely (status))
goto fail;
font->output = _cairo_output_stream_create (type1_font_write, NULL, font);
@@ -1243,7 +1249,7 @@ cairo_type1_font_subset_generate (void *abstract_font,
}
status = cairo_type1_font_subset_write (font, name);
- if (status)
+ if (unlikely (status))
goto fail;
font->base.data = _cairo_array_index (&font->contents, 0);
@@ -1300,7 +1306,7 @@ _cairo_type1_subset_init (cairo_type1_subset_t *type1_subset,
unscaled_font = _cairo_ft_scaled_font_get_unscaled_font (scaled_font_subset->scaled_font);
status = _cairo_type1_font_subset_init (&font, unscaled_font, hex_encode);
- if (status)
+ if (unlikely (status))
return status;
for (i = 0; i < scaled_font_subset->num_glyphs; i++) {
@@ -1309,7 +1315,7 @@ _cairo_type1_subset_init (cairo_type1_subset_t *type1_subset,
}
status = cairo_type1_font_subset_generate (&font, name);
- if (status)
+ if (unlikely (status))
goto fail1;
if (font.base.base_font) {
@@ -1319,11 +1325,11 @@ _cairo_type1_subset_init (cairo_type1_subset_t *type1_subset,
scaled_font_subset->font_id, scaled_font_subset->subset_id);
type1_subset->base_font = strdup (buf);
}
- if (type1_subset->base_font == NULL)
+ if (unlikely (type1_subset->base_font == NULL))
goto fail1;
type1_subset->widths = calloc (sizeof (int), font.num_glyphs);
- if (type1_subset->widths == NULL)
+ if (unlikely (type1_subset->widths == NULL))
goto fail2;
for (i = 0; i < font.base.num_glyphs; i++) {
if (font.glyphs[i].subset_index < 0)
@@ -1343,7 +1349,7 @@ _cairo_type1_subset_init (cairo_type1_subset_t *type1_subset,
font.base.data_size +
font.base.trailer_size;
type1_subset->data = malloc (length);
- if (type1_subset->data == NULL)
+ if (unlikely (type1_subset->data == NULL))
goto fail3;
memcpy (type1_subset->data,
diff --git a/src/cairo-type3-glyph-surface.c b/src/cairo-type3-glyph-surface.c
index 58048aca..b3a48313 100644
--- a/src/cairo-type3-glyph-surface.c
+++ b/src/cairo-type3-glyph-surface.c
@@ -55,7 +55,7 @@ _cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font,
cairo_matrix_t invert_y_axis;
surface = malloc (sizeof (cairo_type3_glyph_surface_t));
- if (surface == NULL)
+ if (unlikely (surface == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_surface_init (&surface->base, &cairo_type3_glyph_surface_backend,
@@ -96,7 +96,7 @@ _cairo_type3_glyph_surface_emit_image (cairo_type3_glyph_surface_t *surface,
} else {
image_mask = _cairo_image_surface_clone (image, CAIRO_FORMAT_A1);
status = cairo_surface_status (&image->base);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -182,7 +182,8 @@ _cairo_type3_glyph_surface_intersect_clip_path (void *abstract_surface,
static cairo_int_status_t
_cairo_type3_glyph_surface_paint (void *abstract_surface,
cairo_operator_t op,
- const cairo_pattern_t *source)
+ const cairo_pattern_t *source,
+ cairo_rectangle_int_t *extents)
{
cairo_type3_glyph_surface_t *surface = abstract_surface;
const cairo_surface_pattern_t *pattern;
@@ -195,7 +196,7 @@ _cairo_type3_glyph_surface_paint (void *abstract_surface,
pattern = (const cairo_surface_pattern_t *) source;
status = _cairo_surface_acquire_source_image (pattern->surface, &image, &image_extra);
- if (status)
+ if (unlikely (status))
goto fail;
status = _cairo_type3_glyph_surface_emit_image_pattern (surface,
@@ -212,9 +213,10 @@ static cairo_int_status_t
_cairo_type3_glyph_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- const cairo_pattern_t *mask)
+ const cairo_pattern_t *mask,
+ cairo_rectangle_int_t *extents)
{
- return _cairo_type3_glyph_surface_paint (abstract_surface, op, mask);
+ return _cairo_type3_glyph_surface_paint (abstract_surface, op, mask, extents);
}
static cairo_int_status_t
@@ -226,7 +228,8 @@ _cairo_type3_glyph_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
cairo_type3_glyph_surface_t *surface = abstract_surface;
@@ -244,7 +247,8 @@ _cairo_type3_glyph_surface_fill (void *abstract_surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
cairo_type3_glyph_surface_t *surface = abstract_surface;
cairo_int_status_t status;
@@ -263,7 +267,8 @@ _cairo_type3_glyph_surface_show_glyphs (void *abstract_surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs)
+ int *remaining_glyphs,
+ cairo_rectangle_int_t *extents)
{
cairo_type3_glyph_surface_t *surface = abstract_surface;
cairo_int_status_t status;
@@ -277,7 +282,7 @@ _cairo_type3_glyph_surface_show_glyphs (void *abstract_surface,
/* We require the matrix to be invertable. */
ctm_inverse = scaled_font->ctm;
status = cairo_matrix_invert (&ctm_inverse);
- if (status)
+ if (unlikely (status))
return CAIRO_INT_STATUS_IMAGE_FALLBACK;
cairo_matrix_multiply (&new_ctm, &scaled_font->ctm, &ctm_inverse);
@@ -310,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 */
@@ -352,7 +359,7 @@ _cairo_type3_glyph_surface_emit_fallback_image (cairo_type3_glyph_surface_t *sur
CAIRO_SCALED_GLYPH_INFO_METRICS |
CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph);
- if (status)
+ if (unlikely (status))
return status;
image = scaled_glyph->surface;
@@ -414,7 +421,7 @@ _cairo_type3_glyph_surface_analyze_glyph (void *abstract_surface,
status = _cairo_meta_surface_replay (scaled_glyph->meta_surface,
&surface->base);
- if (status)
+ if (unlikely (status))
goto cleanup;
status2 = _cairo_pdf_operators_flush (&surface->pdf_operators);
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index 12e1a20e..d8d5a2c0 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -41,8 +41,10 @@
#include "cairo.h"
#include "cairo-fixed-type-private.h"
+#include "cairo-reference-count-private.h"
typedef struct _cairo_array cairo_array_t;
+typedef struct _cairo_backend cairo_backend_t;
typedef struct _cairo_cache cairo_cache_t;
typedef struct _cairo_clip cairo_clip_t;
typedef struct _cairo_clip_path cairo_clip_path_t;
@@ -52,6 +54,7 @@ typedef struct _cairo_gstate cairo_gstate_t;
typedef struct _cairo_hash_entry cairo_hash_entry_t;
typedef struct _cairo_hash_table cairo_hash_table_t;
typedef struct _cairo_image_surface cairo_image_surface_t;
+typedef struct _cairo_mime_data cairo_mime_data_t;
typedef struct _cairo_output_stream cairo_output_stream_t;
typedef struct _cairo_paginated_surface_backend cairo_paginated_surface_backend_t;
typedef struct _cairo_path_fixed cairo_path_fixed_t;
@@ -249,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
@@ -262,9 +289,7 @@ typedef enum _cairo_clip_mode {
typedef struct _cairo_edge {
cairo_line_t edge;
- int clockWise;
-
- cairo_fixed_t current_x;
+ int dir;
} cairo_edge_t;
typedef struct _cairo_polygon {
@@ -284,15 +309,16 @@ typedef struct _cairo_spline_knots {
cairo_point_t a, b, c, d;
} cairo_spline_knots_t;
typedef struct _cairo_spline {
+ void (*add_point_func) (void *, const cairo_point_t *);
+ void *closure;
+
cairo_spline_knots_t knots;
cairo_slope_t initial_slope;
cairo_slope_t final_slope;
- int num_points;
- int points_size;
- cairo_point_t *points;
- cairo_point_t points_embedded[64];
+ cairo_bool_t has_point;
+ cairo_point_t last_point;
} cairo_spline_t;
typedef struct _cairo_pen_vertex {
@@ -342,4 +368,12 @@ typedef enum _cairo_image_transparency {
CAIRO_IMAGE_UNKNOWN
} cairo_image_transparency_t;
+struct _cairo_mime_data {
+ cairo_reference_count_t ref_count;
+ unsigned char *data;
+ unsigned int length;
+ cairo_destroy_func_t destroy;
+ void *closure;
+};
+
#endif /* CAIRO_TYPES_PRIVATE_H */
diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c
index c272966a..6670b536 100644
--- a/src/cairo-user-font.c
+++ b/src/cairo-user-font.c
@@ -127,7 +127,7 @@ _cairo_user_scaled_glyph_init (void *abstract_font,
cairo_destroy (cr);
- if (status) {
+ if (unlikely (status)) {
cairo_surface_destroy (meta_surface);
return status;
}
@@ -152,7 +152,7 @@ _cairo_user_scaled_glyph_init (void *abstract_font,
analysis_surface = _cairo_analysis_surface_create (null_surface, -1, -1);
cairo_surface_destroy (null_surface);
status = analysis_surface->status;
- if (status)
+ if (unlikely (status))
return status;
_cairo_analysis_surface_set_ctm (analysis_surface,
@@ -162,7 +162,7 @@ _cairo_user_scaled_glyph_init (void *abstract_font,
_cairo_analysis_surface_get_bounding_box (analysis_surface, &bbox);
cairo_surface_destroy (analysis_surface);
- if (status)
+ if (unlikely (status))
return status;
_cairo_box_to_doubles (&bbox, &x1, &y1, &x2, &y2);
@@ -215,7 +215,7 @@ _cairo_user_scaled_glyph_init (void *abstract_font,
- _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y));
status = _cairo_meta_surface_replay (meta_surface, surface);
- if (status) {
+ if (unlikely (status)) {
cairo_surface_destroy(surface);
return status;
}
@@ -232,7 +232,7 @@ _cairo_user_scaled_glyph_init (void *abstract_font,
status = _cairo_meta_surface_get_path (meta_surface, path);
- if (status) {
+ if (unlikely (status)) {
_cairo_path_fixed_destroy (path);
return status;
}
@@ -355,7 +355,7 @@ _cairo_user_scaled_font_get_implementation (cairo_toy_font_face_t *toy_face,
face,
(cairo_destroy_func_t) cairo_font_face_destroy);
- if (status) {
+ if (unlikely (status)) {
cairo_font_face_destroy (face);
return status;
}
@@ -376,7 +376,7 @@ _cairo_user_scaled_font_create_toy (cairo_toy_font_face_t *toy_face,
cairo_status_t status;
status = _cairo_user_scaled_font_get_implementation (toy_face, &face);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_user_font_face_scaled_font_create (face,
@@ -384,7 +384,7 @@ _cairo_user_scaled_font_create_toy (cairo_toy_font_face_t *toy_face,
ctm,
font_options,
font);
- if (status)
+ if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
@@ -420,7 +420,7 @@ _cairo_user_font_face_scaled_font_create (void *abstract_
font_face->immutable = TRUE;
user_scaled_font = malloc (sizeof (cairo_user_scaled_font_t));
- if (user_scaled_font == NULL)
+ if (unlikely (user_scaled_font == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_scaled_font_init (&user_scaled_font->base,
@@ -428,7 +428,7 @@ _cairo_user_font_face_scaled_font_create (void *abstract_
font_matrix, ctm, options,
&_cairo_user_scaled_font_backend);
- if (status) {
+ if (unlikely (status)) {
free (user_scaled_font);
return status;
}
diff --git a/src/cairo-win32-printing-surface.c b/src/cairo-win32-printing-surface.c
index 553ef406..94927aeb 100644
--- a/src/cairo-win32-printing-surface.c
+++ b/src/cairo-win32-printing-surface.c
@@ -1,7 +1,7 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* Cairo - a vector graphics library with display and print output
*
- * Copyright © 2007 Adrian Johnson
+ * Copyright © 2007, 2008 Adrian Johnson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -52,6 +52,7 @@
#include "cairo-win32-private.h"
#include "cairo-meta-surface-private.h"
#include "cairo-scaled-font-subsets-private.h"
+#include "cairo-image-info-private.h"
#include <windows.h>
@@ -75,6 +76,14 @@
# define GRADIENT_FILL_RECT_H 0x00
#endif
+#if !defined(CHECKJPEGFORMAT)
+# define CHECKJPEGFORMAT 0x1017
+#endif
+
+#if !defined(CHECKPNGFORMAT)
+# define CHECKPNGFORMAT 0x1018
+#endif
+
#define PELS_72DPI ((LONG)(72. / 0.0254))
static const cairo_surface_backend_t cairo_win32_printing_surface_backend;
@@ -99,6 +108,20 @@ _cairo_win32_printing_surface_init_ps_mode (cairo_win32_surface_t *surface)
surface->flags |= CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT;
}
+static void
+_cairo_win32_printing_surface_init_image_support (cairo_win32_surface_t *surface)
+{
+ DWORD word;
+
+ word = CHECKJPEGFORMAT;
+ if (ExtEscape(surface->dc, QUERYESCSUPPORT, sizeof(word), (char *)&word, 0, (char *)NULL) > 0)
+ surface->flags |= CAIRO_WIN32_SURFACE_CAN_CHECK_JPEG;
+
+ word = CHECKPNGFORMAT;
+ if (ExtEscape(surface->dc, QUERYESCSUPPORT, sizeof(word), (char *)&word, 0, (char *)NULL) > 0)
+ surface->flags |= CAIRO_WIN32_SURFACE_CAN_CHECK_PNG;
+}
+
static cairo_int_status_t
analyze_surface_pattern_transparency (cairo_surface_pattern_t *pattern)
{
@@ -486,6 +509,83 @@ _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t *surfa
return status;
}
+static cairo_int_status_t
+_cairo_win32_printing_surface_check_jpeg (cairo_win32_surface_t *surface,
+ cairo_surface_t *source,
+ const unsigned char **data,
+ unsigned int *length,
+ cairo_image_info_t *info)
+{
+ const unsigned char *mime_data;
+ unsigned int mime_data_length;
+ cairo_int_status_t status;
+ DWORD result;
+
+ if (!(surface->flags & CAIRO_WIN32_SURFACE_CAN_CHECK_JPEG))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG,
+ &mime_data, &mime_data_length);
+ if (mime_data == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_image_info_get_jpeg_info (info, mime_data, mime_data_length);
+ if (status)
+ return status;
+
+ result = 0;
+ if (ExtEscape(surface->dc, CHECKJPEGFORMAT, mime_data_length, (char *) mime_data,
+ sizeof(result), (char *) &result) <= 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (result != 1)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ *data = mime_data;
+ *length = mime_data_length;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_cairo_win32_printing_surface_check_png (cairo_win32_surface_t *surface,
+ cairo_surface_t *source,
+ const unsigned char **data,
+ unsigned int *length,
+ cairo_image_info_t *info)
+{
+ const unsigned char *mime_data;
+ unsigned int mime_data_length;
+
+ cairo_int_status_t status;
+ DWORD result;
+
+ if (!(surface->flags & CAIRO_WIN32_SURFACE_CAN_CHECK_PNG))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_PNG,
+ &mime_data, &mime_data_length);
+ if (mime_data == NULL)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ status = _cairo_image_info_get_png_info (info, mime_data, mime_data_length);
+ if (status)
+ return status;
+
+ result = 0;
+ if (ExtEscape(surface->dc, CHECKPNGFORMAT, mime_data_length, (char *) mime_data,
+ sizeof(result), (char *) &result) <= 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ if (result != 1)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ *data = mime_data;
+ *length = mime_data_length;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
static cairo_status_t
_cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surface,
cairo_surface_pattern_t *pattern)
@@ -503,6 +603,11 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf
int x_tile, y_tile, left, right, top, bottom;
RECT clip;
const cairo_color_t *background_color;
+ const unsigned char *mime_data;
+ unsigned int mime_size;
+ cairo_image_info_t mime_info;
+ cairo_bool_t use_mime;
+ DWORD mime_type;
/* If we can't use StretchDIBits with this surface, we can't do anything
* here.
@@ -532,7 +637,26 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf
goto CLEANUP_IMAGE;
}
- if (image->format != CAIRO_FORMAT_RGB24) {
+ mime_type = BI_JPEG;
+ status = _cairo_win32_printing_surface_check_jpeg (surface,
+ pattern->surface,
+ &mime_data,
+ &mime_size,
+ &mime_info);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ mime_type = BI_PNG;
+ status = _cairo_win32_printing_surface_check_png (surface,
+ pattern->surface,
+ &mime_data,
+ &mime_size,
+ &mime_info);
+ }
+ if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
+ use_mime = (status == CAIRO_STATUS_SUCCESS);
+
+ if (!use_mime && image->format != CAIRO_FORMAT_RGB24) {
cairo_surface_pattern_t opaque_pattern;
opaque_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
@@ -577,14 +701,14 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf
}
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- bi.bmiHeader.biWidth = opaque_image->width;
- bi.bmiHeader.biHeight = -opaque_image->height;
- bi.bmiHeader.biSizeImage = 0;
+ bi.bmiHeader.biWidth = use_mime ? mime_info.width : opaque_image->width;
+ bi.bmiHeader.biHeight = use_mime ? - mime_info.height : -opaque_image->height;
+ bi.bmiHeader.biSizeImage = use_mime ? mime_size : 0;
bi.bmiHeader.biXPelsPerMeter = PELS_72DPI;
bi.bmiHeader.biYPelsPerMeter = PELS_72DPI;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
- bi.bmiHeader.biCompression = BI_RGB;
+ bi.bmiHeader.biCompression = use_mime ? mime_type : BI_RGB;
bi.bmiHeader.biClrUsed = 0;
bi.bmiHeader.biClrImportant = 0;
@@ -626,9 +750,9 @@ _cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surf
opaque_image->height,
0,
0,
- opaque_image->width,
- opaque_image->height,
- opaque_image->data,
+ use_mime ? mime_info.width : opaque_image->width,
+ use_mime ? mime_info.height : opaque_image->height,
+ use_mime ? mime_data : opaque_image->data,
&bi,
DIB_RGB_COLORS,
SRCCOPY))
@@ -1037,7 +1161,8 @@ _cairo_win32_printing_surface_get_font_options (void *abstract_
static cairo_int_status_t
_cairo_win32_printing_surface_paint (void *abstract_surface,
cairo_operator_t op,
- const cairo_pattern_t *source)
+ const cairo_pattern_t *source,
+ cairo_rectangle_int_t *extents)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_solid_pattern_t clear;
@@ -1114,7 +1239,8 @@ _cairo_win32_printing_surface_stroke (void *abstract_surface,
cairo_matrix_t *stroke_ctm,
cairo_matrix_t *stroke_ctm_inverse,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_int_status_t status;
@@ -1235,7 +1361,8 @@ _cairo_win32_printing_surface_fill (void *abstract_surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_int_status_t status;
@@ -1294,7 +1421,8 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs)
+ int *remaining_glyphs,
+ cairo_rectangle_int_t *extents)
{
cairo_win32_surface_t *surface = abstract_surface;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
@@ -1414,7 +1542,8 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac
status = _cairo_win32_surface_show_glyphs (surface, op,
source, glyphs,
num_glyphs, scaled_font,
- remaining_glyphs);
+ remaining_glyphs,
+ extents);
if (surface->has_ctm)
cairo_scaled_font_destroy (scaled_font);
@@ -1589,6 +1718,7 @@ cairo_win32_printing_surface_create (HDC hdc)
surface->flags |= CAIRO_WIN32_SURFACE_FOR_PRINTING;
_cairo_win32_printing_surface_init_ps_mode (surface);
+ _cairo_win32_printing_surface_init_image_support (surface);
_cairo_surface_init (&surface->base, &cairo_win32_printing_surface_backend,
CAIRO_CONTENT_COLOR_ALPHA);
@@ -1622,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-private.h b/src/cairo-win32-private.h
index 09f63286..51564d04 100644
--- a/src/cairo-win32-private.h
+++ b/src/cairo-win32-private.h
@@ -117,6 +117,12 @@ enum {
/* Whether we can use GradientFill rectangles with this surface */
CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT = (1<<6),
+
+ /* Whether we can use the CHECKJPEGFORMAT escape function */
+ CAIRO_WIN32_SURFACE_CAN_CHECK_JPEG = (1<<7),
+
+ /* Whether we can use the CHECKJPEGFORMAT escape function */
+ CAIRO_WIN32_SURFACE_CAN_CHECK_PNG = (1<<8),
};
cairo_status_t
@@ -145,7 +151,8 @@ _cairo_win32_surface_show_glyphs (void *surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs);
+ int *remaining_glyphs,
+ cairo_rectangle_int_t *extents);
cairo_surface_t *
_cairo_win32_surface_create_similar (void *abstract_src,
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index 05f5188c..03a8f61a 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -872,6 +872,9 @@ _cairo_win32_surface_composite_inner (cairo_win32_surface_t *src,
return CAIRO_STATUS_SUCCESS;
}
+/* from pixman-private.h */
+#define MOD(a,b) ((a) < 0 ? ((b) - ((-(a) - 1) % (b))) - 1 : (a) % (b))
+
static cairo_int_status_t
_cairo_win32_surface_composite (cairo_operator_t op,
const cairo_pattern_t *pattern,
@@ -1153,8 +1156,8 @@ _cairo_win32_surface_composite (cairo_operator_t op,
uint32_t rendered_width = 0, rendered_height = 0;
uint32_t to_render_height, to_render_width;
int32_t piece_x, piece_y;
- int32_t src_start_x = src_r.x % src_extents.width;
- int32_t src_start_y = src_r.y % src_extents.height;
+ int32_t src_start_x = MOD(src_r.x, src_extents.width);
+ int32_t src_start_y = MOD(src_r.y, src_extents.height);
if (needs_scale)
goto UNSUPPORTED;
@@ -1469,11 +1472,12 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
/* Create a GDI region for the cairo region */
_cairo_region_get_extents (region, &extents);
+ num_boxes = 0;
status = _cairo_region_get_boxes (region, &num_boxes, &boxes);
if (status)
return status;
- if (num_boxes == 1 &&
+ if (num_boxes == 1 &&
boxes[0].p1.x == 0 &&
boxes[0].p1.y == 0 &&
boxes[0].p2.x == surface->extents.width &&
@@ -1566,7 +1570,8 @@ _cairo_win32_surface_show_glyphs (void *surface,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs)
+ int *remaining_glyphs,
+ cairo_rectangle_int_t *extents)
{
#if CAIRO_HAS_WIN32_FONT
cairo_win32_surface_t *dst = surface;
@@ -1977,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 d5146592..6f246f80 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -1560,6 +1560,7 @@ _cairo_xcb_surface_set_clip_region (void *abstract_surface,
xcb_rectangle_t *rects = NULL;
int n_boxes, i;
+ n_boxes = 0;
status = _cairo_region_get_boxes (region, &n_boxes, &boxes);
if (status)
return status;
@@ -1683,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,
@@ -2416,6 +2419,9 @@ _cairo_xcb_surface_emit_glyphs (cairo_xcb_surface_t *dst,
}
}
+ /* We wouldn't want to leak memory, would we? */
+ free(output_glyphs);
+
return CAIRO_STATUS_SUCCESS;
}
diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c
index 14e50d60..e85174b7 100644
--- a/src/cairo-xlib-display.c
+++ b/src/cairo-xlib-display.c
@@ -248,7 +248,7 @@ _cairo_xlib_display_get (Display *dpy,
}
display = malloc (sizeof (cairo_xlib_display_t));
- if (display == NULL) {
+ if (unlikely (display == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto UNLOCK;
}
@@ -262,7 +262,7 @@ _cairo_xlib_display_get (Display *dpy,
XRenderQueryVersion (dpy, &render_major, &render_minor);
codes = XAddExtension (dpy);
- if (codes == NULL) {
+ if (unlikely (codes == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
free (display);
display = NULL;
@@ -287,25 +287,54 @@ _cairo_xlib_display_get (Display *dpy,
sizeof (display->cached_xrender_formats));
display->buggy_repeat = FALSE;
+
+ /* This buggy_repeat condition is very complicated because there
+ * are multiple X server code bases (with multiple versioning
+ * schemes within a code base), and multiple bugs.
+ *
+ * The X servers:
+ *
+ * 1. The Vendor=="XFree86" code base with release numbers such
+ * as 4.7.0 (VendorRelease==40700000).
+ *
+ * 2. The Vendor=="X.Org" code base (a descendant of the
+ * XFree86 code base). It originally had things like
+ * VendorRelease==60700000 for release 6.7.0 but then changed
+ * its versioning scheme so that, for example,
+ * VendorRelease==10400000 for the 1.4.0 X server within the
+ * X.Org 7.3 release.
+ *
+ * The bugs:
+ *
+ * 1. The original bug that led to the buggy_repeat
+ * workaround. This was a bug that Owen Taylor investigated,
+ * understood well, and characterized against carious X
+ * servers. Confirmed X servers with this bug include:
+ *
+ * "XFree86" <= 40500000
+ * "X.Org" <= 60802000 (only with old numbering >= 60700000)
+ *
+ * 2. A separate bug resulting in a crash of the X server when
+ * using cairo's extend-reflect test case, (which, surprisingly
+ * enough was not passing RepeatReflect to the X server, but
+ * instead using RepeatNormal in a workaround). Nobody to date
+ * has understood the bug well, but it appears to be gone as of
+ * the X.Org 1.4.0 server. This bug is coincidentally avoided
+ * by using the same buggy_repeat workaround. Confirmed X
+ * servers with this bug include:
+ *
+ * "X.org" == 60900000 (old versioning scheme)
+ * "X.org" < 10400000 (new numbering scheme)
+ *
+ * For the old-versioning-scheme X servers we don't know
+ * exactly when second the bug started, but since bug 1 is
+ * present through 6.8.2 and bug 2 is present in 6.9.0 it seems
+ * safest to just blacklist all old-versioning-scheme X servers,
+ * (just using VendorRelase < 70000000), as buggy_repeat=TRUE.
+ */
if (strstr (ServerVendor (dpy), "X.Org") != NULL) {
- /* When modularized, the X.Org server VendorRelease was
- * bogusly reset to a very small number, without any change in
- * the ServerVendor string. We avoid considering the new
- * servers with the small number as buggy by restricting the
- * test to known bad releases. But there could be a problem
- * again in the future if X.Org server versions ever climb
- * back up to 6.7 or 6.8. */
- if (VendorRelease (dpy) >= 60700000 && VendorRelease (dpy) <= 60802000)
+ if (VendorRelease (dpy) >= 60700000 && VendorRelease (dpy) < 70000000)
display->buggy_repeat = TRUE;
-
- /* But even the new modular server has bugs, (bad enough to
- * crash the X server), that it so happens we can avoid with
- * the exact same buggy_repeat workaround. We've verified that
- * this bug exists as least as late as version 1.3.0.0, (which
- * is in Fedora 8), and is gone again in version 1.4.99.901
- * (from a Fedora 9 Beta). Versions between those are still
- * unknown, but until we learn more, we'll assume that any 1.3
- * version is buggy. */
if (VendorRelease (dpy) < 10400000)
display->buggy_repeat = TRUE;
} else if (strstr (ServerVendor (dpy), "XFree86") != NULL) {
diff --git a/src/cairo-xlib-screen.c b/src/cairo-xlib-screen.c
index 9dd411ed..3b1ae2e1 100644
--- a/src/cairo-xlib-screen.c
+++ b/src/cairo-xlib-screen.c
@@ -352,7 +352,7 @@ _cairo_xlib_screen_info_get (cairo_xlib_display_t *display,
info = _cairo_xlib_screen_info_reference (info);
} else {
info = malloc (sizeof (cairo_xlib_screen_info_t));
- if (info == NULL)
+ if (unlikely (info == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
CAIRO_REFERENCE_COUNT_INIT (&info->ref_count, 2); /* Add one for display cache */
@@ -485,7 +485,7 @@ _cairo_xlib_screen_get_visual_info (cairo_xlib_screen_info_t *info,
XScreenNumberOfScreen (info->screen),
visual->visualid,
&ret);
- if (status)
+ if (unlikely (status))
return status;
CAIRO_MUTEX_LOCK (info->mutex);
@@ -506,7 +506,7 @@ _cairo_xlib_screen_get_visual_info (cairo_xlib_screen_info_t *info,
status = _cairo_array_append (&info->visuals, &ret);
CAIRO_MUTEX_UNLOCK (info->mutex);
- if (status) {
+ if (unlikely (status)) {
_cairo_xlib_visual_info_destroy (dpy, ret);
return status;
}
diff --git a/src/cairo-xlib-surface-private.h b/src/cairo-xlib-surface-private.h
index e06fd978..fe37e5fb 100644
--- a/src/cairo-xlib-surface-private.h
+++ b/src/cairo-xlib-surface-private.h
@@ -85,7 +85,8 @@ struct _cairo_xlib_surface {
unsigned int clip_dirty;
cairo_bool_t have_clip_rects;
- XRectangle embedded_clip_rects[4];
+ cairo_bool_t gc_has_clip_rects;
+ XRectangle embedded_clip_rects[8];
XRectangle *clip_rects;
int num_clip_rects;
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 7efe8287..68d81922 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -86,7 +86,8 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs);
+ int *remaining_glyphs,
+ cairo_rectangle_int_t *extents);
/*
* Instead of taking two round trips for each blending request,
@@ -146,9 +147,8 @@ _cairo_xlib_surface_create_similar_with_format (void *abstract_src,
if (! CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src))
return NULL;
- xrender_format = _cairo_xlib_display_get_xrender_format (
- src->display,
- format);
+ xrender_format = _cairo_xlib_display_get_xrender_format (src->display,
+ format);
if (xrender_format == NULL)
return NULL;
@@ -306,7 +306,7 @@ _cairo_xlib_surface_finish (void *abstract_surface)
status2 = _cairo_xlib_screen_put_gc (surface->screen_info,
surface->depth,
surface->gc,
- surface->have_clip_rects);
+ surface->gc_has_clip_rects);
surface->gc = NULL;
if (status == CAIRO_STATUS_SUCCESS)
status = status2;
@@ -671,7 +671,7 @@ _get_image_surface (cairo_xlib_surface_t *surface,
Pixmap pixmap;
status = _cairo_xlib_surface_ensure_gc (surface);
- if (status)
+ if (unlikely (status))
return status;
pixmap = XCreatePixmap (surface->dpy,
@@ -716,7 +716,7 @@ _get_image_surface (cairo_xlib_surface_t *surface,
ximage->height,
ximage->bytes_per_line);
status = image->base.status;
- if (status)
+ if (unlikely (status))
goto BAIL;
/* Let the surface take ownership of the data */
@@ -777,14 +777,14 @@ _get_image_surface (cairo_xlib_surface_t *surface,
status = _cairo_xlib_screen_get_visual_info (surface->screen_info,
surface->visual,
&visual_info);
- if (status)
+ if (unlikely (status))
goto BAIL;
}
image = (cairo_image_surface_t *) cairo_image_surface_create
(format, ximage->width, ximage->height);
status = image->base.status;
- if (status)
+ if (unlikely (status))
goto BAIL;
data = cairo_image_surface_get_data (&image->base);
@@ -821,7 +821,7 @@ _get_image_surface (cairo_xlib_surface_t *surface,
BAIL:
XDestroyImage (ximage);
- if (status) {
+ if (unlikely (status)) {
if (image) {
cairo_surface_destroy (&image->base);
image = NULL;
@@ -870,6 +870,7 @@ _cairo_xlib_surface_set_picture_clip_rects (cairo_xlib_surface_t *surface)
static void
_cairo_xlib_surface_set_gc_clip_rects (cairo_xlib_surface_t *surface)
{
+ surface->gc_has_clip_rects = surface->have_clip_rects;
if (surface->have_clip_rects) {
XSetClipRectangles(surface->dpy, surface->gc,
0, 0,
@@ -908,7 +909,7 @@ _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface)
gcv.graphics_exposures = False;
surface->gc = XCreateGC (surface->dpy, surface->drawable,
GCGraphicsExposures, &gcv);
- if (!surface->gc)
+ if (unlikely (surface->gc == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
}
@@ -988,7 +989,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
ximage.bits_per_pixel);
ximage.bytes_per_line = stride;
ximage.data = _cairo_malloc_ab (stride, ximage.height);
- if (ximage.data == NULL)
+ if (unlikely (ximage.data == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
own_data = TRUE;
@@ -1012,7 +1013,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
status = _cairo_xlib_screen_get_visual_info (surface->screen_info,
surface->visual,
&visual_info);
- if (status)
+ if (unlikely (status))
goto BAIL;
}
@@ -1069,7 +1070,7 @@ _draw_image_surface (cairo_xlib_surface_t *surface,
}
status = _cairo_xlib_surface_ensure_gc (surface);
- if (status)
+ if (unlikely (status))
goto BAIL;
XPutImage(surface->dpy, surface->drawable, surface->gc,
@@ -1095,7 +1096,7 @@ _cairo_xlib_surface_acquire_source_image (void *abstract_surf
_cairo_xlib_display_notify (surface->display);
status = _get_image_surface (surface, NULL, &image, NULL);
- if (status)
+ if (unlikely (status))
return status;
*image_out = image;
@@ -1126,7 +1127,7 @@ _cairo_xlib_surface_acquire_dest_image (void *abstract_surfac
_cairo_xlib_display_notify (surface->display);
status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
- if (status)
+ if (unlikely (status))
return status;
*image_out = image;
@@ -1215,7 +1216,7 @@ _cairo_xlib_surface_clone_similar (void *abstract_surface,
src_x, src_y,
width, height,
0, 0);
- if (status) {
+ if (unlikely (status)) {
cairo_surface_destroy (&clone->base);
return status;
}
@@ -1262,7 +1263,7 @@ _cairo_xlib_surface_create_solid_pattern_surface (void *abstrac
_cairo_image_surface_create_with_content (solid_pattern->content,
width, height);
status = image->base.status;
- if (status)
+ if (unlikely (status))
goto BAIL;
pixmap = XCreatePixmap (other->dpy,
@@ -1278,26 +1279,26 @@ _cairo_xlib_surface_create_solid_pattern_surface (void *abstrac
width, height,
other->depth);
status = surface->base.status;
- if (status)
+ if (unlikely (status))
goto BAIL;
status = _cairo_surface_paint (&image->base,
CAIRO_OPERATOR_SOURCE,
- &solid_pattern->base);
- if (status)
+ &solid_pattern->base, NULL);
+ if (unlikely (status))
goto BAIL;
status = _draw_image_surface (surface, image,
0, 0,
width, height,
0, 0);
- if (status)
+ if (unlikely (status))
goto BAIL;
BAIL:
cairo_surface_destroy (&image->base);
- if (status) {
+ if (unlikely (status)) {
if (pixmap != None)
XFreePixmap (other->dpy, pixmap);
cairo_surface_destroy (&surface->base);
@@ -1311,24 +1312,28 @@ _cairo_xlib_surface_create_solid_pattern_surface (void *abstrac
static cairo_status_t
_cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface,
- cairo_matrix_t *matrix)
+ cairo_matrix_t *matrix,
+ double xc,
+ double yc)
{
XTransform xtransform;
if (!surface->src_picture)
return CAIRO_STATUS_SUCCESS;
-
+
/* Casting between pixman_transform_t and XTransform is safe because
* they happen to be the exact same type.
*/
- _cairo_matrix_to_pixman_matrix (matrix, (pixman_transform_t *)&xtransform);
+ _cairo_matrix_to_pixman_matrix (matrix,
+ (pixman_transform_t *) &xtransform,
+ xc, yc);
if (memcmp (&xtransform, &surface->xtransform, sizeof (XTransform)) == 0)
return CAIRO_STATUS_SUCCESS;
if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
return CAIRO_INT_STATUS_UNSUPPORTED;
-
+
XRenderSetPictureTransform (surface->dpy, surface->src_picture, &xtransform);
surface->xtransform = xtransform;
@@ -1410,14 +1415,17 @@ _cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface, int repeat)
static cairo_int_status_t
_cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface,
- cairo_surface_attributes_t *attributes)
+ cairo_surface_attributes_t *attributes,
+ double xc,
+ double yc)
{
cairo_int_status_t status;
_cairo_xlib_surface_ensure_src_picture (surface);
- status = _cairo_xlib_surface_set_matrix (surface, &attributes->matrix);
- if (status)
+ status = _cairo_xlib_surface_set_matrix (surface, &attributes->matrix,
+ xc, yc);
+ if (unlikely (status))
return status;
switch (attributes->extend) {
@@ -1434,7 +1442,7 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface,
}
status = _cairo_xlib_surface_set_filter (surface, attributes->filter);
- if (status)
+ if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
@@ -1719,7 +1727,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
(cairo_surface_t **) &src,
(cairo_surface_t **) &mask,
&src_attr, &mask_attr);
- if (status)
+ if (unlikely (status))
return status;
/* check for fallback surfaces that we cannot handle ... */
@@ -1745,14 +1753,18 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
switch (operation)
{
case DO_RENDER:
- status = _cairo_xlib_surface_set_attributes (src, &src_attr);
- if (status)
+ status = _cairo_xlib_surface_set_attributes (src, &src_attr,
+ dst_x + width / 2.,
+ dst_y + height / 2.);
+ if (unlikely (status))
goto BAIL;
_cairo_xlib_surface_ensure_dst_picture (dst);
if (mask) {
- status = _cairo_xlib_surface_set_attributes (mask, &mask_attr);
- if (status)
+ status = _cairo_xlib_surface_set_attributes (mask, &mask_attr,
+ dst_x + width / 2.,
+ dst_y + height/ 2.);
+ if (unlikely (status))
goto BAIL;
XRenderComposite (dst->dpy,
@@ -1783,7 +1795,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
case DO_XCOPYAREA:
status = _cairo_xlib_surface_ensure_gc (dst);
- if (status)
+ if (unlikely (status))
goto BAIL;
is_integer_translation = _cairo_matrix_is_integer_translation (&src_attr.matrix,
@@ -1811,7 +1823,7 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
*/
status = _cairo_xlib_surface_ensure_gc (dst);
- if (status)
+ if (unlikely (status))
goto BAIL;
is_integer_translation = _cairo_matrix_is_integer_translation (&src_attr.matrix,
&itx, &ity);
@@ -1866,7 +1878,7 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface,
_cairo_pattern_init_solid (&solid, color, CAIRO_CONTENT_COLOR);
status = _cairo_xlib_surface_ensure_gc (surface);
- if (status)
+ if (unlikely (status))
return status;
status = _cairo_pattern_acquire_surface (&solid.base, &surface->base,
@@ -1875,7 +1887,7 @@ _cairo_xlib_surface_solid_fill_rectangles (cairo_xlib_surface_t *surface,
ARRAY_LENGTH (dither_pattern),
&solid_surface,
&attrs);
- if (status)
+ if (unlikely (status))
return status;
if (! _cairo_surface_is_xlib (solid_surface)) {
@@ -1911,8 +1923,6 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface,
{
cairo_xlib_surface_t *surface = abstract_surface;
XRenderColor render_color;
- XRectangle static_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
- XRectangle *xrects = static_xrects;
int i;
_cairo_xlib_display_notify (surface->display);
@@ -1948,9 +1958,12 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface,
rects->width,
rects->height);
} else {
+ XRectangle static_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
+ XRectangle *xrects = static_xrects;
+
if (num_rects > ARRAY_LENGTH (static_xrects)) {
xrects = _cairo_malloc_ab (num_rects, sizeof (XRectangle));
- if (xrects == NULL)
+ if (unlikely (xrects == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -2122,7 +2135,7 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
src_x, src_y, width, height,
(cairo_surface_t **) &src,
&attributes);
- if (status)
+ if (unlikely (status))
return status;
operation = _recategorize_composite_operation (dst, op, src,
@@ -2160,8 +2173,10 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
render_src_y = src_y + render_reference_y - dst_y;
_cairo_xlib_surface_ensure_dst_picture (dst);
- status = _cairo_xlib_surface_set_attributes (src, &attributes);
- if (status)
+ status = _cairo_xlib_surface_set_attributes (src, &attributes,
+ dst_x + width / 2.,
+ dst_y + height / 2.);
+ if (unlikely (status))
goto BAIL;
if (!_cairo_operator_bounded_by_mask (op)) {
@@ -2209,7 +2224,7 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
if (num_traps > ARRAY_LENGTH (xtraps_stack)) {
xtraps = _cairo_malloc_ab (num_traps, sizeof (XTrapezoid));
- if (xtraps == NULL) {
+ if (unlikely (xtraps == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL;
}
@@ -2246,6 +2261,7 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
return status;
}
+COMPILE_TIME_ASSERT (sizeof (XRectangle) <= sizeof (cairo_box_int_t));
static cairo_int_status_t
_cairo_xlib_surface_set_clip_region (void *abstract_surface,
cairo_region_t *region)
@@ -2283,14 +2299,16 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
_cairo_region_init_rect (&bound, &rect);
_cairo_region_init (&bounded);
status = _cairo_region_intersect (&bounded, &bound, region);
- if (status) {
+ if (unlikely (status)) {
_cairo_region_fini (&bound);
_cairo_region_fini (&bounded);
return status;
}
+ n_boxes = sizeof (surface->embedded_clip_rects) / sizeof (cairo_box_int_t);
+ boxes = (cairo_box_int_t *) surface->embedded_clip_rects;
status = _cairo_region_get_boxes (&bounded, &n_boxes, &boxes);
- if (status) {
+ if (unlikely (status)) {
_cairo_region_fini (&bound);
_cairo_region_fini (&bounded);
return status;
@@ -2298,24 +2316,24 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
if (n_boxes > ARRAY_LENGTH (surface->embedded_clip_rects)) {
rects = _cairo_malloc_ab (n_boxes, sizeof (XRectangle));
- if (rects == NULL) {
+ if (unlikely (rects == NULL)) {
_cairo_region_boxes_fini (&bounded, boxes);
_cairo_region_fini (&bound);
_cairo_region_fini (&bounded);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
- } else {
+ } else
rects = surface->embedded_clip_rects;
- }
for (i = 0; i < n_boxes; i++) {
rects[i].x = boxes[i].p1.x;
rects[i].y = boxes[i].p1.y;
- rects[i].width = boxes[i].p2.x - boxes[i].p1.x;
- rects[i].height = boxes[i].p2.y - boxes[i].p1.y;
+ rects[i].width = boxes[i].p2.x - rects[i].x;
+ rects[i].height = boxes[i].p2.y - rects[i].y;
}
- _cairo_region_boxes_fini (&bounded, boxes);
+ if (boxes != (cairo_box_int_t *) surface->embedded_clip_rects)
+ _cairo_region_boxes_fini (&bounded, boxes);
_cairo_region_fini (&bounded);
_cairo_region_fini (&bound);
@@ -2410,7 +2428,7 @@ _cairo_xlib_surface_reset (void *abstract_surface)
cairo_status_t status;
status = _cairo_xlib_surface_set_clip_region (surface, NULL);
- if (status)
+ if (unlikely (status))
return status;
return CAIRO_STATUS_SUCCESS;
@@ -2428,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,
@@ -2545,17 +2565,17 @@ _cairo_xlib_surface_create_internal (Display *dpy,
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
status = _cairo_xlib_display_get (dpy, &display);
- if (status)
+ if (unlikely (status))
return _cairo_surface_create_in_error (status);
status = _cairo_xlib_screen_info_get (display, screen, &screen_info);
- if (status) {
+ if (unlikely (status)) {
_cairo_xlib_display_destroy (display);
return _cairo_surface_create_in_error (status);
}
surface = malloc (sizeof (cairo_xlib_surface_t));
- if (surface == NULL) {
+ if (unlikely (surface == NULL)) {
_cairo_xlib_screen_info_destroy (screen_info);
_cairo_xlib_display_destroy (display);
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
@@ -2619,6 +2639,7 @@ _cairo_xlib_surface_create_internal (Display *dpy,
surface->xtransform = identity;
surface->have_clip_rects = FALSE;
+ surface->gc_has_clip_rects = FALSE;
surface->clip_rects = surface->embedded_clip_rects;
surface->num_clip_rects = 0;
surface->clip_dirty = 0;
@@ -2883,7 +2904,7 @@ cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface,
surface->display,
XRenderFreePicture,
surface->dst_picture);
- if (status) {
+ if (unlikely (status)) {
status = _cairo_surface_set_error (&surface->base, status);
return;
}
@@ -2896,7 +2917,7 @@ cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface,
surface->display,
XRenderFreePicture,
surface->src_picture);
- if (status) {
+ if (unlikely (status)) {
status = _cairo_surface_set_error (&surface->base, status);
return;
}
@@ -3148,12 +3169,12 @@ _cairo_xlib_surface_font_init (Display *dpy,
int i;
font_private = malloc (sizeof (cairo_xlib_surface_font_private_t));
- if (font_private == NULL)
+ if (unlikely (font_private == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font_private->scaled_font = scaled_font;
status = _cairo_xlib_display_get (dpy, &font_private->display);
- if (status) {
+ if (unlikely (status)) {
free (font_private);
return status;
}
@@ -3269,7 +3290,7 @@ _cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
to_free,
free);
/* XXX cannot propagate failure */
- if (status)
+ if (unlikely (status))
free (to_free);
to_free = glyphset_info->pending_free_glyphs = NULL;
@@ -3277,7 +3298,7 @@ _cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
if (to_free == NULL) {
to_free = malloc (sizeof (cairo_xlib_font_glyphset_free_glyphs_t));
- if (to_free == NULL) {
+ if (unlikely (to_free == NULL)) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return; /* XXX cannot propagate failure */
}
@@ -3425,7 +3446,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
CAIRO_SCALED_GLYPH_INFO_METRICS |
CAIRO_SCALED_GLYPH_INFO_SURFACE,
pscaled_glyph);
- if (status)
+ if (unlikely (status))
return status;
scaled_glyph = *pscaled_glyph;
@@ -3437,7 +3458,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
if (scaled_font->surface_private == NULL) {
status = _cairo_xlib_surface_font_init (dpy, scaled_font);
- if (status)
+ if (unlikely (status))
return status;
}
@@ -3464,7 +3485,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
tmp_surface = cairo_image_surface_create (glyphset_info->format, 1, 1);
status = tmp_surface->status;
- if (status)
+ if (unlikely (status))
goto BAIL;
cr = cairo_create (tmp_surface);
@@ -3478,7 +3499,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
glyph_surface = (cairo_image_surface_t *) tmp_surface;
- if (status)
+ if (unlikely (status))
goto BAIL;
}
@@ -3494,7 +3515,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
glyph_surface->width,
glyph_surface->height);
status = tmp_surface->status;
- if (status)
+ if (unlikely (status))
goto BAIL;
tmp_surface->device_transform = glyph_surface->base.device_transform;
@@ -3509,7 +3530,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
glyph_surface = (cairo_image_surface_t *) tmp_surface;
- if (status)
+ if (unlikely (status))
goto BAIL;
}
@@ -3559,7 +3580,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
unsigned char *new, *n;
new = malloc (c);
- if (new == NULL) {
+ if (unlikely (new == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL;
}
@@ -3703,7 +3724,7 @@ _emit_glyphs_chunk (cairo_xlib_surface_t *dst,
elts = stack_elts;
} else {
elts = _cairo_malloc_ab (num_elts, sizeof (XGlyphElt8));
- if (elts == NULL)
+ if (unlikely (elts == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
@@ -3844,7 +3865,7 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
status = _cairo_xlib_surface_add_glyph (dst->dpy,
scaled_font,
&scaled_glyph);
- if (status) {
+ if (unlikely (status)) {
if (status == CAIRO_INT_STATUS_UNSUPPORTED)
/* Break so we flush glyphs so far and let fallback code
* handle the rest */
@@ -3966,7 +3987,8 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs)
+ int *remaining_glyphs,
+ cairo_rectangle_int_t *extents)
{
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
cairo_xlib_surface_t *dst = (cairo_xlib_surface_t*) abstract_dst;
@@ -4034,7 +4056,7 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
0, 0, 1, 1,
(cairo_surface_t **) &src,
&attributes);
- if (status)
+ if (unlikely (status))
goto BAIL0;
} else {
cairo_rectangle_int_t glyph_extents;
@@ -4043,7 +4065,7 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
glyphs,
num_glyphs,
&glyph_extents);
- if (status)
+ if (unlikely (status))
goto BAIL0;
status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
@@ -4051,7 +4073,7 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
glyph_extents.width, glyph_extents.height,
(cairo_surface_t **) &src,
&attributes);
- if (status)
+ if (unlikely (status))
goto BAIL0;
}
@@ -4062,8 +4084,8 @@ _cairo_xlib_surface_show_glyphs (void *abstract_dst,
goto BAIL1;
}
- status = _cairo_xlib_surface_set_attributes (src, &attributes);
- if (status)
+ status = _cairo_xlib_surface_set_attributes (src, &attributes, 0, 0);
+ if (unlikely (status))
goto BAIL1;
_cairo_scaled_font_freeze_cache (scaled_font);
diff --git a/src/cairo-xlib-visual.c b/src/cairo-xlib-visual.c
index f6eb1ee9..7dbe86c2 100644
--- a/src/cairo-xlib-visual.c
+++ b/src/cairo-xlib-visual.c
@@ -78,7 +78,7 @@ _cairo_xlib_visual_info_create (Display *dpy,
ramp_index_to_short[i] = (0xffff * i + ((RAMP_SIZE-1)>>1)) / (RAMP_SIZE-1);
info = malloc (sizeof (cairo_xlib_visual_info_t));
- if (info == NULL)
+ if (unlikely (info == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
info->visualid = visualid;
diff --git a/src/cairo-xlib-xrender-private.h b/src/cairo-xlib-xrender-private.h
index 329262c7..eee585cc 100644
--- a/src/cairo-xlib-xrender-private.h
+++ b/src/cairo-xlib-xrender-private.h
@@ -45,6 +45,24 @@
#include <X11/extensions/Xrender.h>
#include <X11/extensions/renderproto.h>
+/* We require Render >= 0.6. The following defines were only added in
+ * 0.10. Make sure they are defined.
+ */
+
+/* Filters included in 0.10 */
+#ifndef FilterConvolution
+#define FilterConvolution "convolution"
+#endif
+
+/* Extended repeat attributes included in 0.10 */
+#ifndef RepeatNone
+#define RepeatNone 0
+#define RepeatNormal 1
+#define RepeatPad 2
+#define RepeatReflect 3
+#endif
+
+
#else /* !CAIRO_HAS_XLIB_XRENDER_SURFACE */
/* Provide dummy symbols and macros to get it compile and take the fallback
diff --git a/src/cairo.c b/src/cairo.c
index 06353319..b33c03b7 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -152,7 +152,7 @@ cairo_create (cairo_surface_t *target)
return (cairo_t *) &_cairo_nil;
cr = malloc (sizeof (cairo_t));
- if (cr == NULL) {
+ if (unlikely (cr == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return (cairo_t *) &_cairo_nil;
}
@@ -166,9 +166,9 @@ cairo_create (cairo_surface_t *target)
cr->gstate = cr->gstate_tail;
cr->gstate_freelist = NULL;
- status = _cairo_gstate_init (cr->gstate, target);
- if (status)
+ status = _cairo_gstate_init (cr->gstate, target);
+ if (unlikely (status))
_cairo_set_error (cr, status);
return cr;
@@ -212,6 +212,8 @@ cairo_reference (cairo_t *cr)
void
cairo_destroy (cairo_t *cr)
{
+ cairo_surface_t *surface;
+
if (cr == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&cr->ref_count))
return;
@@ -225,6 +227,15 @@ cairo_destroy (cairo_t *cr)
break;
}
+ /* The context is expected (>99% of all use cases) to be held for the
+ * duration of a single expose event/sequence of graphic operations.
+ * Therefore, on destroy we explicitly flush the Cairo pipeline of any
+ * pending operations.
+ */
+ surface = _cairo_gstate_get_original_target (cr->gstate);
+ if (surface != NULL)
+ cairo_surface_flush (surface);
+
_cairo_gstate_fini (cr->gstate);
while (cr->gstate_freelist != NULL) {
cairo_gstate_t *gstate = cr->gstate_freelist;
@@ -338,7 +349,7 @@ cairo_save (cairo_t *cr)
return;
status = _cairo_gstate_save (&cr->gstate, &cr->gstate_freelist);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def(cairo_save);
@@ -360,7 +371,7 @@ cairo_restore (cairo_t *cr)
return;
status = _cairo_gstate_restore (&cr->gstate, &cr->gstate_freelist);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def(cairo_restore);
@@ -414,7 +425,6 @@ cairo_push_group (cairo_t *cr)
{
cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA);
}
-slim_hidden_def(cairo_push_group);
/**
* cairo_push_group_with_content:
@@ -448,10 +458,10 @@ cairo_push_group_with_content (cairo_t *cr, cairo_content_t content)
parent_surface = _cairo_gstate_get_target (cr->gstate);
/* Get the extents that we'll use in creating our new group surface */
status = _cairo_surface_get_extents (parent_surface, &extents);
- if (status)
+ if (unlikely (status))
goto bail;
status = _cairo_clip_intersect_to_rectangle (_cairo_gstate_get_clip (cr->gstate), &extents);
- if (status)
+ if (unlikely (status))
goto bail;
group_surface = cairo_surface_create_similar (_cairo_gstate_get_target (cr->gstate),
@@ -459,7 +469,7 @@ cairo_push_group_with_content (cairo_t *cr, cairo_content_t content)
extents.width,
extents.height);
status = cairo_surface_status (group_surface);
- if (status)
+ if (unlikely (status))
goto bail;
/* Set device offsets on the new surface so that logically it appears at
@@ -480,7 +490,7 @@ cairo_push_group_with_content (cairo_t *cr, cairo_content_t content)
bail:
cairo_surface_destroy (group_surface);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def(cairo_push_group_with_content);
@@ -597,7 +607,6 @@ cairo_pop_group_to_source (cairo_t *cr)
cairo_set_source (cr, group_pattern);
cairo_pattern_destroy (group_pattern);
}
-slim_hidden_def(cairo_pop_group_to_source);
/**
* cairo_set_operator:
@@ -619,7 +628,7 @@ cairo_set_operator (cairo_t *cr, cairo_operator_t op)
return;
status = _cairo_gstate_set_operator (cr->gstate, op);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_set_operator);
@@ -781,7 +790,7 @@ cairo_set_source (cairo_t *cr, cairo_pattern_t *source)
}
status = _cairo_gstate_set_source (cr->gstate, source);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_set_source);
@@ -829,9 +838,10 @@ cairo_set_tolerance (cairo_t *cr, double tolerance)
_cairo_restrict_value (&tolerance, CAIRO_TOLERANCE_MINIMUM, tolerance);
status = _cairo_gstate_set_tolerance (cr->gstate, tolerance);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
+slim_hidden_def (cairo_set_tolerance);
/**
* cairo_set_antialias:
@@ -855,7 +865,7 @@ cairo_set_antialias (cairo_t *cr, cairo_antialias_t antialias)
return;
status = _cairo_gstate_set_antialias (cr->gstate, antialias);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -881,7 +891,7 @@ cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule)
return;
status = _cairo_gstate_set_fill_rule (cr->gstate, fill_rule);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -922,7 +932,7 @@ cairo_set_line_width (cairo_t *cr, double width)
_cairo_restrict_value (&width, 0.0, width);
status = _cairo_gstate_set_line_width (cr->gstate, width);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_set_line_width);
@@ -952,7 +962,7 @@ cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap)
return;
status = _cairo_gstate_set_line_cap (cr->gstate, line_cap);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_set_line_cap);
@@ -982,7 +992,7 @@ cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join)
return;
status = _cairo_gstate_set_line_join (cr->gstate, line_join);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_set_line_join);
@@ -1032,7 +1042,7 @@ cairo_set_dash (cairo_t *cr,
status = _cairo_gstate_set_dash (cr->gstate,
dashes, num_dashes, offset);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -1122,7 +1132,7 @@ cairo_set_miter_limit (cairo_t *cr, double limit)
return;
status = _cairo_gstate_set_miter_limit (cr->gstate, limit);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -1147,7 +1157,7 @@ cairo_translate (cairo_t *cr, double tx, double ty)
return;
status = _cairo_gstate_translate (cr->gstate, tx, ty);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -1171,7 +1181,7 @@ cairo_scale (cairo_t *cr, double sx, double sy)
return;
status = _cairo_gstate_scale (cr->gstate, sx, sy);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_scale);
@@ -1197,7 +1207,7 @@ cairo_rotate (cairo_t *cr, double angle)
return;
status = _cairo_gstate_rotate (cr->gstate, angle);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -1220,7 +1230,7 @@ cairo_transform (cairo_t *cr,
return;
status = _cairo_gstate_transform (cr->gstate, matrix);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -1242,7 +1252,7 @@ cairo_set_matrix (cairo_t *cr,
return;
status = _cairo_gstate_set_matrix (cr->gstate, matrix);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_set_matrix);
@@ -1383,7 +1393,7 @@ cairo_move_to (cairo_t *cr, double x, double y)
y_fixed = _cairo_fixed_from_double (y);
status = _cairo_path_fixed_move_to (cr->path, x_fixed, y_fixed);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def(cairo_move_to);
@@ -1442,7 +1452,7 @@ cairo_line_to (cairo_t *cr, double x, double y)
y_fixed = _cairo_fixed_from_double (y);
status = _cairo_path_fixed_line_to (cr->path, x_fixed, y_fixed);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_line_to);
@@ -1497,7 +1507,7 @@ cairo_curve_to (cairo_t *cr,
x1_fixed, y1_fixed,
x2_fixed, y2_fixed,
x3_fixed, y3_fixed);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_curve_to);
@@ -1631,7 +1641,7 @@ cairo_arc_to (cairo_t *cr,
x1, y1,
x2, y2,
radius);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
*/
@@ -1667,7 +1677,7 @@ cairo_rel_move_to (cairo_t *cr, double dx, double dy)
dy_fixed = _cairo_fixed_from_double (dy);
status = _cairo_path_fixed_rel_move_to (cr->path, dx_fixed, dy_fixed);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -1704,7 +1714,7 @@ cairo_rel_line_to (cairo_t *cr, double dx, double dy)
dy_fixed = _cairo_fixed_from_double (dy);
status = _cairo_path_fixed_rel_line_to (cr->path, dx_fixed, dy_fixed);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def(cairo_rel_line_to);
@@ -1765,7 +1775,7 @@ cairo_rel_curve_to (cairo_t *cr,
dx1_fixed, dy1_fixed,
dx2_fixed, dy2_fixed,
dx3_fixed, dy3_fixed);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -1817,7 +1827,7 @@ cairo_stroke_to_path (cairo_t *cr)
/* The code in _cairo_meta_surface_get_path has a poorman's stroke_to_path */
status = _cairo_gstate_stroke_path (cr->gstate);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
#endif
@@ -1857,7 +1867,7 @@ cairo_close_path (cairo_t *cr)
return;
status = _cairo_path_fixed_close_path (cr->path);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def(cairo_close_path);
@@ -1897,8 +1907,6 @@ void
cairo_path_extents (cairo_t *cr,
double *x1, double *y1, double *x2, double *y2)
{
- cairo_status_t status;
-
if (cr->status) {
if (x1)
*x1 = 0.0;
@@ -1912,13 +1920,10 @@ cairo_path_extents (cairo_t *cr,
return;
}
- status = _cairo_gstate_path_extents (cr->gstate,
- cr->path,
- x1, y1, x2, y2);
- if (status)
- _cairo_set_error (cr, status);
+ _cairo_gstate_path_extents (cr->gstate,
+ cr->path,
+ x1, y1, x2, y2);
}
-slim_hidden_def (cairo_path_extents);
/**
* cairo_paint:
@@ -1936,7 +1941,7 @@ cairo_paint (cairo_t *cr)
return;
status = _cairo_gstate_paint (cr->gstate);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_paint);
@@ -1975,7 +1980,7 @@ cairo_paint_with_alpha (cairo_t *cr,
_cairo_pattern_init_solid (&pattern, &color, CAIRO_CONTENT_ALPHA);
status = _cairo_gstate_mask (cr->gstate, &pattern.base);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
_cairo_pattern_fini (&pattern.base);
@@ -2011,7 +2016,7 @@ cairo_mask (cairo_t *cr,
}
status = _cairo_gstate_mask (cr->gstate, pattern);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_mask);
@@ -2113,7 +2118,7 @@ cairo_stroke_preserve (cairo_t *cr)
return;
status = _cairo_gstate_stroke (cr->gstate, cr->path);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def(cairo_stroke_preserve);
@@ -2156,7 +2161,7 @@ cairo_fill_preserve (cairo_t *cr)
return;
status = _cairo_gstate_fill (cr->gstate, cr->path);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def(cairo_fill_preserve);
@@ -2182,7 +2187,7 @@ cairo_copy_page (cairo_t *cr)
return;
status = _cairo_gstate_copy_page (cr->gstate);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -2205,7 +2210,7 @@ cairo_show_page (cairo_t *cr)
return;
status = _cairo_gstate_show_page (cr->gstate);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -2239,7 +2244,7 @@ cairo_in_stroke (cairo_t *cr, double x, double y)
status = _cairo_gstate_in_stroke (cr->gstate,
cr->path,
x, y, &inside);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
return inside;
@@ -2264,17 +2269,14 @@ cairo_in_stroke (cairo_t *cr, double x, double y)
cairo_bool_t
cairo_in_fill (cairo_t *cr, double x, double y)
{
- cairo_status_t status;
- cairo_bool_t inside = FALSE;
+ cairo_bool_t inside;
if (cr->status)
return 0;
- status = _cairo_gstate_in_fill (cr->gstate,
- cr->path,
- x, y, &inside);
- if (status)
- _cairo_set_error (cr, status);
+ _cairo_gstate_in_fill (cr->gstate,
+ cr->path,
+ x, y, &inside);
return inside;
}
@@ -2409,7 +2411,7 @@ cairo_stroke_extents (cairo_t *cr,
status = _cairo_gstate_stroke_extents (cr->gstate,
cr->path,
x1, y1, x2, y2);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -2460,7 +2462,7 @@ cairo_fill_extents (cairo_t *cr,
status = _cairo_gstate_fill_extents (cr->gstate,
cr->path,
x1, y1, x2, y2);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -2525,7 +2527,7 @@ cairo_clip_preserve (cairo_t *cr)
return;
status = _cairo_gstate_clip (cr->gstate, cr->path);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def(cairo_clip_preserve);
@@ -2555,7 +2557,7 @@ cairo_reset_clip (cairo_t *cr)
return;
status = _cairo_gstate_reset_clip (cr->gstate);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -2593,7 +2595,7 @@ cairo_clip_extents (cairo_t *cr,
}
status = _cairo_gstate_clip_extents (cr->gstate, x1, y1, x2, y2);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -2679,7 +2681,7 @@ cairo_select_font_face (cairo_t *cr,
return;
status = _cairo_gstate_select_font_face (cr->gstate, family, slant, weight);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -2707,7 +2709,7 @@ cairo_font_extents (cairo_t *cr,
return;
status = _cairo_gstate_get_font_extents (cr->gstate, extents);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -2730,7 +2732,7 @@ cairo_set_font_face (cairo_t *cr,
return;
status = _cairo_gstate_set_font_face (cr->gstate, font_face);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -2762,7 +2764,7 @@ cairo_get_font_face (cairo_t *cr)
return (cairo_font_face_t*) &_cairo_font_face_nil;
status = _cairo_gstate_get_font_face (cr->gstate, &font_face);
- if (status) {
+ if (unlikely (status)) {
_cairo_set_error (cr, status);
return (cairo_font_face_t*) &_cairo_font_face_nil;
}
@@ -2794,7 +2796,7 @@ cairo_set_font_size (cairo_t *cr, double size)
return;
status = _cairo_gstate_set_font_size (cr->gstate, size);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
slim_hidden_def (cairo_set_font_size);
@@ -2822,7 +2824,7 @@ cairo_set_font_matrix (cairo_t *cr,
return;
status = _cairo_gstate_set_font_matrix (cr->gstate, matrix);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -2866,7 +2868,7 @@ cairo_set_font_options (cairo_t *cr,
return;
status = cairo_font_options_status ((cairo_font_options_t *) options);
- if (status) {
+ if (unlikely (status)) {
_cairo_set_error (cr, status);
return;
}
@@ -2930,15 +2932,15 @@ cairo_set_scaled_font (cairo_t *cr,
}
status = scaled_font->status;
- if (status)
+ if (unlikely (status))
goto BAIL;
status = _cairo_gstate_set_font_face (cr->gstate, scaled_font->font_face);
- if (status)
+ if (unlikely (status))
goto BAIL;
status = _cairo_gstate_set_font_matrix (cr->gstate, &scaled_font->font_matrix);
- if (status)
+ if (unlikely (status))
goto BAIL;
_cairo_gstate_set_font_options (cr->gstate, &scaled_font->options);
@@ -2979,7 +2981,7 @@ cairo_get_scaled_font (cairo_t *cr)
return _cairo_scaled_font_create_in_error (cr->status);
status = _cairo_gstate_get_scaled_font (cr->gstate, &scaled_font);
- if (status) {
+ if (unlikely (status)) {
_cairo_set_error (cr, status);
return _cairo_scaled_font_create_in_error (status);
}
@@ -3045,7 +3047,7 @@ cairo_text_extents (cairo_t *cr,
extents);
cairo_glyph_free (glyphs);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -3100,7 +3102,7 @@ cairo_glyph_extents (cairo_t *cr,
status = _cairo_gstate_glyph_extents (cr->gstate, glyphs, num_glyphs,
extents);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -3136,12 +3138,14 @@ cairo_show_text (cairo_t *cr, const char *utf8)
{
cairo_text_extents_t extents;
cairo_status_t status;
- cairo_glyph_t *glyphs = NULL, *last_glyph;
- cairo_text_cluster_t *clusters = NULL;
+ cairo_glyph_t *glyphs, *last_glyph;
+ cairo_text_cluster_t *clusters;
int utf8_len, num_glyphs, num_clusters;
cairo_text_cluster_flags_t cluster_flags;
double x, y;
cairo_bool_t has_show_text_glyphs;
+ cairo_glyph_t stack_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)];
+ cairo_text_cluster_t stack_clusters[CAIRO_STACK_ARRAY_LENGTH (cairo_text_cluster_t)];
if (cr->status)
return;
@@ -3156,13 +3160,19 @@ cairo_show_text (cairo_t *cr, const char *utf8)
has_show_text_glyphs =
cairo_surface_has_show_text_glyphs (cairo_get_target (cr));
+ glyphs = stack_glyphs;
+ num_glyphs = ARRAY_LENGTH (stack_glyphs);
+
+ clusters = stack_clusters;
+ num_clusters = ARRAY_LENGTH (stack_clusters);
+
status = _cairo_gstate_text_to_glyphs (cr->gstate,
x, y,
utf8, utf8_len,
&glyphs, &num_glyphs,
has_show_text_glyphs ? &clusters : NULL, &num_clusters,
&cluster_flags);
- if (status)
+ if (unlikely (status))
goto BAIL;
if (num_glyphs == 0)
@@ -3173,14 +3183,14 @@ cairo_show_text (cairo_t *cr, const char *utf8)
glyphs, num_glyphs,
clusters, num_clusters,
cluster_flags);
- if (status)
+ if (unlikely (status))
goto BAIL;
last_glyph = &glyphs[num_glyphs - 1];
status = _cairo_gstate_glyph_extents (cr->gstate,
last_glyph, 1,
&extents);
- if (status)
+ if (unlikely (status))
goto BAIL;
x = last_glyph->x + extents.x_advance;
@@ -3188,10 +3198,12 @@ cairo_show_text (cairo_t *cr, const char *utf8)
cairo_move_to (cr, x, y);
BAIL:
- cairo_glyph_free (glyphs);
- cairo_text_cluster_free (clusters);
+ if (glyphs != stack_glyphs)
+ cairo_glyph_free (glyphs);
+ if (clusters != stack_clusters)
+ cairo_text_cluster_free (clusters);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -3231,7 +3243,7 @@ cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs)
glyphs, num_glyphs,
NULL, 0,
FALSE);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -3334,7 +3346,7 @@ cairo_show_text_glyphs (cairo_t *cr,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters, cluster_flags);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -3386,7 +3398,7 @@ cairo_text_path (cairo_t *cr, const char *utf8)
NULL, NULL,
NULL);
- if (status)
+ if (unlikely (status))
goto BAIL;
if (num_glyphs == 0)
@@ -3396,7 +3408,7 @@ cairo_text_path (cairo_t *cr, const char *utf8)
glyphs, num_glyphs,
cr->path);
- if (status)
+ if (unlikely (status))
goto BAIL;
last_glyph = &glyphs[num_glyphs - 1];
@@ -3404,7 +3416,7 @@ cairo_text_path (cairo_t *cr, const char *utf8)
last_glyph, 1,
&extents);
- if (status)
+ if (unlikely (status))
goto BAIL;
x = last_glyph->x + extents.x_advance;
@@ -3414,7 +3426,7 @@ cairo_text_path (cairo_t *cr, const char *utf8)
BAIL:
cairo_glyph_free (glyphs);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -3452,7 +3464,7 @@ cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs)
status = _cairo_gstate_glyph_path (cr->gstate,
glyphs, num_glyphs,
cr->path);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
@@ -3872,7 +3884,7 @@ cairo_append_path (cairo_t *cr,
}
status = _cairo_path_append_to_context (path, cr);
- if (status)
+ if (unlikely (status))
_cairo_set_error (cr, status);
}
diff --git a/src/cairo.h b/src/cairo.h
index 7b7fe486..5e27478c 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -1883,6 +1883,7 @@ cairo_surface_status (cairo_surface_t *surface);
* @CAIRO_SURFACE_TYPE_WIN32_PRINTING: The surface is a win32 printing surface
* @CAIRO_SURFACE_TYPE_QUARTZ_IMAGE: The surface is of type quartz_image
* @CAIRO_SURFACE_TYPE_SDL: The surface is of type SDL, since 1.10
+ * @CAIRO_SURFACE_TYPE_SCRIPT: The surface is of type script, since 1.10
*
* #cairo_surface_type_t is used to describe the type of a given
* surface. The surface types are also known as "backends" or "surface
@@ -1922,7 +1923,8 @@ typedef enum _cairo_surface_type {
CAIRO_SURFACE_TYPE_OS2,
CAIRO_SURFACE_TYPE_WIN32_PRINTING,
CAIRO_SURFACE_TYPE_QUARTZ_IMAGE,
- CAIRO_SURFACE_TYPE_SDL
+ CAIRO_SURFACE_TYPE_SDL,
+ CAIRO_SURFACE_TYPE_SCRIPT
} cairo_surface_type_t;
cairo_public cairo_surface_type_t
@@ -1954,6 +1956,24 @@ cairo_surface_set_user_data (cairo_surface_t *surface,
void *user_data,
cairo_destroy_func_t destroy);
+#define CAIRO_MIME_TYPE_JPEG "image/jpeg"
+#define CAIRO_MIME_TYPE_PNG "image/png"
+#define CAIRO_MIME_TYPE_JP2 "image/jp2"
+
+cairo_public void
+cairo_surface_get_mime_data (cairo_surface_t *surface,
+ const char *mime_type,
+ const unsigned char **data,
+ unsigned int *length);
+
+cairo_public cairo_status_t
+cairo_surface_set_mime_data (cairo_surface_t *surface,
+ const char *mime_type,
+ const unsigned char *data,
+ unsigned int length,
+ cairo_destroy_func_t destroy,
+ void *closure);
+
cairo_public void
cairo_surface_get_font_options (cairo_surface_t *surface,
cairo_font_options_t *options);
diff --git a/src/cairoint.h b/src/cairoint.h
index 3e11604e..5a2a909c 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,
@@ -263,6 +264,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
@@ -322,9 +330,16 @@ _cairo_user_data_array_set_data (cairo_user_data_array_t *array,
void *user_data,
cairo_destroy_func_t destroy);
+#define _CAIRO_HASH_INIT_VALUE 5381
+
cairo_private unsigned long
_cairo_hash_string (const char *c);
+cairo_private unsigned long
+_cairo_hash_bytes (unsigned long hash,
+ const void *bytes,
+ unsigned int length);
+
/*
* A #cairo_unscaled_font_t is just an opaque handle we use in the
* glyph cache.
@@ -339,6 +354,7 @@ typedef struct _cairo_scaled_glyph {
cairo_cache_entry_t cache_entry; /* hash is glyph index */
cairo_scaled_font_t *scaled_font; /* font the glyph lives in */
cairo_text_extents_t metrics; /* user-space metrics */
+ cairo_text_extents_t fs_metrics; /* font-space metrics */
cairo_box_t bbox; /* device-space bounds */
int16_t x_advance; /* device-space rounded X advance */
int16_t y_advance; /* device-space rounded Y advance */
@@ -618,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);
@@ -726,13 +756,15 @@ struct _cairo_surface_backend {
cairo_warn cairo_int_status_t
(*paint) (void *surface,
cairo_operator_t op,
- const cairo_pattern_t *source);
+ const cairo_pattern_t *source,
+ cairo_rectangle_int_t *extents);
cairo_warn cairo_int_status_t
(*mask) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- const cairo_pattern_t *mask);
+ const cairo_pattern_t *mask,
+ cairo_rectangle_int_t *extents);
cairo_warn cairo_int_status_t
(*stroke) (void *surface,
@@ -743,7 +775,8 @@ struct _cairo_surface_backend {
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
- cairo_antialias_t antialias);
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents);
cairo_warn cairo_int_status_t
(*fill) (void *surface,
@@ -752,7 +785,8 @@ struct _cairo_surface_backend {
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
- cairo_antialias_t antialias);
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents);
cairo_warn cairo_int_status_t
(*show_glyphs) (void *surface,
@@ -761,7 +795,8 @@ struct _cairo_surface_backend {
cairo_glyph_t *glyphs,
int num_glyphs,
cairo_scaled_font_t *scaled_font,
- int *remaining_glyphs);
+ int *remaining_glyphs,
+ cairo_rectangle_int_t *extents);
cairo_surface_t *
(*snapshot) (void *surface);
@@ -788,7 +823,8 @@ struct _cairo_surface_backend {
cairo_matrix_t *stroke_ctm,
cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
- cairo_antialias_t stroke_antialias);
+ cairo_antialias_t stroke_antialias,
+ cairo_rectangle_int_t *extents);
cairo_surface_t *
(*create_solid_pattern_surface)
@@ -809,7 +845,8 @@ struct _cairo_surface_backend {
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
- cairo_scaled_font_t *scaled_font);
+ cairo_scaled_font_t *scaled_font,
+ cairo_rectangle_int_t *extents);
};
#include "cairo-surface-private.h"
@@ -820,9 +857,6 @@ struct _cairo_image_surface {
pixman_format_code_t pixman_format;
cairo_format_t format;
unsigned char *data;
- cairo_bool_t owns_data;
- cairo_bool_t has_clip;
- cairo_image_transparency_t transparency;
int width;
int height;
@@ -830,6 +864,10 @@ struct _cairo_image_surface {
int depth;
pixman_image_t *pixman_image;
+
+ unsigned owns_data : 1;
+ unsigned has_clip : 1;
+ unsigned transparency : 2;
};
extern const cairo_private cairo_surface_backend_t _cairo_image_surface_backend;
@@ -926,7 +964,8 @@ typedef struct _cairo_traps {
int num_traps;
int traps_size;
cairo_trapezoid_t *traps;
- cairo_trapezoid_t traps_embedded[1];
+ /* embed enough storage for a stroked rectangle */
+ cairo_trapezoid_t traps_embedded[4];
cairo_bool_t has_limits;
cairo_box_t limits;
@@ -1122,7 +1161,7 @@ _cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate,
double *x2, double *y2,
cairo_bool_t *is_tight);
-cairo_private cairo_status_t
+cairo_private void
_cairo_gstate_path_extents (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double *x1, double *y1,
@@ -1175,7 +1214,7 @@ _cairo_gstate_in_stroke (cairo_gstate_t *gstate,
double y,
cairo_bool_t *inside_ret);
-cairo_private cairo_status_t
+cairo_private void
_cairo_gstate_in_fill (cairo_gstate_t *gstate,
cairo_path_fixed_t *path,
double x,
@@ -1282,6 +1321,13 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
int num_glyphs,
cairo_path_fixed_t *path);
+cairo_private cairo_status_t
+_cairo_gstate_set_antialias (cairo_gstate_t *gstate,
+ cairo_antialias_t antialias);
+
+cairo_private cairo_antialias_t
+_cairo_gstate_get_antialias (cairo_gstate_t *gstate);
+
cairo_private cairo_bool_t
_cairo_operator_bounded_by_mask (cairo_operator_t op) cairo_pure;
@@ -1393,6 +1439,12 @@ _cairo_validate_text_clusters (const char *utf8,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags);
+cairo_private cairo_status_t
+_cairo_intern_string (const char **str_inout, int len);
+
+cairo_private void
+_cairo_intern_string_reset_static_data (void);
+
/* cairo-path-fixed.c */
cairo_private void
_cairo_path_fixed_init (cairo_path_fixed_t *path);
@@ -1497,7 +1549,11 @@ _cairo_path_fixed_append (cairo_path_fixed_t *path,
const cairo_path_fixed_t *other,
cairo_direction_t dir);
-cairo_private cairo_status_t
+cairo_private void
+_cairo_path_fixed_approximate_extents (cairo_path_fixed_t *path,
+ cairo_rectangle_int_t *extents);
+
+cairo_private void
_cairo_path_fixed_bounds (cairo_path_fixed_t *path,
double *x1, double *y1,
double *x2, double *y2,
@@ -1518,6 +1574,18 @@ 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,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ double x,
+ double y,
+ cairo_bool_t *is_inside);
+
/* cairo-path-fill.c */
cairo_private cairo_status_t
_cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path,
@@ -1662,6 +1730,11 @@ cairo_private cairo_surface_t *
_cairo_surface_create_in_error (cairo_status_t status);
cairo_private cairo_status_t
+_cairo_surface_copy_mime_data (cairo_surface_t *dst,
+ cairo_surface_t *src,
+ const char *mime_type);
+
+cairo_private cairo_status_t
_cairo_surface_set_error (cairo_surface_t *surface,
cairo_status_t status);
@@ -1743,13 +1816,15 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface,
cairo_private cairo_status_t
_cairo_surface_paint (cairo_surface_t *surface,
cairo_operator_t op,
- const cairo_pattern_t *source);
+ const cairo_pattern_t *source,
+ cairo_rectangle_int_t *extents);
cairo_private cairo_status_t
_cairo_surface_mask (cairo_surface_t *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- const cairo_pattern_t *mask);
+ const cairo_pattern_t *mask,
+ cairo_rectangle_int_t *extents);
cairo_private cairo_status_t
_cairo_surface_fill_stroke (cairo_surface_t *surface,
@@ -1765,7 +1840,8 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface,
cairo_matrix_t *stroke_ctm,
cairo_matrix_t *stroke_ctm_inverse,
double stroke_tolerance,
- cairo_antialias_t stroke_antialias);
+ cairo_antialias_t stroke_antialias,
+ cairo_rectangle_int_t *extents);
cairo_private cairo_status_t
_cairo_surface_stroke (cairo_surface_t *surface,
@@ -1776,7 +1852,8 @@ _cairo_surface_stroke (cairo_surface_t *surface,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
- cairo_antialias_t antialias);
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents);
cairo_private cairo_status_t
_cairo_surface_fill (cairo_surface_t *surface,
@@ -1785,7 +1862,8 @@ _cairo_surface_fill (cairo_surface_t *surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
- cairo_antialias_t antialias);
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents);
cairo_private cairo_status_t
_cairo_surface_show_text_glyphs (cairo_surface_t *surface,
@@ -1798,7 +1876,8 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
- cairo_scaled_font_t *scaled_font);
+ cairo_scaled_font_t *scaled_font,
+ cairo_rectangle_int_t *extents);
cairo_private cairo_status_t
_cairo_surface_composite_trapezoids (cairo_operator_t op,
@@ -1814,6 +1893,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,
@@ -2082,7 +2177,7 @@ cairo_private void
_cairo_pen_init_empty (cairo_pen_t *pen);
cairo_private cairo_status_t
-_cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other);
+_cairo_pen_init_copy (cairo_pen_t *pen, const cairo_pen_t *other);
cairo_private void
_cairo_pen_fini (cairo_pen_t *pen);
@@ -2097,21 +2192,40 @@ _cairo_pen_add_points_for_slopes (cairo_pen_t *pen,
cairo_point_t *c,
cairo_point_t *d);
-cairo_private void
-_cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen,
- cairo_slope_t *slope,
- int *active);
+cairo_private int
+_cairo_pen_find_active_cw_vertex_index (const cairo_pen_t *pen,
+ const cairo_slope_t *slope);
-cairo_private void
-_cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen,
- cairo_slope_t *slope,
- int *active);
+cairo_private int
+_cairo_pen_find_active_ccw_vertex_index (const cairo_pen_t *pen,
+ const cairo_slope_t *slope);
+
+typedef struct _cairo_pen_stroke_spline {
+ cairo_pen_t pen;
+ cairo_spline_t spline;
+ cairo_polygon_t polygon;
+ cairo_point_t last_point;
+ cairo_point_t forward_hull_point;
+ cairo_point_t backward_hull_point;
+ int forward_vertex;
+ int backward_vertex;
+} cairo_pen_stroke_spline_t;
+
+cairo_private cairo_int_status_t
+_cairo_pen_stroke_spline_init (cairo_pen_stroke_spline_t *stroker,
+ const cairo_pen_t *pen,
+ const cairo_point_t *a,
+ const cairo_point_t *b,
+ const cairo_point_t *c,
+ const cairo_point_t *d);
cairo_private cairo_status_t
-_cairo_pen_stroke_spline (cairo_pen_t *pen,
- cairo_spline_t *spline,
- double tolerance,
- cairo_traps_t *traps);
+_cairo_pen_stroke_spline (cairo_pen_stroke_spline_t *pen,
+ double tolerance,
+ cairo_traps_t *traps);
+
+cairo_private void
+_cairo_pen_stroke_spline_fini (cairo_pen_stroke_spline_t *stroker);
/* cairo-polygon.c */
cairo_private void
@@ -2121,6 +2235,12 @@ cairo_private void
_cairo_polygon_fini (cairo_polygon_t *polygon);
cairo_private void
+_cairo_polygon_add_edge (cairo_polygon_t *polygon,
+ const cairo_point_t *p1,
+ const cairo_point_t *p2,
+ int dir);
+
+cairo_private void
_cairo_polygon_move_to (cairo_polygon_t *polygon,
const cairo_point_t *point);
@@ -2134,14 +2254,16 @@ _cairo_polygon_close (cairo_polygon_t *polygon);
#define _cairo_polygon_status(P) (P)->status
/* cairo-spline.c */
-cairo_private cairo_int_status_t
+typedef void (*cairo_add_point_func_t) (void*, const cairo_point_t *);
+
+cairo_private cairo_bool_t
_cairo_spline_init (cairo_spline_t *spline,
- const cairo_point_t *a,
- const cairo_point_t *b,
- const cairo_point_t *c,
- const cairo_point_t *d);
+ cairo_add_point_func_t add_point_func,
+ void *closure,
+ const cairo_point_t *a, const cairo_point_t *b,
+ const cairo_point_t *c, const cairo_point_t *d);
-cairo_private cairo_status_t
+cairo_private void
_cairo_spline_decompose (cairo_spline_t *spline, double tolerance);
cairo_private void
@@ -2193,7 +2315,9 @@ _cairo_matrix_transformed_circle_major_axis(cairo_matrix_t *matrix, double radiu
cairo_private void
_cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix,
- pixman_transform_t *pixman_transform);
+ pixman_transform_t *pixman_transform,
+ double xc,
+ double yc);
/* cairo-traps.c */
cairo_private void
@@ -2363,15 +2487,18 @@ cairo_private cairo_status_t
_cairo_pattern_get_extents (const cairo_pattern_t *pattern,
cairo_rectangle_int_t *extents);
-cairo_private void
-_cairo_pattern_reset_static_data (void);
+cairo_private unsigned long
+_cairo_pattern_hash (const cairo_pattern_t *pattern);
-cairo_private cairo_status_t
-_cairo_gstate_set_antialias (cairo_gstate_t *gstate,
- cairo_antialias_t antialias);
+cairo_private unsigned long
+_cairo_pattern_size (const cairo_pattern_t *pattern);
-cairo_private cairo_antialias_t
-_cairo_gstate_get_antialias (cairo_gstate_t *gstate);
+cairo_private cairo_bool_t
+_cairo_pattern_equal (const cairo_pattern_t *a,
+ const cairo_pattern_t *b);
+
+cairo_private void
+_cairo_pattern_reset_static_data (void);
/* cairo-region.c */
@@ -2435,6 +2562,7 @@ slim_hidden_proto (cairo_font_options_set_hint_metrics);
slim_hidden_proto (cairo_font_options_set_hint_style);
slim_hidden_proto (cairo_font_options_set_subpixel_order);
slim_hidden_proto (cairo_font_options_status);
+slim_hidden_proto (cairo_format_stride_for_width);
slim_hidden_proto (cairo_get_current_point);
slim_hidden_proto (cairo_get_line_width);
slim_hidden_proto (cairo_get_matrix);
@@ -2448,7 +2576,6 @@ slim_hidden_proto (cairo_image_surface_get_data);
slim_hidden_proto (cairo_image_surface_get_height);
slim_hidden_proto (cairo_image_surface_get_stride);
slim_hidden_proto (cairo_image_surface_get_width);
-slim_hidden_proto (cairo_format_stride_for_width);
slim_hidden_proto (cairo_line_to);
slim_hidden_proto (cairo_mask);
slim_hidden_proto (cairo_matrix_init);
@@ -2465,19 +2592,15 @@ slim_hidden_proto (cairo_matrix_translate);
slim_hidden_proto (cairo_move_to);
slim_hidden_proto (cairo_new_path);
slim_hidden_proto (cairo_paint);
-slim_hidden_proto (cairo_path_extents);
slim_hidden_proto (cairo_pattern_create_for_surface);
slim_hidden_proto (cairo_pattern_create_rgb);
slim_hidden_proto (cairo_pattern_create_rgba);
slim_hidden_proto (cairo_pattern_destroy);
slim_hidden_proto (cairo_pattern_get_extend);
-slim_hidden_proto (cairo_pattern_get_type);
slim_hidden_proto_no_warn (cairo_pattern_reference);
slim_hidden_proto (cairo_pattern_set_matrix);
slim_hidden_proto (cairo_pattern_status);
slim_hidden_proto (cairo_pop_group);
-slim_hidden_proto (cairo_pop_group_to_source);
-slim_hidden_proto (cairo_push_group);
slim_hidden_proto (cairo_push_group_with_content);
slim_hidden_proto (cairo_rel_line_to);
slim_hidden_proto (cairo_restore);
@@ -2490,23 +2613,24 @@ slim_hidden_proto (cairo_scaled_font_get_ctm);
slim_hidden_proto (cairo_scaled_font_get_font_face);
slim_hidden_proto (cairo_scaled_font_get_font_matrix);
slim_hidden_proto (cairo_scaled_font_get_font_options);
-slim_hidden_proto (cairo_scaled_font_text_to_glyphs);
slim_hidden_proto (cairo_scaled_font_glyph_extents);
slim_hidden_proto_no_warn (cairo_scaled_font_reference);
slim_hidden_proto (cairo_scaled_font_status);
-slim_hidden_proto (cairo_set_font_size);
+slim_hidden_proto (cairo_scaled_font_text_to_glyphs);
slim_hidden_proto (cairo_set_font_options);
+slim_hidden_proto (cairo_set_font_size);
slim_hidden_proto (cairo_set_line_cap);
slim_hidden_proto (cairo_set_line_join);
slim_hidden_proto (cairo_set_line_width);
slim_hidden_proto (cairo_set_matrix);
slim_hidden_proto (cairo_set_operator);
slim_hidden_proto (cairo_set_source);
-slim_hidden_proto (cairo_set_source);
slim_hidden_proto (cairo_set_source_surface);
+slim_hidden_proto (cairo_set_tolerance);
slim_hidden_proto (cairo_status);
slim_hidden_proto (cairo_stroke);
slim_hidden_proto (cairo_stroke_preserve);
+slim_hidden_proto (cairo_surface_copy_page);
slim_hidden_proto (cairo_surface_create_similar);
slim_hidden_proto (cairo_surface_destroy);
slim_hidden_proto (cairo_surface_finish);
@@ -2514,15 +2638,17 @@ slim_hidden_proto (cairo_surface_flush);
slim_hidden_proto (cairo_surface_get_content);
slim_hidden_proto (cairo_surface_get_device_offset);
slim_hidden_proto (cairo_surface_get_font_options);
+slim_hidden_proto (cairo_surface_get_mime_data);
slim_hidden_proto (cairo_surface_get_type);
slim_hidden_proto (cairo_surface_has_show_text_glyphs);
slim_hidden_proto (cairo_surface_mark_dirty_rectangle);
slim_hidden_proto_no_warn (cairo_surface_reference);
slim_hidden_proto (cairo_surface_set_device_offset);
slim_hidden_proto (cairo_surface_set_fallback_resolution);
-slim_hidden_proto (cairo_surface_copy_page);
+slim_hidden_proto (cairo_surface_set_mime_data);
slim_hidden_proto (cairo_surface_show_page);
slim_hidden_proto (cairo_surface_status);
+slim_hidden_proto (cairo_surface_write_to_png_stream);
slim_hidden_proto (cairo_text_cluster_allocate);
slim_hidden_proto (cairo_text_cluster_free);
slim_hidden_proto (cairo_toy_font_face_create);
diff --git a/src/check-doc-syntax.sh b/src/check-doc-syntax.sh
index abf526da..a5c84628 100755
--- a/src/check-doc-syntax.sh
+++ b/src/check-doc-syntax.sh
@@ -64,7 +64,7 @@ if echo $FILES | xargs grep . /dev/null | sed -e '/<programlisting>/,/<\/program
echo " '$func_regexp'"
fi >&2
-note_regexp='NOTE'
+note_regexp='\<NOTE\>'
if echo $FILES | xargs grep "$note_regexp" /dev/null; then
stat=1
echo Error: some source files contain the string 'NOTE'.
diff --git a/src/test-fallback-surface.c b/src/test-fallback-surface.c
index 883941df..8acd91ee 100644
--- a/src/test-fallback-surface.c
+++ b/src/test-fallback-surface.c
@@ -79,7 +79,7 @@ _cairo_test_fallback_surface_create (cairo_content_t content,
return backing;
surface = malloc (sizeof (test_fallback_surface_t));
- if (surface == NULL) {
+ if (unlikely (surface == NULL)) {
cairo_surface_destroy (backing);
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
@@ -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 f19cbd69..42bf6b0c 100644
--- a/src/test-meta-surface.c
+++ b/src/test-meta-surface.c
@@ -77,7 +77,7 @@ _cairo_test_meta_surface_create (cairo_content_t content,
cairo_status_t status;
surface = malloc (sizeof (test_meta_surface_t));
- if (surface == NULL) {
+ if (unlikely (surface == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FAIL;
}
@@ -194,26 +194,28 @@ _test_meta_surface_get_extents (void *abstract_surface,
static cairo_int_status_t
_test_meta_surface_paint (void *abstract_surface,
cairo_operator_t op,
- const cairo_pattern_t *source)
+ const cairo_pattern_t *source,
+ cairo_rectangle_int_t *extents)
{
test_meta_surface_t *surface = abstract_surface;
surface->image_reflects_meta = FALSE;
- return _cairo_surface_paint (surface->meta, op, source);
+ return _cairo_surface_paint (surface->meta, op, source, extents);
}
static cairo_int_status_t
_test_meta_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- const cairo_pattern_t *mask)
+ const cairo_pattern_t *mask,
+ cairo_rectangle_int_t *extents)
{
test_meta_surface_t *surface = abstract_surface;
surface->image_reflects_meta = FALSE;
- return _cairo_surface_mask (surface->meta, op, source, mask);
+ return _cairo_surface_mask (surface->meta, op, source, mask, extents);
}
static cairo_int_status_t
@@ -225,7 +227,8 @@ _test_meta_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
test_meta_surface_t *surface = abstract_surface;
@@ -234,7 +237,7 @@ _test_meta_surface_stroke (void *abstract_surface,
return _cairo_surface_stroke (surface->meta, op, source,
path, style,
ctm, ctm_inverse,
- tolerance, antialias);
+ tolerance, antialias, extents);
}
static cairo_int_status_t
@@ -244,7 +247,8 @@ _test_meta_surface_fill (void *abstract_surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
test_meta_surface_t *surface = abstract_surface;
@@ -252,7 +256,7 @@ _test_meta_surface_fill (void *abstract_surface,
return _cairo_surface_fill (surface->meta, op, source,
path, fill_rule,
- tolerance, antialias);
+ tolerance, antialias, extents);
}
static cairo_bool_t
@@ -274,7 +278,8 @@ _test_meta_surface_show_text_glyphs (void *abstract_surface,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
- cairo_scaled_font_t *scaled_font)
+ cairo_scaled_font_t *scaled_font,
+ cairo_rectangle_int_t *extents)
{
test_meta_surface_t *surface = abstract_surface;
@@ -284,7 +289,7 @@ _test_meta_surface_show_text_glyphs (void *abstract_surface,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters, cluster_flags,
- scaled_font);
+ scaled_font, extents);
}
@@ -308,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 ba80a107..4c566470 100644
--- a/src/test-paginated-surface.c
+++ b/src/test-paginated-surface.c
@@ -80,7 +80,7 @@ _cairo_test_paginated_surface_create_for_data (unsigned char *data,
return target;
surface = malloc (sizeof (test_paginated_surface_t));
- if (surface == NULL) {
+ if (unlikely (surface == NULL)) {
cairo_surface_destroy (target);
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
}
@@ -169,28 +169,30 @@ _test_paginated_surface_get_extents (void *abstract_surface,
static cairo_int_status_t
_test_paginated_surface_paint (void *abstract_surface,
cairo_operator_t op,
- const cairo_pattern_t *source)
+ const cairo_pattern_t *source,
+ cairo_rectangle_int_t *extents)
{
test_paginated_surface_t *surface = abstract_surface;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return CAIRO_STATUS_SUCCESS;
- return _cairo_surface_paint (surface->target, op, source);
+ return _cairo_surface_paint (surface->target, op, source, extents);
}
static cairo_int_status_t
_test_paginated_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- const cairo_pattern_t *mask)
+ const cairo_pattern_t *mask,
+ cairo_rectangle_int_t *extents)
{
test_paginated_surface_t *surface = abstract_surface;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return CAIRO_STATUS_SUCCESS;
- return _cairo_surface_mask (surface->target, op, source, mask);
+ return _cairo_surface_mask (surface->target, op, source, mask, extents);
}
static cairo_int_status_t
@@ -202,7 +204,8 @@ _test_paginated_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm,
cairo_matrix_t *ctm_inverse,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
test_paginated_surface_t *surface = abstract_surface;
@@ -212,7 +215,7 @@ _test_paginated_surface_stroke (void *abstract_surface,
return _cairo_surface_stroke (surface->target, op, source,
path, style,
ctm, ctm_inverse,
- tolerance, antialias);
+ tolerance, antialias, extents);
}
static cairo_int_status_t
@@ -222,7 +225,8 @@ _test_paginated_surface_fill (void *abstract_surface,
cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
double tolerance,
- cairo_antialias_t antialias)
+ cairo_antialias_t antialias,
+ cairo_rectangle_int_t *extents)
{
test_paginated_surface_t *surface = abstract_surface;
@@ -231,7 +235,7 @@ _test_paginated_surface_fill (void *abstract_surface,
return _cairo_surface_fill (surface->target, op, source,
path, fill_rule,
- tolerance, antialias);
+ tolerance, antialias, extents);
}
static cairo_bool_t
@@ -253,7 +257,8 @@ _test_paginated_surface_show_text_glyphs (void *abstract_surface,
const cairo_text_cluster_t *clusters,
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
- cairo_scaled_font_t *scaled_font)
+ cairo_scaled_font_t *scaled_font,
+ cairo_rectangle_int_t *extents)
{
test_paginated_surface_t *surface = abstract_surface;
@@ -264,7 +269,7 @@ _test_paginated_surface_show_text_glyphs (void *abstract_surface,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters, cluster_flags,
- scaled_font);
+ scaled_font, extents);
}
@@ -293,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,
diff --git a/test/Makefile.am b/test/Makefile.am
index 21976de6..de9f9c47 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -13,8 +13,10 @@ test_sources = \
big-line.c \
big-trap.c \
bilevel-image.c \
+ caps.c \
caps-joins.c \
caps-joins-alpha.c \
+ caps-joins-curve.c \
caps-sub-paths.c \
clip-all.c \
clip-empty.c \
@@ -51,6 +53,8 @@ test_sources = \
device-offset-positive.c \
device-offset-scale.c \
extend-pad.c \
+ extend-pad-border.c \
+ extend-pad-similar.c \
extend-reflect.c \
extend-reflect-similar.c \
extend-repeat.c \
@@ -106,6 +110,7 @@ test_sources = \
mask-transformed-image.c \
mask-transformed-similar.c \
meta-surface-pattern.c \
+ mime-data.c \
miter-precision.c \
move-to-show-surface.c \
new-sub-path.c \
@@ -138,6 +143,8 @@ test_sources = \
rgb24-ignore-alpha.c \
rotate-image-surface-paint.c \
scale-down-source-surface-paint.c \
+ scale-offset-image.c \
+ scale-offset-similar.c \
scale-source-surface-paint.c \
stroke-ctm-caps.c \
stroke-image.c \
@@ -207,13 +214,18 @@ test_sources += ft-text-vertical-layout-type3.c
test_sources += ft-text-antialias-none.c
endif
-# Need to add win32-surface-source, quartz-surface-source
+# Need to add quartz-surface-source
+if CAIRO_HAS_QUARTZ_SURFACE
+test_sources += quartz-surface-source.c
+endif
+
if CAIRO_HAS_GLITZ_SURFACE
test_sources += glitz-surface-source.c
endif
if CAIRO_HAS_PDF_SURFACE
test_sources += pdf-features.c
+test_sources += pdf-mime-data.c
test_sources += pdf-surface-source.c
endif
@@ -279,12 +291,19 @@ cairo_test_suite_LDADD = \
cairo_test_suite_DEPENDENCIES = \
$(top_builddir)/test/pdiff/libpdiff.la \
$(top_builddir)/boilerplate/libcairoboilerplate.la \
- $(top_builddir)/src/libcairo.la \
+ $(top_builddir)/src/libcairo.la
+if BUILD_ANY2PPM
+cairo_test_suite_DEPENDENCIES += \
any2ppm
+endif
if HAVE_PTHREAD
cairo_test_suite_LDADD += -lpthread
endif
+if CAIRO_HAS_SDL_SURFACE
+cairo_test_suite_LDADD += $(sdl_LIBS)
+endif
+
BUILT_SOURCES += cairo-test-constructors.c
noinst_SCRIPTS = make-cairo-test-constructors.pl
EXTRA_DIST += $(BUILT_SOURCES) $(noinst_SCRIPTS) COPYING
@@ -309,13 +328,16 @@ REFERENCE_IMAGES = \
bilevel-image.ref.png \
bitmap-font.ref.png \
bitmap-font.rgb24.ref.png \
+ caps.ref.png \
+ caps.ps.ref.png \
caps-joins-alpha.quartz.ref.png \
caps-joins-alpha.ref.png \
caps-joins-alpha.svg12.ref.png \
caps-joins-alpha.svg11.ref.png \
+ caps-joins-curve.ref.png \
+ caps-joins-curve.ps.ref.png \
caps-joins.ref.png \
- caps-joins.ps2.ref.png \
- caps-joins.ps3.ref.png \
+ caps-joins.ps.ref.png \
caps-sub-paths.ref.png \
clip-all.ref.png \
clip-empty.ref.png \
@@ -438,6 +460,8 @@ REFERENCE_IMAGES = \
device-offset.rgb24.ref.png \
device-offset-scale.ref.png \
extend-pad.ref.png \
+ extend-pad-border.ref.png \
+ extend-pad-similar.ref.png \
extend-reflect.ref.png \
extend-reflect-similar.ref.png \
extend-reflect-similar.ps2.ref.png \
@@ -687,6 +711,10 @@ REFERENCE_IMAGES = \
meta-surface-pattern.svg11.rgb24.ref.png \
meta-surface-pattern.svg12.argb32.ref.png \
meta-surface-pattern.svg12.rgb24.ref.png \
+ mime-data.ref.png \
+ mime-data.ps.ref.png \
+ mime-data.pdf.ref.png \
+ mime-data.svg.ref.png \
miter-precision.ref.png \
miter-precision.ps2.ref.png \
miter-precision.ps3.ref.png \
@@ -800,6 +828,10 @@ REFERENCE_IMAGES = \
rotate-image-surface-paint.svg12.ref.png \
rotate-image-surface-paint.svg11.ref.png \
scale-down-source-surface-paint.ref.png \
+ scale-offset-image.ref.png \
+ scale-offset-image.ps.ref.png \
+ scale-offset-similar.ref.png \
+ scale-offset-similar.ps.ref.png \
scale-source-surface-paint.pdf.argb32.ref.png \
scale-source-surface-paint.ref.png \
scale-source-surface-paint.rgb24.ref.png \
@@ -903,8 +935,7 @@ REFERENCE_IMAGES = \
surface-pattern-scale-up.ps2.ref.png \
surface-pattern-scale-up.ps3.ref.png \
surface-pattern-scale-up.ref.png \
- surface-pattern.svg12.ref.png \
- surface-pattern.svg11.ref.png \
+ surface-pattern.svg.ref.png \
svg-surface-source.ref.png \
text-antialias-gray.ref.png \
text-antialias-gray.quartz.ref.png \
@@ -953,6 +984,7 @@ REFERENCE_IMAGES = \
trap-clip.ps2.argb32.ref.png \
trap-clip.ps2.rgb24.ref.png \
twin.ref.png \
+ twin.pdf.ref.png \
twin.ps2.ref.png \
twin.ps3.ref.png \
twin.svg11.ref.png \
@@ -993,7 +1025,11 @@ REFERENCE_IMAGES = \
EXTRA_DIST += \
6x13.pcf \
make-html.pl \
+jpeg.jpg \
+png.png \
+romedalen.jpg \
romedalen.png \
+scarab.jpg \
surface-source.c \
$(REFERENCE_IMAGES)
@@ -1120,6 +1156,7 @@ AM_CPPFLAGS = \
-I$(srcdir) \
-I$(srcdir)/pdiff \
-I$(top_srcdir)/boilerplate \
+ -I$(top_srcdir)/util/cairo-script \
-I$(top_srcdir)/src \
-I$(top_builddir)/src \
$(CAIRO_CFLAGS)
@@ -1133,6 +1170,9 @@ $(top_builddir)/src/libcairo.la:
$(top_builddir)/test/pdiff/libpdiff.la:
cd $(top_builddir)/test/pdiff && $(MAKE) $(AM_MAKEFLAGS) libpdiff.la
+$(top_builddir)/util/cairo-script/libcairo-script-interpreter.la: $(top_builddir)/src/libcairo.la
+ cd $(top_builddir)/util/cairo-script && $(MAKE) $(AM_MAKEFLAGS) libcairo-script-interpreter.la
+
EXTRA_PROGRAMS += imagediff png-flatten
imagediff_SOURCES = \
@@ -1140,7 +1180,8 @@ imagediff_SOURCES = \
buffer-diff.c \
buffer-diff.h
imagediff_LDADD = \
- $(top_builddir)/test/pdiff/libpdiff.la
+ $(top_builddir)/test/pdiff/libpdiff.la \
+ $(top_builddir)/src/libcairo.la
png_flatten_SOURCES = png-flatten.c
png_flatten_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD)
@@ -1150,7 +1191,7 @@ check_PROGRAMS += any2ppm
any2ppm_CFLAGS = $(POPPLER_CFLAGS) $(LIBRSVG_CFLAGS) $(LIBSPECTRE_CFLAGS)
# add LDADD, so poppler/librsvg uses "our" cairo
any2ppm_LDFLAGS = $(CAIRO_TEST_UNDEFINED_LDFLAGS)
-any2ppm_LDADD = $(top_builddir)/src/libcairo.la $(CAIRO_LDADD) $(POPPLER_LIBS) $(LIBRSVG_LIBS) $(LIBSPECTRE_LIBS)
+any2ppm_LDADD = $(top_builddir)/util/cairo-script/libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LDADD) $(POPPLER_LIBS) $(LIBRSVG_LIBS) $(LIBSPECTRE_LIBS)
endif
if CAIRO_CAN_TEST_PDF_SURFACE
@@ -1209,6 +1250,7 @@ CLEANFILES += \
pdf-surface-source.pdf \
ps-surface-source.ps \
pdf-features.pdf \
+ pdf-mime-data.out* \
ps-features.ps \
svg-clip.svg \
svg-surface.svg \
@@ -1222,12 +1264,12 @@ CLEANFILES += \
# reality of portability was raised and it became....
clean-local: clean-caches
rm -rf output
- -${FIND} . -name '*-out.*' -print | ${XARGS} ${RM}
+ -${FIND} . -name '*.out.*' -print | ${XARGS} ${RM}
-${FIND} . -name '*.log' -print | ${XARGS} ${RM}
-${FIND} . -name '*.[is]' -print | ${XARGS} ${RM}
clean-caches:
- -${FIND} . -name '*-pass.*' -print | ${XARGS} ${RM}
- -${FIND} . -name '*-fail.*' -print | ${XARGS} ${RM}
+ -${FIND} . -name '*.pass.*' -print | ${XARGS} ${RM}
+ -${FIND} . -name '*.fail.*' -print | ${XARGS} ${RM}
# The following definitions both should work.
#FAILED_TESTS = `grep -l '\<FAIL\>' $(test_sources:.c=.log) 2>/dev/null | sed -e 's/[.]log$$//' | xargs echo`
@@ -1267,6 +1309,7 @@ run:
$(MAKE) $(AM_MAKEFLAGS) check TESTS_ENVIRONMENT='$(TESTS_ENVIRONMENT) $(top_builddir)/libtool --mode=execute env $(TOOL)'
# Check tests under valgrind. Saves log to valgrind-log
+check-valgrind: MODE+=,foreground
check-valgrind:
$(MAKE) $(AM_MAKEFLAGS) check TESTS_ENVIRONMENT='$(TESTS_ENVIRONMENT) $(top_builddir)/libtool --mode=execute valgrind $(VALGRIND_FLAGS)' 2>&1 | tee valgrind-log
diff --git a/test/README b/test/README
index cb8a80e4..c039ebb2 100644
--- a/test/README
+++ b/test/README
@@ -125,7 +125,7 @@ Here are some of the relevant details:
X server that uses only software for all rendering. One such X
server is Xvfb which can be started like this:
- Xfvb -screen 0 1280x1024x24 -ac -nolisten tcp :2
+ Xvfb -screen 0 1280x1024x24 -ac -nolisten tcp :2
after which the test suite can be run against it like so:
diff --git a/test/any2ppm.c b/test/any2ppm.c
index 94450b2f..ae5de325 100644
--- a/test/any2ppm.c
+++ b/test/any2ppm.c
@@ -62,6 +62,7 @@
#include <string.h>
#include <cairo.h>
+#include <cairo-script-interpreter.h>
#if CAIRO_CAN_TEST_PDF_SURFACE
#include <poppler.h>
@@ -160,7 +161,24 @@ write_ppm (cairo_surface_t *surface, int fd)
int width, height, stride;
int i, j;
+ data = cairo_image_surface_get_data (surface);
+ height = cairo_image_surface_get_height (surface);
+ width = cairo_image_surface_get_width (surface);
+ stride = cairo_image_surface_get_stride (surface);
format = cairo_image_surface_get_format (surface);
+ if (format == CAIRO_FORMAT_ARGB32) {
+ /* see if we can convert to a standard ppm type and trim a few bytes */
+ const unsigned char *alpha = data;
+ for (j = height; j--; alpha += stride) {
+ for (i = 0; i < width; i++) {
+ if ((*(unsigned int *) (alpha+4*i) & 0xff000000) != 0xff000000)
+ goto done;
+ }
+ }
+ format = CAIRO_FORMAT_RGB24;
+ done: ;
+ }
+
switch (format) {
case CAIRO_FORMAT_ARGB32:
/* XXX need true alpha for svg */
@@ -177,33 +195,32 @@ write_ppm (cairo_surface_t *surface, int fd)
return "unhandled image format";
}
- data = cairo_image_surface_get_data (surface);
- height = cairo_image_surface_get_height (surface);
- width = cairo_image_surface_get_width (surface);
- stride = cairo_image_surface_get_stride (surface);
-
len = sprintf (buf, "%s %d %d 255\n", format_str, width, height);
for (j = 0; j < height; j++) {
- const unsigned char *row = data + stride * j;
+ const unsigned int *row = (unsigned int *) (data + stride * j);
switch ((int) format) {
case CAIRO_FORMAT_ARGB32:
len = _write (fd,
buf, sizeof (buf), len,
- row, 4 * width);
+ (unsigned char *) row, 4 * width);
break;
case CAIRO_FORMAT_RGB24:
for (i = 0; i < width; i++) {
+ unsigned char rgb[3];
+ unsigned int p = *row++;
+ rgb[0] = (p & 0xff0000) >> 16;
+ rgb[1] = (p & 0x00ff00) >> 8;
+ rgb[2] = (p & 0x0000ff) >> 0;
len = _write (fd,
buf, sizeof (buf), len,
- row, 3);
- row += 4;
+ rgb, 3);
}
break;
case CAIRO_FORMAT_A8:
len = _write (fd,
buf, sizeof (buf), len,
- row, width);
+ (unsigned char *) row, width);
break;
}
if (len < 0)
@@ -216,6 +233,63 @@ write_ppm (cairo_surface_t *surface, int fd)
return NULL;
}
+static cairo_surface_t *
+_create_image (void *closure,
+ double width, double height)
+ //csi_object_t *dictionary)
+{
+ cairo_surface_t **out = closure;
+ *out = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+ return cairo_surface_reference (*out);
+}
+
+static const char *
+_cairo_script_render_page (const char *filename,
+ cairo_surface_t **surface_out)
+{
+ cairo_script_interpreter_t *csi;
+ cairo_surface_t *surface = NULL;
+ cairo_status_t status;
+ const cairo_script_interpreter_hooks_t hooks = {
+ .closure = &surface,
+ .surface_create = _create_image,
+ };
+
+ csi = cairo_script_interpreter_create ();
+ cairo_script_interpreter_install_hooks (csi, &hooks);
+ cairo_script_interpreter_run (csi, filename);
+ status = cairo_script_interpreter_destroy (csi);
+ if (surface == NULL) {
+ return "cairo-script interpreter failed";
+ }
+
+ if (status == CAIRO_STATUS_SUCCESS)
+ status = cairo_surface_status (surface);
+ if (status) {
+ cairo_surface_destroy (surface);
+ return cairo_status_to_string (status);
+ }
+
+ *surface_out = surface;
+ return NULL;
+}
+
+static const char *
+cs_convert (char **argv, int fd)
+{
+ const char *err;
+ cairo_surface_t *surface = NULL; /* silence compiler warning */
+
+ err = _cairo_script_render_page (argv[0], &surface);
+ if (err != NULL)
+ return err;
+
+ err = write_ppm (surface, fd);
+ cairo_surface_destroy (surface);
+
+ return err;
+}
+
#if CAIRO_CAN_TEST_PDF_SURFACE
/* adapted from pdf2png.c */
static const char *
@@ -449,6 +523,7 @@ convert (char **argv, int fd)
const char *type;
const char *(*func) (char **, int);
} converters[] = {
+ { "cs", cs_convert },
{ "pdf", pdf_convert },
{ "ps", ps_convert },
{ "svg", svg_convert },
diff --git a/test/cairo-test-runner.c b/test/cairo-test-runner.c
index 34a57257..aec90ff7 100644
--- a/test/cairo-test-runner.c
+++ b/test/cairo-test-runner.c
@@ -33,6 +33,10 @@
#undef CAIRO_VERSION_MICRO
#include "../cairo-version.h"
+#if CAIRO_HAS_SDL_SURFACE
+#include <SDL_main.h>
+#endif
+
#include <pixman.h> /* for version information */
#if HAVE_FORK && HAVE_WAITPID
@@ -51,6 +55,31 @@ typedef struct _cairo_test_list {
struct _cairo_test_list *next;
} cairo_test_list_t;
+typedef struct _cairo_test_runner {
+ cairo_test_context_t base;
+
+ unsigned int num_device_offsets;
+
+ int num_passed;
+ int num_xpassed;
+ int num_skipped;
+ int num_failed;
+ int num_xfailed;
+ int num_crashed;
+
+ cairo_test_list_t **crashes_per_target;
+ cairo_test_list_t **fails_per_target;
+ cairo_test_list_t **xpasses_per_target;
+
+ int *num_failed_per_target;
+ int *num_crashed_per_target;
+ int *num_xpassed_per_target;
+
+ cairo_bool_t foreground;
+ cairo_bool_t list_only;
+ cairo_bool_t full_test;
+} cairo_test_runner_t;
+
typedef enum {
GE,
GT
@@ -137,50 +166,54 @@ _cairo_test_wait (pid_t pid)
#endif
static cairo_test_status_t
-_cairo_test_runner_preamble (cairo_test_context_t *ctx)
+_cairo_test_runner_preamble (cairo_test_runner_t *runner,
+ cairo_test_context_t *ctx)
{
#if HAVE_FORK && HAVE_WAITPID
- pid_t pid;
+ if (! runner->foreground) {
+ pid_t pid;
- switch ((pid = fork ())) {
- case -1: /* error */
- return CAIRO_TEST_UNTESTED;
+ switch ((pid = fork ())) {
+ case -1: /* error */
+ return CAIRO_TEST_UNTESTED;
- case 0: /* child */
- exit (ctx->test->preamble (ctx));
+ case 0: /* child */
+ exit (ctx->test->preamble (ctx));
- default:
- return _cairo_test_wait (pid);
+ default:
+ return _cairo_test_wait (pid);
+ }
}
-#else
- return ctx->test->preamble (ctx);
#endif
+ return ctx->test->preamble (ctx);
}
static cairo_test_status_t
-_cairo_test_runner_draw (cairo_test_context_t *ctx,
+_cairo_test_runner_draw (cairo_test_runner_t *runner,
+ cairo_test_context_t *ctx,
const cairo_boilerplate_target_t *target,
cairo_bool_t similar,
int device_offset)
{
#if HAVE_FORK && HAVE_WAITPID
- pid_t pid;
+ if (! runner->foreground) {
+ pid_t pid;
- switch ((pid = fork ())) {
- case -1: /* error */
- return CAIRO_TEST_UNTESTED;
+ switch ((pid = fork ())) {
+ case -1: /* error */
+ return CAIRO_TEST_UNTESTED;
- case 0: /* child */
- exit (_cairo_test_context_run_for_target (ctx, target,
- similar, device_offset));
+ case 0: /* child */
+ exit (_cairo_test_context_run_for_target (ctx, target,
+ similar, device_offset));
- default:
- return _cairo_test_wait (pid);
+ default:
+ return _cairo_test_wait (pid);
+ }
}
-#else
+#endif
return _cairo_test_context_run_for_target (ctx, target,
similar, device_offset);
-#endif
}
static void
@@ -243,43 +276,20 @@ append_argv (int *argc, char ***argv, const char *str)
*argc += i;
}
-typedef struct _cairo_test_runner {
- cairo_test_context_t base;
-
- unsigned int num_device_offsets;
-
- int num_passed;
- int num_xpassed;
- int num_skipped;
- int num_failed;
- int num_xfailed;
- int num_crashed;
-
- cairo_test_list_t **crashes_per_target;
- cairo_test_list_t **fails_per_target;
- cairo_test_list_t **xpasses_per_target;
-
- int *num_failed_per_target;
- int *num_crashed_per_target;
- int *num_xpassed_per_target;
-
- cairo_bool_t list_only;
- cairo_bool_t full_test;
-} cairo_test_runner_t;
-
static void
usage (const char *argv0)
{
fprintf (stderr,
- "Usage: %s [-f] [test-names|keywords ...]\n"
+ "Usage: %s [-af] [test-names|keywords ...]\n"
" %s -l\n"
"\n"
"Run the cairo conformance test suite over the given tests (all by default)\n"
"The command-line arguments are interpreted as follows:\n"
"\n"
- " -l list only; just list selected test case names without executing\n"
- " -f full; run the full set of tests. By default the test suite\n"
+ " -a all; run the full set of tests. By default the test suite\n"
" skips similar surface and device offset testing.\n"
+ " -f foreground; do not fork\n"
+ " -l list only; just list selected test case names without executing\n"
"\n"
"If test names are given they are used as exact matches either to a specific\n"
"test case or to a keyword, so a command such as\n"
@@ -293,16 +303,19 @@ _parse_cmdline (cairo_test_runner_t *runner, int *argc, char **argv[])
int c;
while (1) {
- c = _cairo_getopt (*argc, *argv, ":l");
+ c = _cairo_getopt (*argc, *argv, ":afl");
if (c == -1)
break;
switch (c) {
+ case 'a':
+ runner->full_test = TRUE;
+ break;
case 'l':
runner->list_only = TRUE;
break;
case 'f':
- runner->full_test = TRUE;
+ runner->foreground = TRUE;
break;
default:
fprintf (stderr, "Internal error: unhandled option: %c\n", c);
@@ -585,6 +598,9 @@ main (int argc, char **argv)
if (strstr (env, "full")) {
runner.full_test = TRUE;
}
+ if (strstr (env, "foreground")) {
+ runner.foreground = TRUE;
+ }
}
_parse_cmdline (&runner, &argc, &argv);
@@ -706,7 +722,7 @@ main (int argc, char **argv)
sizeof (cairo_test_status_t) * ctx.num_targets);
if (ctx.test->preamble != NULL) {
- status = _cairo_test_runner_preamble (&ctx);
+ status = _cairo_test_runner_preamble (&runner, &ctx);
switch (status) {
case CAIRO_TEST_SUCCESS:
skipped = FALSE;
@@ -766,7 +782,7 @@ main (int argc, char **argv)
int similar;
for (similar = 0; similar <= has_similar; similar++) {
- status = _cairo_test_runner_draw (&ctx, target,
+ status = _cairo_test_runner_draw (&runner, &ctx, target,
similar, dev_offset);
switch (status) {
case CAIRO_TEST_SUCCESS:
diff --git a/test/cairo-test.c b/test/cairo-test.c
index 11ca650d..24d693dc 100644
--- a/test/cairo-test.c
+++ b/test/cairo-test.c
@@ -192,7 +192,7 @@ _cairo_test_init (cairo_test_context_t *ctx,
#ifdef HAVE_UNISTD_H
if (*fail_face == '\0' && isatty (2)) {
fail_face = "\033[41;37;1m";
- xfail_face = "\033[33;1m";
+ xfail_face = "\033[43;37;1m";
normal_face = "\033[m";
if (isatty (1))
print_fail_on_stdout = FALSE;
@@ -704,7 +704,9 @@ cairo_test_for_target (cairo_test_context_t *ctx,
xasprintf (&diff_path, "%s" CAIRO_TEST_DIFF_SUFFIX, base_path);
if (ctx->test->requirements != NULL) {
- const char *required = target->is_vector ? "target=raster" : "target=vector";
+ const char *required;
+
+ required = target->is_vector ? "target=raster" : "target=vector";
if (strstr (ctx->test->requirements, required) != NULL) {
cairo_test_log (ctx, "Error: Skipping for %s target %s\n",
target->is_vector ? "vector" : "raster",
@@ -712,6 +714,15 @@ cairo_test_for_target (cairo_test_context_t *ctx,
ret = CAIRO_TEST_UNTESTED;
goto UNWIND_STRINGS;
}
+
+ required = target->is_meta ? "target=!meta" : "target=meta";
+ if (strstr (ctx->test->requirements, required) != NULL) {
+ cairo_test_log (ctx, "Error: Skipping for %s target %s\n",
+ target->is_meta ? "meta" : "non-meta",
+ target->name);
+ ret = CAIRO_TEST_UNTESTED;
+ goto UNWIND_STRINGS;
+ }
}
width = ctx->test->width;
diff --git a/test/caps-joins-curve.c b/test/caps-joins-curve.c
new file mode 100644
index 00000000..1b2fc7f0
--- /dev/null
+++ b/test/caps-joins-curve.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright © 2008 Chris Wilson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Chris Wilson not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Chris Wilson makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairo-test.h"
+
+#define LINE_WIDTH 10.
+#define SIZE (5 * LINE_WIDTH)
+#define PAD (3 * LINE_WIDTH)
+
+static void
+make_path (cairo_t *cr)
+{
+ cairo_move_to (cr, 0, 0);
+ cairo_rel_curve_to (cr,
+ -SIZE/4, SIZE/3,
+ -SIZE/4, SIZE/3,
+ 0, SIZE);
+ cairo_rel_curve_to (cr,
+ SIZE/3, -SIZE/4,
+ SIZE/3, -SIZE/4,
+ SIZE, 0);
+ cairo_close_path (cr);
+
+ cairo_move_to (cr, 5 * LINE_WIDTH, 3 * LINE_WIDTH);
+ cairo_rel_curve_to (cr,
+ 0, -3 * LINE_WIDTH,
+ 0, -3 * LINE_WIDTH,
+ -3 * LINE_WIDTH, -3 * LINE_WIDTH);
+}
+
+static void
+draw_caps_joins (cairo_t *cr)
+{
+ cairo_save (cr);
+
+ cairo_translate (cr, PAD, PAD);
+
+ make_path (cr);
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
+ cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL);
+ cairo_stroke (cr);
+
+ cairo_translate (cr, SIZE + PAD, 0.);
+
+ make_path (cr);
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+ cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
+ cairo_stroke (cr);
+
+ cairo_translate (cr, SIZE + PAD, 0.);
+
+ make_path (cr);
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
+ cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
+ cairo_stroke (cr);
+
+ cairo_restore (cr);
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ /* We draw in the default black, so paint white first. */
+ cairo_save (cr);
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
+ cairo_paint (cr);
+ cairo_restore (cr);
+
+ cairo_set_line_width (cr, LINE_WIDTH);
+
+ draw_caps_joins (cr);
+
+ /* and reflect to generate the opposite vertex ordering */
+ cairo_translate (cr, 0, height);
+ cairo_scale (cr, 1, -1);
+
+ draw_caps_joins (cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (caps_joins_curve,
+ "Test caps and joins on curves",
+ "stroke cap join", /* keywords */
+ NULL, /* requirements */
+ 3 * (PAD + SIZE) + PAD,
+ 2 * (PAD + SIZE) + PAD,
+ NULL, draw)
+
diff --git a/test/caps-joins-curve.ps.ref.png b/test/caps-joins-curve.ps.ref.png
new file mode 100644
index 00000000..1f7e2000
--- /dev/null
+++ b/test/caps-joins-curve.ps.ref.png
Binary files differ
diff --git a/test/caps-joins-curve.ref.png b/test/caps-joins-curve.ref.png
new file mode 100644
index 00000000..9f763013
--- /dev/null
+++ b/test/caps-joins-curve.ref.png
Binary files differ
diff --git a/test/caps-joins.c b/test/caps-joins.c
index 5ec6a817..9d1c2a88 100644
--- a/test/caps-joins.c
+++ b/test/caps-joins.c
@@ -37,21 +37,15 @@ make_path (cairo_t *cr)
cairo_rel_line_to (cr, SIZE, 0.);
cairo_close_path (cr);
- cairo_move_to (cr, 2 * LINE_WIDTH, 0.);
- cairo_rel_line_to (cr, 3 * LINE_WIDTH, 0.);
- cairo_rel_line_to (cr, 0., 3 * LINE_WIDTH);
+ cairo_move_to (cr, 5 * LINE_WIDTH, 3 * LINE_WIDTH);
+ cairo_rel_line_to (cr, 0., -3 * LINE_WIDTH);
+ cairo_rel_line_to (cr, -3 * LINE_WIDTH, 0.);
}
-static cairo_test_status_t
-draw (cairo_t *cr, int width, int height)
+static void
+draw_caps_joins (cairo_t *cr)
{
- /* We draw in the default black, so paint white first. */
cairo_save (cr);
- cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
- cairo_paint (cr);
- cairo_restore (cr);
-
- cairo_set_line_width (cr, LINE_WIDTH);
cairo_translate (cr, PAD, PAD);
@@ -74,6 +68,28 @@ draw (cairo_t *cr, int width, int height)
cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
cairo_stroke (cr);
+ cairo_restore (cr);
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ /* We draw in the default black, so paint white first. */
+ cairo_save (cr);
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
+ cairo_paint (cr);
+ cairo_restore (cr);
+
+ cairo_set_line_width (cr, LINE_WIDTH);
+
+ draw_caps_joins (cr);
+
+ /* and reflect to generate the opposite vertex ordering */
+ cairo_translate (cr, 0, height);
+ cairo_scale (cr, 1, -1);
+
+ draw_caps_joins (cr);
+
return CAIRO_TEST_SUCCESS;
}
@@ -82,6 +98,6 @@ CAIRO_TEST (caps_joins,
"stroke", /* keywords */
NULL, /* requirements */
3 * (PAD + SIZE) + PAD,
- PAD + SIZE + PAD,
+ 2 * (PAD + SIZE) + PAD,
NULL, draw)
diff --git a/test/caps-joins.ps.ref.png b/test/caps-joins.ps.ref.png
new file mode 100644
index 00000000..e61aafce
--- /dev/null
+++ b/test/caps-joins.ps.ref.png
Binary files differ
diff --git a/test/caps-joins.ps2.ref.png b/test/caps-joins.ps2.ref.png
deleted file mode 100644
index 1d473ac7..00000000
--- a/test/caps-joins.ps2.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/caps-joins.ps3.ref.png b/test/caps-joins.ps3.ref.png
deleted file mode 100644
index 1d473ac7..00000000
--- a/test/caps-joins.ps3.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/caps-joins.ref.png b/test/caps-joins.ref.png
index 9297ac4d..d83f9561 100644
--- a/test/caps-joins.ref.png
+++ b/test/caps-joins.ref.png
Binary files differ
diff --git a/test/caps.c b/test/caps.c
new file mode 100644
index 00000000..7f561179
--- /dev/null
+++ b/test/caps.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright © 2008 Chris Wilson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Chris Wilson not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Chris Wilson makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairo-test.h"
+
+#define LINE_WIDTH 10.
+#define SIZE (5 * LINE_WIDTH)
+#define PAD (2 * LINE_WIDTH)
+
+static void
+make_path (cairo_t *cr)
+{
+ int i;
+
+ cairo_save (cr);
+ for (i = 0; i <= 3; i++) {
+ cairo_new_sub_path (cr);
+ cairo_move_to (cr, -SIZE / 2, 0.);
+ cairo_line_to (cr, SIZE / 2, 0.);
+ cairo_rotate (cr, M_PI / 4.);
+ }
+ cairo_restore (cr);
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_save (cr);
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
+ cairo_paint (cr);
+ cairo_restore (cr);
+
+ cairo_set_line_width (cr, LINE_WIDTH);
+ cairo_translate (cr, PAD + SIZE / 2., PAD + SIZE / 2.);
+
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
+ cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL);
+ make_path (cr);
+ cairo_stroke (cr);
+
+ cairo_translate (cr, 0, SIZE + PAD);
+
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+ cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
+ make_path (cr);
+ cairo_stroke (cr);
+
+ cairo_translate (cr, 0, SIZE + PAD);
+
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE);
+ cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
+ make_path (cr);
+ cairo_stroke (cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (caps,
+ "Test caps",
+ "stroke caps", /* keywords */
+ NULL, /* requirements */
+ PAD + SIZE + PAD,
+ 3 * (PAD + SIZE) + PAD,
+ NULL, draw)
+
diff --git a/test/caps.ps.ref.png b/test/caps.ps.ref.png
new file mode 100644
index 00000000..b1f4a72a
--- /dev/null
+++ b/test/caps.ps.ref.png
Binary files differ
diff --git a/test/caps.ref.png b/test/caps.ref.png
new file mode 100644
index 00000000..a46e0366
--- /dev/null
+++ b/test/caps.ref.png
Binary files differ
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 00000000..0d9938e7
--- /dev/null
+++ b/test/clip-fill-rule.pdf.argb32.ref.png
Binary files differ
diff --git a/test/clip-fill-rule.rgb24.ref.png b/test/clip-fill-rule.rgb24.ref.png
index a969e367..050bd666 100644
--- a/test/clip-fill-rule.rgb24.ref.png
+++ b/test/clip-fill-rule.rgb24.ref.png
Binary files differ
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 00000000..d21472dc
--- /dev/null
+++ b/test/clip-fill-rule.test-fallback.rgb24.ref.png
Binary files 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 00000000..d21472dc
--- /dev/null
+++ b/test/clip-fill-rule.test-paginated.rgb24.ref.png
Binary files 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 00000000..a969e367
--- /dev/null
+++ b/test/clip-fill-rule.xlib.rgb24.ref.png
Binary files differ
diff --git a/test/clip-nesting.pdf.argb32.ref.png b/test/clip-nesting.pdf.argb32.ref.png
new file mode 100644
index 00000000..78ae6e08
--- /dev/null
+++ b/test/clip-nesting.pdf.argb32.ref.png
Binary files differ
diff --git a/test/clip-nesting.rgb24.ref.png b/test/clip-nesting.rgb24.ref.png
index e2488f34..a014763d 100644
--- a/test/clip-nesting.rgb24.ref.png
+++ b/test/clip-nesting.rgb24.ref.png
Binary files 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 00000000..d087ab6c
--- /dev/null
+++ b/test/clip-nesting.test-fallback.rgb24.ref.png
Binary files 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 00000000..d087ab6c
--- /dev/null
+++ b/test/clip-nesting.test-paginated.rgb24.ref.png
Binary files differ
diff --git a/test/clip-nesting.xlib.rgb24.ref.png b/test/clip-nesting.xlib.rgb24.ref.png
new file mode 100644
index 00000000..e2488f34
--- /dev/null
+++ b/test/clip-nesting.xlib.rgb24.ref.png
Binary files differ
diff --git a/test/clip-operator.pdf.argb32.ref.png b/test/clip-operator.pdf.argb32.ref.png
index b3ee1437..e2fdc8d1 100644
--- a/test/clip-operator.pdf.argb32.ref.png
+++ b/test/clip-operator.pdf.argb32.ref.png
Binary files differ
diff --git a/test/clip-operator.pdf.rgb24.ref.png b/test/clip-operator.pdf.rgb24.ref.png
index b420f385..6590dd88 100644
--- a/test/clip-operator.pdf.rgb24.ref.png
+++ b/test/clip-operator.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/clip-operator.ps2.rgb24.ref.png b/test/clip-operator.ps2.rgb24.ref.png
index 6ed9fc45..52452993 100644
--- a/test/clip-operator.ps2.rgb24.ref.png
+++ b/test/clip-operator.ps2.rgb24.ref.png
Binary files differ
diff --git a/test/clip-operator.ps3.argb32.ref.png b/test/clip-operator.ps3.argb32.ref.png
new file mode 100644
index 00000000..cd207d92
--- /dev/null
+++ b/test/clip-operator.ps3.argb32.ref.png
Binary files differ
diff --git a/test/clip-operator.ps3.rgb24.ref.png b/test/clip-operator.ps3.rgb24.ref.png
index 6ed9fc45..52452993 100644
--- a/test/clip-operator.ps3.rgb24.ref.png
+++ b/test/clip-operator.ps3.rgb24.ref.png
Binary files differ
diff --git a/test/clip-operator.ref.png b/test/clip-operator.ref.png
index 4ea1842e..3a685f5e 100644
--- a/test/clip-operator.ref.png
+++ b/test/clip-operator.ref.png
Binary files differ
diff --git a/test/clip-operator.rgb24.ref.png b/test/clip-operator.rgb24.ref.png
index 7ab964c3..0a4d4c09 100644
--- a/test/clip-operator.rgb24.ref.png
+++ b/test/clip-operator.rgb24.ref.png
Binary files 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 00000000..f53e4921
--- /dev/null
+++ b/test/clip-operator.test-fallback.argb32.ref.png
Binary files 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 00000000..7579ae69
--- /dev/null
+++ b/test/clip-operator.test-fallback.rgb24.ref.png
Binary files 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 00000000..22e080a2
--- /dev/null
+++ b/test/clip-operator.test-paginated.argb32.ref.png
Binary files 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 00000000..4a05f7ba
--- /dev/null
+++ b/test/clip-operator.xlib-fallback.rgb24.ref.png
Binary files differ
diff --git a/test/clip-operator.xlib.ref.png b/test/clip-operator.xlib.ref.png
new file mode 100644
index 00000000..4ea1842e
--- /dev/null
+++ b/test/clip-operator.xlib.ref.png
Binary files differ
diff --git a/test/clip-operator.xlib.rgb24.ref.png b/test/clip-operator.xlib.rgb24.ref.png
new file mode 100644
index 00000000..7ab964c3
--- /dev/null
+++ b/test/clip-operator.xlib.rgb24.ref.png
Binary files differ
diff --git a/test/clip-twice.pdf.argb32.ref.png b/test/clip-twice.pdf.argb32.ref.png
new file mode 100644
index 00000000..2a7541fe
--- /dev/null
+++ b/test/clip-twice.pdf.argb32.ref.png
Binary files differ
diff --git a/test/clip-twice.ref.png b/test/clip-twice.ref.png
index 8dc86f30..4aafc9ac 100644
--- a/test/clip-twice.ref.png
+++ b/test/clip-twice.ref.png
Binary files differ
diff --git a/test/clip-twice.rgb24.ref.png b/test/clip-twice.rgb24.ref.png
index 3f1c013b..25c44ef7 100644
--- a/test/clip-twice.rgb24.ref.png
+++ b/test/clip-twice.rgb24.ref.png
Binary files 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 00000000..ba621807
--- /dev/null
+++ b/test/clip-twice.test-fallback.argb32.ref.png
Binary files 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 00000000..9cbdc4d4
--- /dev/null
+++ b/test/clip-twice.test-fallback.rgb24.ref.png
Binary files 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 00000000..ffd59aaf
--- /dev/null
+++ b/test/clip-twice.test-paginated.argb32.ref.png
Binary files 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 00000000..e3d0ae49
--- /dev/null
+++ b/test/clip-twice.test-paginated.rgb24.ref.png
Binary files differ
diff --git a/test/clip-twice.xlib.ref.png b/test/clip-twice.xlib.ref.png
new file mode 100644
index 00000000..8dc86f30
--- /dev/null
+++ b/test/clip-twice.xlib.ref.png
Binary files differ
diff --git a/test/clip-twice.xlib.rgb24.ref.png b/test/clip-twice.xlib.rgb24.ref.png
new file mode 100644
index 00000000..3f1c013b
--- /dev/null
+++ b/test/clip-twice.xlib.rgb24.ref.png
Binary files differ
diff --git a/test/clipped-group.pdf.argb32.ref.png b/test/clipped-group.pdf.argb32.ref.png
new file mode 100644
index 00000000..b9975e12
--- /dev/null
+++ b/test/clipped-group.pdf.argb32.ref.png
Binary files differ
diff --git a/test/clipped-group.pdf.rgb24.ref.png b/test/clipped-group.pdf.rgb24.ref.png
new file mode 100644
index 00000000..b9975e12
--- /dev/null
+++ b/test/clipped-group.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/dash-curve.ref.png b/test/dash-curve.ref.png
index 542b2d82..a590fc43 100644
--- a/test/dash-curve.ref.png
+++ b/test/dash-curve.ref.png
Binary files differ
diff --git a/test/degenerate-arc.ref.png b/test/degenerate-arc.ref.png
index 5112d7f9..1d131b22 100644
--- a/test/degenerate-arc.ref.png
+++ b/test/degenerate-arc.ref.png
Binary files 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 00000000..73d41afa
--- /dev/null
+++ b/test/degenerate-arc.test-fallback.argb32.ref.png
Binary files 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 00000000..73d41afa
--- /dev/null
+++ b/test/degenerate-arc.test-fallback.rgb24.ref.png
Binary files differ
diff --git a/test/degenerate-arc.xlib.ref.png b/test/degenerate-arc.xlib.ref.png
new file mode 100644
index 00000000..5112d7f9
--- /dev/null
+++ b/test/degenerate-arc.xlib.ref.png
Binary files 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 00000000..c076932c
--- /dev/null
+++ b/test/device-offset-fractional.pdf.argb32.ref.png
Binary files 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 00000000..c076932c
--- /dev/null
+++ b/test/device-offset-fractional.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/device-offset-positive.c b/test/device-offset-positive.c
index 4ea9469d..5afe9730 100644
--- a/test/device-offset-positive.c
+++ b/test/device-offset-positive.c
@@ -67,6 +67,7 @@ draw (cairo_t *cr, int width, int height)
cairo_destroy (cr2);
cairo_surface_set_device_offset (surface, + SIZE / 2, + SIZE / 2);
cairo_set_source_surface (cr, surface, SIZE / 2, SIZE / 2);
+ cairo_surface_destroy (surface);
cairo_paint (cr);
diff --git a/test/extend-pad-border.c b/test/extend-pad-border.c
new file mode 100644
index 00000000..79a81fcf
--- /dev/null
+++ b/test/extend-pad-border.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright © 2007 Red Hat, Inc.
+ *
+ * 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.
+ *
+ * Author: Behdad Esfahbod <behdad@behdad.org>
+ */
+
+#include <math.h>
+#include "cairo-test.h"
+#include <stdio.h>
+
+#define SIZE 90
+
+/* Check the border-pixels of an EXTEND_PAD image pattern */
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_surface_t *surface;
+ cairo_t * cr_surface;
+ int surface_size = (SIZE - 30) / 10;
+
+ cairo_set_source_rgba (cr, 0, 0, 0, 1);
+ cairo_rectangle (cr, 0, 0, SIZE, SIZE);
+ cairo_fill (cr);
+
+ /* Create an image surface with my favorite four colors in each
+ * quadrant. */
+ surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
+ surface_size, surface_size);
+ cr_surface = cairo_create (surface);
+ cairo_surface_destroy (surface);
+
+ cairo_set_source_rgb (cr_surface, 1, 1, 1);
+ cairo_rectangle (cr_surface,
+ 0, 0,
+ surface_size / 2, surface_size / 2);
+ cairo_fill (cr_surface);
+ cairo_set_source_rgb (cr_surface, 1, 0, 0);
+ cairo_rectangle (cr_surface,
+ surface_size / 2, 0,
+ surface_size / 2, surface_size / 2);
+ cairo_fill (cr_surface);
+ cairo_set_source_rgb (cr_surface, 0, 1, 0);
+ cairo_rectangle (cr_surface,
+ 0, surface_size / 2,
+ surface_size / 2, surface_size / 2);
+ cairo_fill (cr_surface);
+ cairo_set_source_rgb (cr_surface, 0, 0, 1);
+ cairo_rectangle (cr_surface,
+ surface_size / 2, surface_size / 2,
+ surface_size / 2, surface_size / 2);
+ cairo_fill (cr_surface);
+
+ cairo_scale (cr, 10, 10);
+ cairo_set_source_surface (cr, cairo_get_target (cr_surface), 1.5, 1.5);
+ cairo_destroy (cr_surface);
+
+ /* Using EXTEND_REFLECT makes this test pass for image and xlib backends */
+ /*cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REFLECT);*/
+
+ cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD);
+ cairo_rectangle (cr, 1.5, 1.5, 6, 6);
+ cairo_clip (cr);
+
+ cairo_paint (cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (extend_pad_border,
+ "Test CAIRO_EXTEND_PAD for surface patterns",
+ "XFAIL=!image,pdf,ps,svg extend", /* keywords */
+ NULL, /* requirements */
+ SIZE, SIZE,
+ NULL, draw)
diff --git a/test/extend-pad-border.ref.png b/test/extend-pad-border.ref.png
new file mode 100644
index 00000000..9292f8bb
--- /dev/null
+++ b/test/extend-pad-border.ref.png
Binary files differ
diff --git a/test/extend-pad-similar.c b/test/extend-pad-similar.c
new file mode 100644
index 00000000..357252ac
--- /dev/null
+++ b/test/extend-pad-similar.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright © 2007 Red Hat, Inc.
+ *
+ * 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.
+ *
+ * Author: Behdad Esfahbod <behdad@behdad.org>
+ */
+
+#include <math.h>
+#include "cairo-test.h"
+#include <stdio.h>
+
+#define SIZE 90
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_surface_t *surface;
+ cairo_t *cr_surface;
+
+ /* Create a 4-pixel similar surface with my favorite four colors in each
+ * quadrant. */
+ surface = cairo_surface_create_similar (cairo_get_group_target (cr),
+ CAIRO_CONTENT_COLOR, 2, 2);
+ cr_surface = cairo_create (surface);
+ cairo_surface_destroy (surface);
+
+ /* upper-left = white */
+ cairo_set_source_rgb (cr_surface, 1, 1, 1);
+ cairo_rectangle (cr_surface, 0, 0, 1, 1);
+ cairo_fill (cr_surface);
+
+ /* upper-right = red */
+ cairo_set_source_rgb (cr_surface, 1, 0, 0);
+ cairo_rectangle (cr_surface, 1, 0, 1, 1);
+ cairo_fill (cr_surface);
+
+ /* lower-left = green */
+ cairo_set_source_rgb (cr_surface, 0, 1, 0);
+ cairo_rectangle (cr_surface, 0, 1, 1, 1);
+ cairo_fill (cr_surface);
+
+ /* lower-right = blue */
+ cairo_set_source_rgb (cr_surface, 0, 0, 1);
+ cairo_rectangle (cr_surface, 1, 1, 1, 1);
+ cairo_fill (cr_surface);
+
+ /* Now use extend pad to cover the entire surface with those 4 colors */
+ cairo_set_source_surface (cr, cairo_get_target (cr_surface),
+ width/2 - 1,
+ height/2 - 1);
+ cairo_destroy (cr_surface);
+ cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD);
+ cairo_paint (cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (extend_pad_similar,
+ "Test CAIRO_EXTEND_PAD for similar surface patterns",
+ "extend", /* keywords */
+ NULL, /* requirements */
+ SIZE, SIZE,
+ NULL, draw)
diff --git a/test/extend-pad-similar.ref.png b/test/extend-pad-similar.ref.png
new file mode 100644
index 00000000..82da7b65
--- /dev/null
+++ b/test/extend-pad-similar.ref.png
Binary files differ
diff --git a/test/extend-pad.c b/test/extend-pad.c
index ed4ffd02..15a2079b 100644
--- a/test/extend-pad.c
+++ b/test/extend-pad.c
@@ -34,52 +34,40 @@ static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
cairo_surface_t *surface;
- cairo_t * cr_surface;
- int surface_size = (SIZE - 30) / 10;
+ cairo_t *cr_surface;
- cairo_set_source_rgba (cr, 0, 0, 0, 1);
- cairo_rectangle (cr, 0, 0, SIZE, SIZE);
- cairo_fill (cr);
-
- /* Create an image surface with my favorite four colors in each
+ /* Create a 4-pixel image surface with my favorite four colors in each
* quadrant. */
- surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
- surface_size, surface_size);
+ surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 2, 2);
cr_surface = cairo_create (surface);
cairo_surface_destroy (surface);
+ /* upper-left = white */
cairo_set_source_rgb (cr_surface, 1, 1, 1);
- cairo_rectangle (cr_surface,
- 0, 0,
- surface_size / 2, surface_size / 2);
+ cairo_rectangle (cr_surface, 0, 0, 1, 1);
cairo_fill (cr_surface);
+
+ /* upper-right = red */
cairo_set_source_rgb (cr_surface, 1, 0, 0);
- cairo_rectangle (cr_surface,
- surface_size / 2, 0,
- surface_size / 2, surface_size / 2);
+ cairo_rectangle (cr_surface, 1, 0, 1, 1);
cairo_fill (cr_surface);
+
+ /* lower-left = green */
cairo_set_source_rgb (cr_surface, 0, 1, 0);
- cairo_rectangle (cr_surface,
- 0, surface_size / 2,
- surface_size / 2, surface_size / 2);
+ cairo_rectangle (cr_surface, 0, 1, 1, 1);
cairo_fill (cr_surface);
+
+ /* lower-right = blue */
cairo_set_source_rgb (cr_surface, 0, 0, 1);
- cairo_rectangle (cr_surface,
- surface_size / 2, surface_size / 2,
- surface_size / 2, surface_size / 2);
+ cairo_rectangle (cr_surface, 1, 1, 1, 1);
cairo_fill (cr_surface);
- cairo_scale (cr, 10, 10);
- cairo_set_source_surface (cr, cairo_get_target (cr_surface), 1.5, 1.5);
+ /* Now use extend pad to cover the entire surface with those 4 colors */
+ cairo_set_source_surface (cr, cairo_get_target (cr_surface),
+ width/2 - 1,
+ height/2 - 1);
cairo_destroy (cr_surface);
-
- /* Using EXTEND_REFLECT makes this test pass for image and xlib backends */
- /*cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REFLECT);*/
-
cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD);
- cairo_rectangle (cr, 1.5, 1.5, 6, 6);
- cairo_clip (cr);
-
cairo_paint (cr);
return CAIRO_TEST_SUCCESS;
@@ -87,7 +75,7 @@ draw (cairo_t *cr, int width, int height)
CAIRO_TEST (extend_pad,
"Test CAIRO_EXTEND_PAD for surface patterns",
- "XFAIL=!image,pdf,ps,svg extend", /* keywords */
+ "extend", /* keywords */
NULL, /* requirements */
SIZE, SIZE,
NULL, draw)
diff --git a/test/extend-pad.ref.png b/test/extend-pad.ref.png
index 9292f8bb..82da7b65 100644
--- a/test/extend-pad.ref.png
+++ b/test/extend-pad.ref.png
Binary files differ
diff --git a/test/fill-alpha-pattern.pdf.argb32.ref.png b/test/fill-alpha-pattern.pdf.argb32.ref.png
index d786c86a..d7a7ebe5 100644
--- a/test/fill-alpha-pattern.pdf.argb32.ref.png
+++ b/test/fill-alpha-pattern.pdf.argb32.ref.png
Binary files differ
diff --git a/test/fill-alpha-pattern.pdf.rgb24.ref.png b/test/fill-alpha-pattern.pdf.rgb24.ref.png
index 75e580fb..ef9049e2 100644
--- a/test/fill-alpha-pattern.pdf.rgb24.ref.png
+++ b/test/fill-alpha-pattern.pdf.rgb24.ref.png
Binary files 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 00000000..b16731af
--- /dev/null
+++ b/test/fill-alpha-pattern.ps3.argb32.ref.png
Binary files 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 00000000..d0193545
--- /dev/null
+++ b/test/fill-alpha-pattern.ps3.rgb24.ref.png
Binary files differ
diff --git a/test/fill-alpha-pattern.ref.png b/test/fill-alpha-pattern.ref.png
index 0031c04c..9ab39a7d 100644
--- a/test/fill-alpha-pattern.ref.png
+++ b/test/fill-alpha-pattern.ref.png
Binary files 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 00000000..4dafb835
--- /dev/null
+++ b/test/fill-alpha-pattern.test-fallback.argb32.ref.png
Binary files 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 00000000..4dafb835
--- /dev/null
+++ b/test/fill-alpha-pattern.test-fallback.rgb24.ref.png
Binary files differ
diff --git a/test/fill-alpha-pattern.xlib.ref.png b/test/fill-alpha-pattern.xlib.ref.png
new file mode 100644
index 00000000..0031c04c
--- /dev/null
+++ b/test/fill-alpha-pattern.xlib.ref.png
Binary files differ
diff --git a/test/fill-alpha.ref.png b/test/fill-alpha.ref.png
index 61aaac29..b50a456d 100644
--- a/test/fill-alpha.ref.png
+++ b/test/fill-alpha.ref.png
Binary files 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 00000000..85df9198
--- /dev/null
+++ b/test/fill-alpha.test-fallback.argb32.ref.png
Binary files 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 00000000..85df9198
--- /dev/null
+++ b/test/fill-alpha.test-fallback.rgb24.ref.png
Binary files differ
diff --git a/test/fill-alpha.xlib.ref.png b/test/fill-alpha.xlib.ref.png
new file mode 100644
index 00000000..61aaac29
--- /dev/null
+++ b/test/fill-alpha.xlib.ref.png
Binary files differ
diff --git a/test/fill-degenerate-sort-order.ref.png b/test/fill-degenerate-sort-order.ref.png
index 8278d76e..3a95c257 100644
--- a/test/fill-degenerate-sort-order.ref.png
+++ b/test/fill-degenerate-sort-order.ref.png
Binary files differ
diff --git a/test/fill-degenerate-sort-order.rgb24.ref.png b/test/fill-degenerate-sort-order.rgb24.ref.png
index 6c76eaf4..377c7087 100644
--- a/test/fill-degenerate-sort-order.rgb24.ref.png
+++ b/test/fill-degenerate-sort-order.rgb24.ref.png
Binary files 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 00000000..8cf567dd
--- /dev/null
+++ b/test/fill-degenerate-sort-order.test-fallback.argb32.ref.png
Binary files 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 00000000..da5aa50a
--- /dev/null
+++ b/test/fill-degenerate-sort-order.test-fallback.rgb24.ref.png
Binary files 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 00000000..8278d76e
--- /dev/null
+++ b/test/fill-degenerate-sort-order.xlib.ref.png
Binary files 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 00000000..6c76eaf4
--- /dev/null
+++ b/test/fill-degenerate-sort-order.xlib.rgb24.ref.png
Binary files 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 00000000..7d56e3e8
--- /dev/null
+++ b/test/fill-missed-stop.pdf.argb32.ref.png
Binary files differ
diff --git a/test/fill-rule.ref.png b/test/fill-rule.ref.png
index e2e10d4a..6e19b621 100644
--- a/test/fill-rule.ref.png
+++ b/test/fill-rule.ref.png
Binary files differ
diff --git a/test/fill-rule.rgb24.ref.png b/test/fill-rule.rgb24.ref.png
index 68d2b9b8..bdfc12f4 100644
--- a/test/fill-rule.rgb24.ref.png
+++ b/test/fill-rule.rgb24.ref.png
Binary files 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 00000000..e2e10d4a
--- /dev/null
+++ b/test/fill-rule.test-fallback.argb32.ref.png
Binary files 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 00000000..49fb39c7
--- /dev/null
+++ b/test/fill-rule.test-fallback.rgb24.ref.png
Binary files differ
diff --git a/test/fill-rule.xlib.ref.png b/test/fill-rule.xlib.ref.png
new file mode 100644
index 00000000..e2e10d4a
--- /dev/null
+++ b/test/fill-rule.xlib.ref.png
Binary files differ
diff --git a/test/fill-rule.xlib.rgb24.ref.png b/test/fill-rule.xlib.rgb24.ref.png
new file mode 100644
index 00000000..68d2b9b8
--- /dev/null
+++ b/test/fill-rule.xlib.rgb24.ref.png
Binary files 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 00000000..3475cb6e
--- /dev/null
+++ b/test/filter-nearest-offset.pdf.argb32.ref.png
Binary files 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 00000000..3475cb6e
--- /dev/null
+++ b/test/filter-nearest-offset.pdf.rgb24.ref.png
Binary files 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 00000000..40169593
--- /dev/null
+++ b/test/filter-nearest-transformed.pdf.argb32.ref.png
Binary files 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 00000000..40169593
--- /dev/null
+++ b/test/filter-nearest-transformed.pdf.rgb24.ref.png
Binary files 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 00000000..92cd9517
--- /dev/null
+++ b/test/finer-grained-fallbacks.ps2.argb32.ref.png
Binary files differ
diff --git a/test/finer-grained-fallbacks.ps2.rgb24.ref.png b/test/finer-grained-fallbacks.ps2.rgb24.ref.png
index de482860..688c3e06 100644
--- a/test/finer-grained-fallbacks.ps2.rgb24.ref.png
+++ b/test/finer-grained-fallbacks.ps2.rgb24.ref.png
Binary files 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 00000000..92cd9517
--- /dev/null
+++ b/test/finer-grained-fallbacks.ps3.argb32.ref.png
Binary files differ
diff --git a/test/finer-grained-fallbacks.ps3.rgb24.ref.png b/test/finer-grained-fallbacks.ps3.rgb24.ref.png
index de482860..688c3e06 100644
--- a/test/finer-grained-fallbacks.ps3.rgb24.ref.png
+++ b/test/finer-grained-fallbacks.ps3.rgb24.ref.png
Binary files differ
diff --git a/test/finer-grained-fallbacks.ref.png b/test/finer-grained-fallbacks.ref.png
index c7eb113d..5b1e532b 100644
--- a/test/finer-grained-fallbacks.ref.png
+++ b/test/finer-grained-fallbacks.ref.png
Binary files differ
diff --git a/test/finer-grained-fallbacks.rgb24.ref.png b/test/finer-grained-fallbacks.rgb24.ref.png
index 3b8e9c38..d3997fe1 100644
--- a/test/finer-grained-fallbacks.rgb24.ref.png
+++ b/test/finer-grained-fallbacks.rgb24.ref.png
Binary files 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 00000000..c7eb113d
--- /dev/null
+++ b/test/finer-grained-fallbacks.test-fallback.argb32.ref.png
Binary files 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 00000000..ff75c6dd
--- /dev/null
+++ b/test/finer-grained-fallbacks.test-fallback.rgb24.ref.png
Binary files differ
diff --git a/test/finer-grained-fallbacks.xlib.ref.png b/test/finer-grained-fallbacks.xlib.ref.png
new file mode 100644
index 00000000..c7eb113d
--- /dev/null
+++ b/test/finer-grained-fallbacks.xlib.ref.png
Binary files 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 00000000..3b8e9c38
--- /dev/null
+++ b/test/finer-grained-fallbacks.xlib.rgb24.ref.png
Binary files 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 00000000..441f6e3b
--- /dev/null
+++ b/test/font-matrix-translation.svg11.argb32.ref.png
Binary files 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 00000000..441f6e3b
--- /dev/null
+++ b/test/font-matrix-translation.svg11.rgb24.ref.png
Binary files 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 00000000..441f6e3b
--- /dev/null
+++ b/test/font-matrix-translation.svg12.argb32.ref.png
Binary files 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 00000000..441f6e3b
--- /dev/null
+++ b/test/font-matrix-translation.svg12.rgb24.ref.png
Binary files 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 00000000..0c6e1c0b
--- /dev/null
+++ b/test/ft-show-glyphs-table.svg11.argb32.ref.png
Binary files 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 00000000..0c6e1c0b
--- /dev/null
+++ b/test/ft-show-glyphs-table.svg11.rgb24.ref.png
Binary files 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 00000000..0c6e1c0b
--- /dev/null
+++ b/test/ft-show-glyphs-table.svg12.argb32.ref.png
Binary files 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 00000000..0c6e1c0b
--- /dev/null
+++ b/test/ft-show-glyphs-table.svg12.rgb24.ref.png
Binary files 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 00000000..242c3be5
--- /dev/null
+++ b/test/ft-text-vertical-layout-type1.pdf.argb32.ref.png
Binary files 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 00000000..242c3be5
--- /dev/null
+++ b/test/ft-text-vertical-layout-type1.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/ft-text-vertical-layout-type1.ref.png b/test/ft-text-vertical-layout-type1.ref.png
index 2b74aa60..1accc0b3 100644
--- a/test/ft-text-vertical-layout-type1.ref.png
+++ b/test/ft-text-vertical-layout-type1.ref.png
Binary files 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 00000000..2de3f5be
--- /dev/null
+++ b/test/ft-text-vertical-layout-type1.svg11.argb32.ref.png
Binary files 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 00000000..2de3f5be
--- /dev/null
+++ b/test/ft-text-vertical-layout-type1.svg11.rgb24.ref.png
Binary files 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 00000000..2de3f5be
--- /dev/null
+++ b/test/ft-text-vertical-layout-type1.svg12.argb32.ref.png
Binary files 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 00000000..2de3f5be
--- /dev/null
+++ b/test/ft-text-vertical-layout-type1.svg12.rgb24.ref.png
Binary files 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 00000000..9eba6bb0
--- /dev/null
+++ b/test/ft-text-vertical-layout-type1.test-fallback.argb32.ref.png
Binary files 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 00000000..9eba6bb0
--- /dev/null
+++ b/test/ft-text-vertical-layout-type1.test-fallback.rgb24.ref.png
Binary files 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 00000000..2b74aa60
--- /dev/null
+++ b/test/ft-text-vertical-layout-type1.xlib.ref.png
Binary files 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 00000000..f232b9a5
--- /dev/null
+++ b/test/ft-text-vertical-layout-type3.pdf.argb32.ref.png
Binary files 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 00000000..f232b9a5
--- /dev/null
+++ b/test/ft-text-vertical-layout-type3.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/ft-text-vertical-layout-type3.ref.png b/test/ft-text-vertical-layout-type3.ref.png
index 8ec2ebec..6b59c56a 100644
--- a/test/ft-text-vertical-layout-type3.ref.png
+++ b/test/ft-text-vertical-layout-type3.ref.png
Binary files 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 00000000..cfe92681
--- /dev/null
+++ b/test/ft-text-vertical-layout-type3.svg11.argb32.ref.png
Binary files 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 00000000..cfe92681
--- /dev/null
+++ b/test/ft-text-vertical-layout-type3.svg11.rgb24.ref.png
Binary files 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 00000000..cfe92681
--- /dev/null
+++ b/test/ft-text-vertical-layout-type3.svg12.argb32.ref.png
Binary files 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 00000000..cfe92681
--- /dev/null
+++ b/test/ft-text-vertical-layout-type3.svg12.rgb24.ref.png
Binary files 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 00000000..e57c0831
--- /dev/null
+++ b/test/ft-text-vertical-layout-type3.test-fallback.argb32.ref.png
Binary files 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 00000000..e57c0831
--- /dev/null
+++ b/test/ft-text-vertical-layout-type3.test-fallback.rgb24.ref.png
Binary files 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 00000000..8ec2ebec
--- /dev/null
+++ b/test/ft-text-vertical-layout-type3.xlib.ref.png
Binary files differ
diff --git a/test/glitz-surface-source.c b/test/glitz-surface-source.c
index 2dfa7355..89094e48 100644
--- a/test/glitz-surface-source.c
+++ b/test/glitz-surface-source.c
@@ -25,8 +25,6 @@
#include "cairo-test.h"
#include <cairo-glitz.h>
-#include <cairo-xlib.h>
-#include <cairo-xlib-xrender.h>
#define NAME "glitz"
#include "surface-source.c"
@@ -34,6 +32,8 @@
static cairo_user_data_key_t closure_key;
#if CAIRO_CAN_TEST_GLITZ_GLX_SURFACE
+#include <cairo-xlib.h>
+#include <cairo-xlib-xrender.h>
#include <glitz-glx.h>
struct closure {
@@ -198,4 +198,96 @@ create_source_surface (int size)
return surface;
}
+
+#elif CAIRO_CAN_TEST_GLITZ_AGL_SURFACE
+#include <glitz-agl.h>
+
+static void
+cleanup (void *data)
+{
+ glitz_agl_fini ();
+}
+
+static glitz_surface_t *
+_glitz_agl_create_surface (glitz_format_name_t formatname,
+ int width,
+ int height)
+{
+ glitz_drawable_format_t * dformat = NULL;
+ glitz_drawable_t * drawable = NULL;
+ glitz_format_t * format;
+ glitz_format_t templ;
+ glitz_surface_t * sr;
+ int i;
+ int alpha_size;
+
+ glitz_agl_init ();
+
+ /* Find a reasonably lame window format and use it to create a pbuffer. */
+ i = 0;
+ alpha_size = (formatname == GLITZ_STANDARD_ARGB32) ? 8 : 0;
+ while ((dformat = glitz_agl_find_window_format (0, 0, i)) != NULL
+ && !(dformat->doublebuffer == 0
+ && dformat->stencil_size == 0
+ && dformat->depth_size == 0
+ && dformat->color.fourcc == GLITZ_FOURCC_RGB
+ && dformat->color.alpha_size == alpha_size))
+ i++;
+
+ if (!dformat)
+ goto FAIL;
+
+ /* Try for a pbuffer first */
+ drawable = glitz_agl_create_pbuffer_drawable (dformat, width, height);
+ if (!drawable)
+ goto FAIL;
+
+ templ.color = dformat->color;
+ format = glitz_find_format (drawable,
+ GLITZ_FORMAT_FOURCC_MASK |
+ GLITZ_FORMAT_RED_SIZE_MASK |
+ GLITZ_FORMAT_GREEN_SIZE_MASK |
+ GLITZ_FORMAT_BLUE_SIZE_MASK |
+ GLITZ_FORMAT_ALPHA_SIZE_MASK,
+ &templ,
+ 0);
+ if (!format) {
+ fprintf (stderr, "Error: couldn't find surface format\n");
+ return NULL;
+ }
+
+ sr = glitz_surface_create (drawable, format, width, height, 0, NULL);
+ if (!sr)
+ goto DESTROY_DRAWABLE;
+
+ glitz_surface_attach (sr, drawable, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR);
+ glitz_drawable_destroy (drawable);
+
+ return sr;
+ DESTROY_DRAWABLE:
+ glitz_drawable_destroy (drawable);
+ FAIL:
+ return NULL;
+}
+
+static cairo_surface_t *
+create_source_surface (int size)
+{
+ glitz_surface_t *glitz_surface;
+ cairo_surface_t *surface;
+
+ glitz_surface = _glitz_agl_create_surface (GLITZ_STANDARD_ARGB32,
+ size, size);
+
+ surface = cairo_glitz_surface_create (glitz_surface);
+ cairo_surface_set_user_data (surface, &closure_key, NULL, cleanup);
+ return surface;
+}
#endif
+
+CAIRO_TEST (glitz_surface_source,
+ "Test using a Glitz surface as the source",
+ "source", /* keywords */
+ NULL, /* requirements */
+ SIZE, SIZE,
+ preamble, draw)
diff --git a/test/glitz-surface-source.ps2.ref.png b/test/glitz-surface-source.ps2.ref.png
new file mode 100644
index 00000000..10231581
--- /dev/null
+++ b/test/glitz-surface-source.ps2.ref.png
Binary files differ
diff --git a/test/glitz-surface-source.ps3.ref.png b/test/glitz-surface-source.ps3.ref.png
new file mode 100644
index 00000000..10231581
--- /dev/null
+++ b/test/glitz-surface-source.ps3.ref.png
Binary files differ
diff --git a/test/huge-pattern.pdf.argb32.ref.png b/test/huge-pattern.pdf.argb32.ref.png
new file mode 100644
index 00000000..005d4a65
--- /dev/null
+++ b/test/huge-pattern.pdf.argb32.ref.png
Binary files differ
diff --git a/test/imagediff.c b/test/imagediff.c
index 424ca6dc..6ebbcfca 100644
--- a/test/imagediff.c
+++ b/test/imagediff.c
@@ -46,6 +46,23 @@ _xunlink (const char *pathname)
}
}
+void
+cairo_test_logv (const cairo_test_context_t *ctx,
+ const char *fmt, va_list va)
+{
+ vfprintf (stderr, fmt, va);
+}
+
+void
+cairo_test_log (const cairo_test_context_t *ctx, const char *fmt, ...)
+{
+ va_list va;
+
+ va_start (va, fmt);
+ vfprintf (stderr, fmt, va);
+ va_end (va);
+}
+
/* Flatten an ARGB surface by blending it over white. The resulting
* surface, (still in ARGB32 format, but with only alpha==1.0
* everywhere) is returned in the same surface pointer.
diff --git a/test/in-fill-trapezoid.c b/test/in-fill-trapezoid.c
index 6ff2fefb..57429687 100644
--- a/test/in-fill-trapezoid.c
+++ b/test/in-fill-trapezoid.c
@@ -42,6 +42,40 @@ draw (cairo_t *cr, int width, int height)
ret = CAIRO_TEST_FAILURE;
}
+ /* rectangular boundary tests */
+ if (cairo_in_fill (cr, -10, -10)) {
+ cairo_test_log (ctx, "Error: Found top-left vertex inside rectangle\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+ if (cairo_in_fill (cr, -10, 10)) {
+ cairo_test_log (ctx, "Error: Found bottom-left vertex inside rectangle\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+ if (! cairo_in_fill (cr, 10, -10)) {
+ cairo_test_log (ctx, "Error: Failed to find top-right vertex inside rectangle\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+ if (cairo_in_fill (cr, 10, 10)) {
+ cairo_test_log (ctx, "Error: Found bottom-right vertex inside rectangle\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+ if (cairo_in_fill (cr, -10, 0)) {
+ cairo_test_log (ctx, "Error: Found left edge inside rectangle\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+ if (! cairo_in_fill (cr, 0, -10)) {
+ cairo_test_log (ctx, "Error: Failed to find top edge inside rectangle\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+ if (! cairo_in_fill (cr, 10, 0)) {
+ cairo_test_log (ctx, "Error: Failed to find right edge inside rectangle\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+ if (cairo_in_fill (cr, 0, 10)) {
+ cairo_test_log (ctx, "Error: Found bottom edge inside rectangle\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+
/* simple circle */
cairo_new_path (cr);
cairo_arc (cr, 0, 0, 10, 0, 2 * M_PI);
@@ -68,6 +102,128 @@ draw (cairo_t *cr, int width, int height)
ret = CAIRO_TEST_FAILURE;
}
+
+ cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING);
+
+ /* simple rectangle */
+ cairo_new_path (cr);
+ cairo_rectangle (cr, -10, -10, 20, 20);
+ if (! cairo_in_fill (cr, 0, 0)) {
+ cairo_test_log (ctx, "Error: Failed to find point inside rectangle\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+
+ /* simple circle */
+ cairo_new_path (cr);
+ cairo_arc (cr, 0, 0, 10, 0, 2 * M_PI);
+ if (! cairo_in_fill (cr, 0, 0)) {
+ cairo_test_log (ctx, "Error: Failed to find point inside circle\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+
+ /* overlapping circle/rectangle */
+ cairo_new_path (cr);
+ cairo_rectangle (cr, -10, -10, 20, 20);
+ cairo_new_sub_path (cr);
+ cairo_arc (cr, 0, 0, 10, 0, 2 * M_PI);
+ if (! cairo_in_fill (cr, 0, 0)) {
+ cairo_test_log (ctx, "Error: Failed to find point inside circle+rectangle\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+
+ /* holey rectangle */
+ cairo_new_path (cr);
+ cairo_rectangle (cr, -10, -10, 20, 20);
+ cairo_rectangle (cr, 5, -5, -10, 10);
+ if (cairo_in_fill (cr, 0, 0)) {
+ cairo_test_log (ctx, "Error: Found an unexpected point inside rectangular hole\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+
+ /* holey circle */
+ cairo_new_path (cr);
+ cairo_arc (cr, 0, 0, 10, 0, 2 * M_PI);
+ cairo_arc_negative (cr, 0, 0, 5, 0, -2 * M_PI);
+ if (cairo_in_fill (cr, 0, 0)) {
+ cairo_test_log (ctx, "Error: Found an unexpected point inside circular hole\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+
+ /* not a holey circle */
+ cairo_new_path (cr);
+ cairo_arc (cr, 0, 0, 10, 0, 2 * M_PI);
+ cairo_arc (cr, 0, 0, 5, 0, 2 * M_PI);
+ if (! cairo_in_fill (cr, 0, 0)) {
+ cairo_test_log (ctx, "Error: Failed to find point inside two circles\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+
+ /* check off-centre */
+ cairo_new_path (cr);
+ cairo_arc (cr, 7.5, 0, 10, 0, 2 * M_PI);
+ cairo_arc_negative (cr, 7.5, 0, 5, 0, -2 * M_PI);
+ if (cairo_in_fill (cr, 7.5, 0)) {
+ cairo_test_log (ctx, "Error: Found an unexpected point inside circular hole\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+ cairo_new_path (cr);
+ cairo_arc (cr, 0, 7.5, 10, 0, 2 * M_PI);
+ cairo_arc_negative (cr, 0, 7.5, 5, 0, -2 * M_PI);
+ if (cairo_in_fill (cr, 0, 7.5)) {
+ cairo_test_log (ctx, "Error: Found an unexpected point inside circular hole\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+ cairo_new_path (cr);
+ cairo_arc (cr, 15, 0, 10, 0, 2 * M_PI);
+ if (! cairo_in_fill (cr, 15, 0)) {
+ cairo_test_log (ctx, "Error: Failed to find point inside circle\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+ cairo_new_path (cr);
+ cairo_arc (cr, 0, 15, 10, 0, 2 * M_PI);
+ if (! cairo_in_fill (cr, 0, 15)) {
+ cairo_test_log (ctx, "Error: Failed to find point inside circle\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+
+ /* simple rectangle */
+ cairo_new_path (cr);
+ cairo_rectangle (cr, 10, 0, 5, 5);
+ if (cairo_in_fill (cr, 0, 0)) {
+ cairo_test_log (ctx, "Error: Found an unexpected point outside rectangle\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+ if (cairo_in_fill (cr, 20, 20)) {
+ cairo_test_log (ctx, "Error: Found an unexpected point outside rectangle\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+ if (! cairo_in_fill (cr, 12.5, 2.5)) {
+ cairo_test_log (ctx, "Error: Failed to find point inside rectangle\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+
+ /* off-centre triangle */
+ cairo_new_path (cr);
+ cairo_move_to (cr, 10, 0);
+ cairo_line_to (cr, 15, 5);
+ cairo_line_to (cr, 5, 5);
+ cairo_close_path (cr);
+ if (cairo_in_fill (cr, 0, 0) ||
+ cairo_in_fill (cr, 10, 10) ||
+ cairo_in_fill (cr, 20, 0) ||
+ cairo_in_fill (cr, 7, 2.5) ||
+ cairo_in_fill (cr, 13, 2.5))
+ {
+ cairo_test_log (ctx, "Error: Found an unexpected point outside triangle\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+ if (! cairo_in_fill (cr, 8, 2.5) ||
+ ! cairo_in_fill (cr, 12, 2.5))
+ {
+ cairo_test_log (ctx, "Error: Failed to find point inside triangle\n");
+ ret = CAIRO_TEST_FAILURE;
+ }
+
return ret;
}
diff --git a/test/jp2.jp2 b/test/jp2.jp2
new file mode 100644
index 00000000..fe8dd6e5
--- /dev/null
+++ b/test/jp2.jp2
Binary files differ
diff --git a/test/jpeg.jpg b/test/jpeg.jpg
new file mode 100644
index 00000000..a1bac1c8
--- /dev/null
+++ b/test/jpeg.jpg
Binary files differ
diff --git a/test/linear-gradient.pdf.argb32.ref.png b/test/linear-gradient.pdf.argb32.ref.png
new file mode 100644
index 00000000..f820c374
--- /dev/null
+++ b/test/linear-gradient.pdf.argb32.ref.png
Binary files differ
diff --git a/test/linear-gradient.pdf.rgb24.ref.png b/test/linear-gradient.pdf.rgb24.ref.png
new file mode 100644
index 00000000..f820c374
--- /dev/null
+++ b/test/linear-gradient.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/linear-gradient.ref.png b/test/linear-gradient.ref.png
index cb8f9089..ee238e6a 100644
--- a/test/linear-gradient.ref.png
+++ b/test/linear-gradient.ref.png
Binary files differ
diff --git a/test/linear-gradient.svg11.argb32.ref.png b/test/linear-gradient.svg11.argb32.ref.png
new file mode 100644
index 00000000..ea0e7238
--- /dev/null
+++ b/test/linear-gradient.svg11.argb32.ref.png
Binary files differ
diff --git a/test/linear-gradient.svg11.rgb24.ref.png b/test/linear-gradient.svg11.rgb24.ref.png
new file mode 100644
index 00000000..ea0e7238
--- /dev/null
+++ b/test/linear-gradient.svg11.rgb24.ref.png
Binary files differ
diff --git a/test/linear-gradient.svg12.argb32.ref.png b/test/linear-gradient.svg12.argb32.ref.png
new file mode 100644
index 00000000..ea0e7238
--- /dev/null
+++ b/test/linear-gradient.svg12.argb32.ref.png
Binary files differ
diff --git a/test/linear-gradient.svg12.rgb24.ref.png b/test/linear-gradient.svg12.rgb24.ref.png
new file mode 100644
index 00000000..ea0e7238
--- /dev/null
+++ b/test/linear-gradient.svg12.rgb24.ref.png
Binary files 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 00000000..8202880e
--- /dev/null
+++ b/test/linear-gradient.test-fallback.argb32.ref.png
Binary files 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 00000000..8202880e
--- /dev/null
+++ b/test/linear-gradient.test-fallback.rgb24.ref.png
Binary files differ
diff --git a/test/linear-gradient.xlib.ref.png b/test/linear-gradient.xlib.ref.png
new file mode 100644
index 00000000..cb8f9089
--- /dev/null
+++ b/test/linear-gradient.xlib.ref.png
Binary files differ
diff --git a/test/mask-alpha.ref.png b/test/mask-alpha.ref.png
index 715a959e..d100da46 100644
--- a/test/mask-alpha.ref.png
+++ b/test/mask-alpha.ref.png
Binary files differ
diff --git a/test/mask-alpha.svg11.argb32.ref.png b/test/mask-alpha.svg11.argb32.ref.png
index 3e56aa34..fa9e82d1 100644
--- a/test/mask-alpha.svg11.argb32.ref.png
+++ b/test/mask-alpha.svg11.argb32.ref.png
Binary files differ
diff --git a/test/mask-alpha.svg11.rgb24.ref.png b/test/mask-alpha.svg11.rgb24.ref.png
new file mode 100644
index 00000000..167eab48
--- /dev/null
+++ b/test/mask-alpha.svg11.rgb24.ref.png
Binary files differ
diff --git a/test/mask-alpha.svg12.argb32.ref.png b/test/mask-alpha.svg12.argb32.ref.png
index 3e56aa34..fa9e82d1 100644
--- a/test/mask-alpha.svg12.argb32.ref.png
+++ b/test/mask-alpha.svg12.argb32.ref.png
Binary files differ
diff --git a/test/mask-alpha.svg12.rgb24.ref.png b/test/mask-alpha.svg12.rgb24.ref.png
new file mode 100644
index 00000000..167eab48
--- /dev/null
+++ b/test/mask-alpha.svg12.rgb24.ref.png
Binary files 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 00000000..a0b9017e
--- /dev/null
+++ b/test/mask-alpha.test-fallback.argb32.ref.png
Binary files differ
diff --git a/test/mask-alpha.xlib.ref.png b/test/mask-alpha.xlib.ref.png
new file mode 100644
index 00000000..715a959e
--- /dev/null
+++ b/test/mask-alpha.xlib.ref.png
Binary files differ
diff --git a/test/mask-alpha.xlib.rgb24.ref.png b/test/mask-alpha.xlib.rgb24.ref.png
new file mode 100644
index 00000000..aa2010f3
--- /dev/null
+++ b/test/mask-alpha.xlib.rgb24.ref.png
Binary files differ
diff --git a/test/mask.pdf.argb32.ref.png b/test/mask.pdf.argb32.ref.png
index 4570bff1..8bd8f140 100644
--- a/test/mask.pdf.argb32.ref.png
+++ b/test/mask.pdf.argb32.ref.png
Binary files differ
diff --git a/test/mask.pdf.rgb24.ref.png b/test/mask.pdf.rgb24.ref.png
index 1231965d..a3d3845c 100644
--- a/test/mask.pdf.rgb24.ref.png
+++ b/test/mask.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/mask.ref.png b/test/mask.ref.png
index 549c130c..2c2fa117 100644
--- a/test/mask.ref.png
+++ b/test/mask.ref.png
Binary files differ
diff --git a/test/mask.rgb24.ref.png b/test/mask.rgb24.ref.png
index 70323672..34400504 100644
--- a/test/mask.rgb24.ref.png
+++ b/test/mask.rgb24.ref.png
Binary files differ
diff --git a/test/mask.svg11.argb32.ref.png b/test/mask.svg11.argb32.ref.png
index c5828591..3ce4d53f 100644
--- a/test/mask.svg11.argb32.ref.png
+++ b/test/mask.svg11.argb32.ref.png
Binary files differ
diff --git a/test/mask.svg11.rgb24.ref.png b/test/mask.svg11.rgb24.ref.png
index 79957237..94e38009 100644
--- a/test/mask.svg11.rgb24.ref.png
+++ b/test/mask.svg11.rgb24.ref.png
Binary files differ
diff --git a/test/mask.svg12.argb32.ref.png b/test/mask.svg12.argb32.ref.png
index c5828591..3ce4d53f 100644
--- a/test/mask.svg12.argb32.ref.png
+++ b/test/mask.svg12.argb32.ref.png
Binary files differ
diff --git a/test/mask.svg12.rgb24.ref.png b/test/mask.svg12.rgb24.ref.png
index 79957237..94e38009 100644
--- a/test/mask.svg12.rgb24.ref.png
+++ b/test/mask.svg12.rgb24.ref.png
Binary files differ
diff --git a/test/mask.test-fallback.argb32.ref.png b/test/mask.test-fallback.argb32.ref.png
new file mode 100644
index 00000000..bba0f9f3
--- /dev/null
+++ b/test/mask.test-fallback.argb32.ref.png
Binary files differ
diff --git a/test/mask.test-fallback.rgb24.ref.png b/test/mask.test-fallback.rgb24.ref.png
new file mode 100644
index 00000000..49a5b364
--- /dev/null
+++ b/test/mask.test-fallback.rgb24.ref.png
Binary files differ
diff --git a/test/mask.xlib-fallback.rgb24.ref.png b/test/mask.xlib-fallback.rgb24.ref.png
new file mode 100644
index 00000000..34400504
--- /dev/null
+++ b/test/mask.xlib-fallback.rgb24.ref.png
Binary files differ
diff --git a/test/mask.xlib.ref.png b/test/mask.xlib.ref.png
new file mode 100644
index 00000000..549c130c
--- /dev/null
+++ b/test/mask.xlib.ref.png
Binary files differ
diff --git a/test/mask.xlib.rgb24.ref.png b/test/mask.xlib.rgb24.ref.png
new file mode 100644
index 00000000..70323672
--- /dev/null
+++ b/test/mask.xlib.rgb24.ref.png
Binary files 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 00000000..2ee9b7da
--- /dev/null
+++ b/test/meta-surface-pattern.pdf.argb32.ref.png
Binary files differ
diff --git a/test/meta-surface-pattern.pdf.rgb24.ref.png b/test/meta-surface-pattern.pdf.rgb24.ref.png
index 680f0f50..6555a265 100644
--- a/test/meta-surface-pattern.pdf.rgb24.ref.png
+++ b/test/meta-surface-pattern.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/meta-surface-pattern.svg11.argb32.ref.png b/test/meta-surface-pattern.svg11.argb32.ref.png
index 6250f26c..99695748 100644
--- a/test/meta-surface-pattern.svg11.argb32.ref.png
+++ b/test/meta-surface-pattern.svg11.argb32.ref.png
Binary files differ
diff --git a/test/meta-surface-pattern.svg11.rgb24.ref.png b/test/meta-surface-pattern.svg11.rgb24.ref.png
index feda67da..dea9b9b5 100644
--- a/test/meta-surface-pattern.svg11.rgb24.ref.png
+++ b/test/meta-surface-pattern.svg11.rgb24.ref.png
Binary files differ
diff --git a/test/meta-surface-pattern.svg12.argb32.ref.png b/test/meta-surface-pattern.svg12.argb32.ref.png
index 6250f26c..99695748 100644
--- a/test/meta-surface-pattern.svg12.argb32.ref.png
+++ b/test/meta-surface-pattern.svg12.argb32.ref.png
Binary files differ
diff --git a/test/meta-surface-pattern.svg12.rgb24.ref.png b/test/meta-surface-pattern.svg12.rgb24.ref.png
index feda67da..dea9b9b5 100644
--- a/test/meta-surface-pattern.svg12.rgb24.ref.png
+++ b/test/meta-surface-pattern.svg12.rgb24.ref.png
Binary files differ
diff --git a/test/mime-data.c b/test/mime-data.c
new file mode 100644
index 00000000..febc3226
--- /dev/null
+++ b/test/mime-data.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright © 2008 Chris Wilson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Chris Wilson not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Chris Wilson makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairo-test.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+/* Basic test to exercise the new mime-data embedding. */
+
+static cairo_status_t
+read_file (const cairo_test_context_t *ctx,
+ const char *filename,
+ unsigned char **data_out,
+ unsigned int *length_out)
+{
+ FILE *file;
+ unsigned char *buf;
+ unsigned int len;
+
+ file = fopen (filename, "rb");
+ if (file == NULL) {
+ char path[4096];
+
+ /* try again with srcdir */
+ snprintf (path, sizeof (path),
+ "%s/%s", ctx->srcdir, filename);
+ file = fopen (path, "rb");
+ }
+ if (file == NULL) {
+ switch (errno) {
+ case ENOMEM:
+ return CAIRO_STATUS_NO_MEMORY;
+ default:
+ return CAIRO_STATUS_FILE_NOT_FOUND;
+ }
+ }
+
+ fseek (file, 0, SEEK_END);
+ len = ftell (file);
+ fseek (file, 0, SEEK_SET);
+
+ buf = xmalloc (len);
+ *length_out = fread (buf, 1, len, file);
+ fclose (file);
+ if (*length_out != len) {
+ free (buf);
+ return CAIRO_STATUS_READ_ERROR;
+ }
+
+ *data_out = buf;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_test_status_t
+paint_file (cairo_t *cr,
+ const char *filename, const char *mime_type,
+ int x, int y)
+{
+ const cairo_test_context_t *ctx = cairo_test_get_context (cr);
+ cairo_surface_t *image;
+ unsigned char *mime_data;
+ unsigned int mime_length;
+ cairo_status_t status;
+
+ /* Deliberately use a non-matching MIME images, so that we can identify
+ * when the MIME representation is used in preference to the plain image
+ * surface.
+ */
+ status = read_file (ctx, filename, &mime_data, &mime_length);
+ if (status)
+ return cairo_test_status_from_status (ctx, status);
+
+ image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 200, 50);
+
+ status = cairo_surface_set_mime_data (image, mime_type,
+ mime_data, mime_length,
+ free, mime_data);
+ if (status) {
+ cairo_surface_destroy (image);
+ return cairo_test_status_from_status (ctx, status);
+ }
+
+ cairo_set_source_surface (cr, image, x, y);
+ cairo_surface_destroy (image);
+
+ cairo_paint (cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ const char jpg_filename[] = "jpeg.jpg";
+ const char png_filename[] = "png.png";
+ const char jp2_filename[] = "jp2.jp2";
+ cairo_test_status_t status;
+
+ status = paint_file (cr, jpg_filename, CAIRO_MIME_TYPE_JPEG, 0, 0);
+ if (status)
+ return status;
+
+ status = paint_file (cr, png_filename, CAIRO_MIME_TYPE_PNG, 0, 50);
+ if (status)
+ return status;
+
+ status = paint_file (cr, jp2_filename, CAIRO_MIME_TYPE_JP2, 0, 100);
+ if (status)
+ return status;
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (mime_data,
+ "Check that the mime-data embedding works",
+ "jpeg, api", /* keywords */
+ NULL, /* requirements */
+ 200, 150,
+ NULL, draw)
diff --git a/test/mime-data.pdf.ref.png b/test/mime-data.pdf.ref.png
new file mode 100644
index 00000000..90a08f59
--- /dev/null
+++ b/test/mime-data.pdf.ref.png
Binary files differ
diff --git a/test/mime-data.ps.ref.png b/test/mime-data.ps.ref.png
new file mode 100644
index 00000000..721fb9c8
--- /dev/null
+++ b/test/mime-data.ps.ref.png
Binary files differ
diff --git a/test/mime-data.ref.png b/test/mime-data.ref.png
new file mode 100644
index 00000000..3a912c54
--- /dev/null
+++ b/test/mime-data.ref.png
Binary files differ
diff --git a/test/mime-data.script.ref.png b/test/mime-data.script.ref.png
new file mode 100644
index 00000000..a236b044
--- /dev/null
+++ b/test/mime-data.script.ref.png
Binary files differ
diff --git a/test/mime-data.svg.ref.png b/test/mime-data.svg.ref.png
new file mode 100644
index 00000000..81fde726
--- /dev/null
+++ b/test/mime-data.svg.ref.png
Binary files differ
diff --git a/test/operator-clear.pdf.argb32.ref.png b/test/operator-clear.pdf.argb32.ref.png
index 06fc51e3..258c61c9 100644
--- a/test/operator-clear.pdf.argb32.ref.png
+++ b/test/operator-clear.pdf.argb32.ref.png
Binary files differ
diff --git a/test/operator-clear.ps2.argb32.ref.png b/test/operator-clear.ps2.argb32.ref.png
new file mode 100644
index 00000000..92b41111
--- /dev/null
+++ b/test/operator-clear.ps2.argb32.ref.png
Binary files differ
diff --git a/test/operator-clear.ps3.argb32.ref.png b/test/operator-clear.ps3.argb32.ref.png
new file mode 100644
index 00000000..92b41111
--- /dev/null
+++ b/test/operator-clear.ps3.argb32.ref.png
Binary files differ
diff --git a/test/operator-source.pdf.argb32.ref.png b/test/operator-source.pdf.argb32.ref.png
index f110ff2a..f42d5af4 100644
--- a/test/operator-source.pdf.argb32.ref.png
+++ b/test/operator-source.pdf.argb32.ref.png
Binary files differ
diff --git a/test/operator-source.pdf.rgb24.ref.png b/test/operator-source.pdf.rgb24.ref.png
index c6b71705..8269bc10 100644
--- a/test/operator-source.pdf.rgb24.ref.png
+++ b/test/operator-source.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/operator-source.ref.png b/test/operator-source.ref.png
index 8e2f5e61..006bf950 100644
--- a/test/operator-source.ref.png
+++ b/test/operator-source.ref.png
Binary files differ
diff --git a/test/operator-source.rgb24.ref.png b/test/operator-source.rgb24.ref.png
index a762d60a..013d8a42 100644
--- a/test/operator-source.rgb24.ref.png
+++ b/test/operator-source.rgb24.ref.png
Binary files 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 00000000..8aac39d1
--- /dev/null
+++ b/test/operator-source.test-fallback.argb32.ref.png
Binary files 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 00000000..ad37a60b
--- /dev/null
+++ b/test/operator-source.test-fallback.rgb24.ref.png
Binary files 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 00000000..fe0d3c61
--- /dev/null
+++ b/test/operator-source.xlib-fallback.rgb24.ref.png
Binary files differ
diff --git a/test/operator-source.xlib.ref.png b/test/operator-source.xlib.ref.png
new file mode 100644
index 00000000..8e2f5e61
--- /dev/null
+++ b/test/operator-source.xlib.ref.png
Binary files differ
diff --git a/test/operator-source.xlib.rgb24.ref.png b/test/operator-source.xlib.rgb24.ref.png
new file mode 100644
index 00000000..a762d60a
--- /dev/null
+++ b/test/operator-source.xlib.rgb24.ref.png
Binary files differ
diff --git a/test/over-above-source.ps2.argb32.ref.png b/test/over-above-source.ps2.argb32.ref.png
index 886faad4..7c90d086 100644
--- a/test/over-above-source.ps2.argb32.ref.png
+++ b/test/over-above-source.ps2.argb32.ref.png
Binary files differ
diff --git a/test/over-above-source.ps3.argb32.ref.png b/test/over-above-source.ps3.argb32.ref.png
index 886faad4..7c90d086 100644
--- a/test/over-above-source.ps3.argb32.ref.png
+++ b/test/over-above-source.ps3.argb32.ref.png
Binary files differ
diff --git a/test/over-above-source.ref.png b/test/over-above-source.ref.png
index f3a49f61..c45fcbde 100644
--- a/test/over-above-source.ref.png
+++ b/test/over-above-source.ref.png
Binary files differ
diff --git a/test/over-above-source.rgb24.ref.png b/test/over-above-source.rgb24.ref.png
index 68c7d982..84fc880c 100644
--- a/test/over-above-source.rgb24.ref.png
+++ b/test/over-above-source.rgb24.ref.png
Binary files 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 00000000..8a0183a6
--- /dev/null
+++ b/test/over-above-source.test-fallback.argb32.ref.png
Binary files 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 00000000..85c19971
--- /dev/null
+++ b/test/over-above-source.test-fallback.rgb24.ref.png
Binary files differ
diff --git a/test/over-above-source.xlib.ref.png b/test/over-above-source.xlib.ref.png
new file mode 100644
index 00000000..f3a49f61
--- /dev/null
+++ b/test/over-above-source.xlib.ref.png
Binary files 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 00000000..68c7d982
--- /dev/null
+++ b/test/over-above-source.xlib.rgb24.ref.png
Binary files 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 00000000..02af76a9
--- /dev/null
+++ b/test/over-around-source.pdf.argb32.ref.png
Binary files differ
diff --git a/test/over-around-source.ps2.argb32.ref.png b/test/over-around-source.ps2.argb32.ref.png
index ea6de696..647420ad 100644
--- a/test/over-around-source.ps2.argb32.ref.png
+++ b/test/over-around-source.ps2.argb32.ref.png
Binary files differ
diff --git a/test/over-around-source.ps3.argb32.ref.png b/test/over-around-source.ps3.argb32.ref.png
index ea6de696..647420ad 100644
--- a/test/over-around-source.ps3.argb32.ref.png
+++ b/test/over-around-source.ps3.argb32.ref.png
Binary files differ
diff --git a/test/over-around-source.ref.png b/test/over-around-source.ref.png
index ccae9514..abaeb4e4 100644
--- a/test/over-around-source.ref.png
+++ b/test/over-around-source.ref.png
Binary files 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 00000000..fca75056
--- /dev/null
+++ b/test/over-around-source.test-fallback.argb32.ref.png
Binary files differ
diff --git a/test/over-around-source.xlib.ref.png b/test/over-around-source.xlib.ref.png
new file mode 100644
index 00000000..ccae9514
--- /dev/null
+++ b/test/over-around-source.xlib.ref.png
Binary files 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 00000000..943a28e3
--- /dev/null
+++ b/test/over-around-source.xlib.rgb24.ref.png
Binary files 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 00000000..b9c4fe28
--- /dev/null
+++ b/test/over-below-source.pdf.argb32.ref.png
Binary files differ
diff --git a/test/over-between-source.ps2.argb32.ref.png b/test/over-between-source.ps2.argb32.ref.png
index 43e9424b..dd95940a 100644
--- a/test/over-between-source.ps2.argb32.ref.png
+++ b/test/over-between-source.ps2.argb32.ref.png
Binary files differ
diff --git a/test/over-between-source.ps3.argb32.ref.png b/test/over-between-source.ps3.argb32.ref.png
index 43e9424b..dd95940a 100644
--- a/test/over-between-source.ps3.argb32.ref.png
+++ b/test/over-between-source.ps3.argb32.ref.png
Binary files differ
diff --git a/test/over-between-source.ref.png b/test/over-between-source.ref.png
index 79ea75e9..0c3986fc 100644
--- a/test/over-between-source.ref.png
+++ b/test/over-between-source.ref.png
Binary files 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 00000000..a8fe66a3
--- /dev/null
+++ b/test/over-between-source.test-fallback.argb32.ref.png
Binary files differ
diff --git a/test/over-between-source.xlib.ref.png b/test/over-between-source.xlib.ref.png
new file mode 100644
index 00000000..79ea75e9
--- /dev/null
+++ b/test/over-between-source.xlib.ref.png
Binary files 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 00000000..602f2d26
--- /dev/null
+++ b/test/over-between-source.xlib.rgb24.ref.png
Binary files differ
diff --git a/test/pdf-mime-data.c b/test/pdf-mime-data.c
new file mode 100644
index 00000000..233374dd
--- /dev/null
+++ b/test/pdf-mime-data.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright © 2008 Adrian Johnson
+ *
+ * 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.
+ *
+ * Author: Adrian Johnson <ajohnson@redneon.com>
+ */
+
+#include "cairo-test.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <cairo.h>
+#include <cairo-pdf.h>
+
+/* This test checks that the mime data is correctly used by the PDF
+ * surface when embedding images..
+ */
+
+/* Both a *.png and *.jpg file with this name is required since we
+ * are not using a jpeg library */
+#define IMAGE_FILE "romedalen"
+
+
+static cairo_test_status_t
+read_file (const cairo_test_context_t *ctx,
+ const char *file,
+ unsigned char **data,
+ unsigned int *len)
+{
+ FILE *fp;
+
+ fp = fopen (file, "rb");
+ if (file == NULL) {
+ char filename[4096];
+
+ /* try again with srcdir */
+ snprintf (filename, sizeof (filename),
+ "%s/%s", ctx->srcdir, file);
+ fp = fopen (filename, "rb");
+ }
+ if (fp == NULL) {
+ switch (errno) {
+ case ENOMEM:
+ return CAIRO_TEST_NO_MEMORY;
+ default:
+ return CAIRO_TEST_FAILURE;
+ }
+ }
+
+ fseek (fp, 0, SEEK_END);
+ *len = ftell(fp);
+ fseek (fp, 0, SEEK_SET);
+ *data = malloc (*len);
+ if (*data == NULL)
+ return CAIRO_TEST_NO_MEMORY;
+
+ if (fread(*data, *len, 1, fp) != 1)
+ return CAIRO_TEST_FAILURE;
+
+ fclose(fp);
+ return CAIRO_TEST_SUCCESS;
+}
+
+static cairo_test_status_t
+preamble (cairo_test_context_t *ctx)
+{
+ const char *filename = "pdf-mime-data.out.pdf";
+ cairo_surface_t *image;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ cairo_status_t status, status2;
+ cairo_test_status_t test_status;
+ int width, height;
+ unsigned char *data;
+ unsigned char *out_data;
+ unsigned int len, out_len;
+ char command[4096];
+ int exit_status;
+
+ if (! cairo_test_is_target_enabled (ctx, "pdf"))
+ return CAIRO_TEST_UNTESTED;
+
+ image = cairo_image_surface_create_from_png (IMAGE_FILE ".png");
+ test_status = read_file (ctx, IMAGE_FILE ".jpg", &data, &len);
+ if (test_status) {
+ cairo_test_log (ctx, "Could not read input jpeg file %s\n", IMAGE_FILE ".jpg");
+ return test_status;
+ }
+
+ cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_JPEG,
+ data, len,
+ free, data);
+ width = cairo_image_surface_get_width (image);
+ height = cairo_image_surface_get_height (image);
+
+ surface = cairo_pdf_surface_create (filename, width + 20, height + 20);
+ cr = cairo_create (surface);
+ cairo_translate (cr, 10, 10);
+ cairo_set_source_surface (cr, image, 0, 0);
+ cairo_paint (cr);
+ status = cairo_status (cr);
+ cairo_destroy (cr);
+ cairo_surface_finish (surface);
+ status2 = cairo_surface_status (surface);
+ if (status != CAIRO_STATUS_SUCCESS)
+ status = status2;
+ cairo_surface_destroy (surface);
+ cairo_surface_destroy (image);
+
+ if (status) {
+ cairo_test_log (ctx, "Failed to create pdf surface for file %s: %s\n",
+ filename, cairo_status_to_string (status));
+ return CAIRO_TEST_FAILURE;
+ }
+
+ printf ("pdf-mime-data: Please check %s to ensure it looks/prints correctly.\n", filename);
+
+ sprintf (command, "pdfimages -j %s pdf-mime-data.out", filename);
+ exit_status = system (command);
+ if (exit_status) {
+ cairo_test_log (ctx, "pdfimages failed with exit status %d\n", exit_status);
+ return CAIRO_TEST_FAILURE;
+ }
+
+ test_status = read_file (ctx, IMAGE_FILE ".jpg", &data, &len);
+ if (test_status) {
+ cairo_test_log (ctx, "Could not read input jpeg file %s\n", IMAGE_FILE ".jpg");
+ return test_status;
+ }
+
+ test_status = read_file (ctx, "pdf-mime-data.out-000.jpg", &out_data, &out_len);
+ if (test_status) {
+ cairo_test_log (ctx,
+ "Could not read input jpeg file %s\n",
+ "pdf-mime-data.out-000.jpg");
+ return test_status;
+ }
+
+ if (len != out_len || memcmp(data, out_data, len) != 0) {
+ cairo_test_log (ctx, "output mime data does not match source mime data\n");
+ return CAIRO_TEST_FAILURE;
+ }
+ free (data);
+ free (out_data);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (pdf_mime_data,
+ "Check mime data correctly used by PDF surface",
+ "pdf, mime-data", /* keywords */
+ NULL, /* requirements */
+ 0, 0,
+ preamble, NULL)
diff --git a/test/pdf2png.c b/test/pdf2png.c
index 543a996e..8471a186 100644
--- a/test/pdf2png.c
+++ b/test/pdf2png.c
@@ -36,21 +36,21 @@ int main (int argc, char *argv[])
{
PopplerDocument *document;
PopplerPage *page;
- GdkPixbuf *pixbuf;
double width, height;
- GError *error;
const char *filename = argv[1];
const char *output_filename = argv[2];
const char *page_label = argv[3];
gchar *absolute, *uri;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ cairo_status_t status;
+ GError *error = NULL;
if (argc != 4)
FAIL ("usage: pdf2png input_file.pdf output_file.png page");
g_type_init ();
- error = NULL;
-
if (g_path_is_absolute(filename)) {
absolute = g_strdup (filename);
} else {
@@ -74,16 +74,22 @@ int main (int argc, char *argv[])
poppler_page_get_size (page, &width, &height);
- pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
- width * PIXELS_PER_POINT,
- height * PIXELS_PER_POINT);
- gdk_pixbuf_fill (pixbuf, 0xffffffff);
- poppler_page_render_to_pixbuf (page, 0, 0, width , height,
- PIXELS_PER_POINT, 0, pixbuf);
+ surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
+ cr = cairo_create (surface);
+ cairo_surface_destroy (surface);
- gdk_pixbuf_save (pixbuf, output_filename, "png", &error, NULL);
- if (error != NULL)
- FAIL (error->message);
+ cairo_set_source_rgb (cr, 1., 1., 1.);
+ cairo_paint (cr);
+
+ poppler_page_render (page, cr);
+ g_object_unref (page);
+
+ status = cairo_surface_write_to_png (cairo_get_target (cr),
+ output_filename);
+ cairo_destroy (cr);
+
+ if (status)
+ FAIL (cairo_status_to_string (status));
return 0;
}
diff --git a/test/png.png b/test/png.png
new file mode 100644
index 00000000..56c428e1
--- /dev/null
+++ b/test/png.png
Binary files differ
diff --git a/test/push-group.pdf.argb32.ref.png b/test/push-group.pdf.argb32.ref.png
new file mode 100644
index 00000000..9cb59c94
--- /dev/null
+++ b/test/push-group.pdf.argb32.ref.png
Binary files differ
diff --git a/test/push-group.pdf.rgb24.ref.png b/test/push-group.pdf.rgb24.ref.png
index 7e84ec83..34d7f74e 100644
--- a/test/push-group.pdf.rgb24.ref.png
+++ b/test/push-group.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/push-group.ref.png b/test/push-group.ref.png
index 84bc184d..e4ae291f 100644
--- a/test/push-group.ref.png
+++ b/test/push-group.ref.png
Binary files differ
diff --git a/test/push-group.rgb24.ref.png b/test/push-group.rgb24.ref.png
index cababd95..3a951827 100644
--- a/test/push-group.rgb24.ref.png
+++ b/test/push-group.rgb24.ref.png
Binary files differ
diff --git a/test/push-group.svg11.argb32.ref.png b/test/push-group.svg11.argb32.ref.png
index 34f06bf7..d6958798 100644
--- a/test/push-group.svg11.argb32.ref.png
+++ b/test/push-group.svg11.argb32.ref.png
Binary files differ
diff --git a/test/push-group.svg12.argb32.ref.png b/test/push-group.svg12.argb32.ref.png
index 34f06bf7..d6958798 100644
--- a/test/push-group.svg12.argb32.ref.png
+++ b/test/push-group.svg12.argb32.ref.png
Binary files 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 00000000..7c5905a6
--- /dev/null
+++ b/test/push-group.test-fallback.argb32.ref.png
Binary files 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 00000000..4586d5c5
--- /dev/null
+++ b/test/push-group.test-fallback.rgb24.ref.png
Binary files 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 00000000..3a951827
--- /dev/null
+++ b/test/push-group.xlib-fallback.rgb24.ref.png
Binary files differ
diff --git a/test/push-group.xlib.ref.png b/test/push-group.xlib.ref.png
new file mode 100644
index 00000000..84bc184d
--- /dev/null
+++ b/test/push-group.xlib.ref.png
Binary files differ
diff --git a/test/push-group.xlib.rgb24.ref.png b/test/push-group.xlib.rgb24.ref.png
new file mode 100644
index 00000000..cababd95
--- /dev/null
+++ b/test/push-group.xlib.rgb24.ref.png
Binary files differ
diff --git a/test/quartz-surface-source.c b/test/quartz-surface-source.c
new file mode 100644
index 00000000..b0c86d0f
--- /dev/null
+++ b/test/quartz-surface-source.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright © 2008 Chris Wilson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Chris Wilson not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Chris Wilson makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairo-test.h"
+#include "cairo-quartz.h"
+
+#include "surface-source.c"
+
+static cairo_surface_t *
+create_source_surface (int size)
+{
+ return cairo_quartz_surface_create (CAIRO_FORMAT_ARGB32, size, size);
+}
+
+CAIRO_TEST (quartz_surface_source,
+ "Test using a Quartz surface as the source",
+ "source", /* keywords */
+ NULL, /* requirements */
+ SIZE, SIZE,
+ preamble, draw)
diff --git a/test/quartz-surface-source.ps2.ref.png b/test/quartz-surface-source.ps2.ref.png
new file mode 100644
index 00000000..10231581
--- /dev/null
+++ b/test/quartz-surface-source.ps2.ref.png
Binary files differ
diff --git a/test/quartz-surface-source.ps3.ref.png b/test/quartz-surface-source.ps3.ref.png
new file mode 100644
index 00000000..10231581
--- /dev/null
+++ b/test/quartz-surface-source.ps3.ref.png
Binary files differ
diff --git a/test/quartz-surface-source.ref.png b/test/quartz-surface-source.ref.png
new file mode 100644
index 00000000..9fbbedd5
--- /dev/null
+++ b/test/quartz-surface-source.ref.png
Binary files differ
diff --git a/test/radial-gradient.pdf.argb32.ref.png b/test/radial-gradient.pdf.argb32.ref.png
new file mode 100644
index 00000000..6cee5d12
--- /dev/null
+++ b/test/radial-gradient.pdf.argb32.ref.png
Binary files differ
diff --git a/test/radial-gradient.pdf.rgb24.ref.png b/test/radial-gradient.pdf.rgb24.ref.png
new file mode 100644
index 00000000..6cee5d12
--- /dev/null
+++ b/test/radial-gradient.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/random-intersections.ref.png b/test/random-intersections.ref.png
index 3188edef..ace75a24 100644
--- a/test/random-intersections.ref.png
+++ b/test/random-intersections.ref.png
Binary files 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 00000000..a35364d8
--- /dev/null
+++ b/test/random-intersections.test-fallback.argb32.ref.png
Binary files 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 00000000..a35364d8
--- /dev/null
+++ b/test/random-intersections.test-fallback.rgb24.ref.png
Binary files differ
diff --git a/test/random-intersections.xlib.ref.png b/test/random-intersections.xlib.ref.png
new file mode 100644
index 00000000..3188edef
--- /dev/null
+++ b/test/random-intersections.xlib.ref.png
Binary files differ
diff --git a/test/romedalen.jpg b/test/romedalen.jpg
new file mode 100644
index 00000000..d655e3d8
--- /dev/null
+++ b/test/romedalen.jpg
Binary files differ
diff --git a/test/rotate-image-surface-paint.pdf.argb32.ref.png b/test/rotate-image-surface-paint.pdf.argb32.ref.png
index c12ae8fd..93fab525 100644
--- a/test/rotate-image-surface-paint.pdf.argb32.ref.png
+++ b/test/rotate-image-surface-paint.pdf.argb32.ref.png
Binary files differ
diff --git a/test/rotate-image-surface-paint.pdf.rgb24.ref.png b/test/rotate-image-surface-paint.pdf.rgb24.ref.png
index 5cd7bf61..93fab525 100644
--- a/test/rotate-image-surface-paint.pdf.rgb24.ref.png
+++ b/test/rotate-image-surface-paint.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/rotate-image-surface-paint.ref.png b/test/rotate-image-surface-paint.ref.png
index bd20481f..5c98d7d8 100644
--- a/test/rotate-image-surface-paint.ref.png
+++ b/test/rotate-image-surface-paint.ref.png
Binary files differ
diff --git a/test/scale-offset-image.c b/test/scale-offset-image.c
new file mode 100644
index 00000000..ab553422
--- /dev/null
+++ b/test/scale-offset-image.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2008 Chris Wilson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Chris Wilson not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Chris Wilson makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+/*
+ * Test case derived from the bug report by Michel Iwaniec:
+ * http://lists.cairographics.org/archives/cairo/2008-November/015660.html
+ */
+
+#include "cairo-test.h"
+
+static cairo_surface_t *
+create_source (cairo_surface_t *target, int width, int height)
+{
+ cairo_surface_t *similar;
+ cairo_t *cr;
+
+ similar = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
+ width, height);
+ cr = cairo_create (similar);
+ cairo_surface_destroy (similar);
+
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_rectangle (cr,
+ width - 4, height - 4,
+ 2, 2);
+ cairo_fill (cr);
+ cairo_set_source_rgb (cr, 1, 0, 0);
+ cairo_rectangle (cr,
+ width - 2, height - 4,
+ 2, 2);
+ cairo_fill (cr);
+ cairo_set_source_rgb (cr, 0, 1, 0);
+ cairo_rectangle (cr,
+ width - 4, height - 2,
+ 2, 2);
+ cairo_fill (cr);
+ cairo_set_source_rgb (cr, 0, 0, 1);
+ cairo_rectangle (cr,
+ width - 2, height - 2,
+ 2, 2);
+ cairo_fill (cr);
+
+ similar = cairo_surface_reference (cairo_get_target (cr));
+ cairo_destroy (cr);
+
+ return similar;
+}
+
+static void
+draw_grid (cairo_t *cr, cairo_pattern_t *pattern, int dst_x, int dst_y)
+{
+ cairo_matrix_t m;
+
+ cairo_save (cr);
+ cairo_translate (cr, dst_x, dst_y);
+ cairo_scale (cr, 16, 16);
+ cairo_rotate (cr, 1);
+
+ cairo_matrix_init_translate (&m, 2560-4, 1280-4);
+ cairo_pattern_set_matrix (pattern, &m);
+ cairo_set_source (cr, pattern);
+ cairo_rectangle (cr, 0, 0, 4, 4);
+ cairo_fill (cr);
+
+ cairo_set_source_rgb (cr, .7, .7, .7);
+ cairo_set_line_width (cr, 1./16);
+ cairo_move_to (cr, 0, 0);
+ cairo_line_to (cr, 4, 0);
+ cairo_move_to (cr, 0, 2);
+ cairo_line_to (cr, 4, 2);
+ cairo_move_to (cr, 0, 4);
+ cairo_line_to (cr, 4, 4);
+ cairo_move_to (cr, 0, 0);
+ cairo_line_to (cr, 0, 4);
+ cairo_move_to (cr, 2, 0);
+ cairo_line_to (cr, 2, 4);
+ cairo_move_to (cr, 4, 0);
+ cairo_line_to (cr, 4, 4);
+ cairo_stroke (cr);
+
+ cairo_restore (cr);
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_surface_t *source;
+ cairo_pattern_t *pattern;
+
+ cairo_paint (cr);
+
+ source = create_source (cairo_get_target (cr), 2560, 1280);
+ pattern = cairo_pattern_create_for_surface (source);
+ cairo_surface_destroy (source);
+
+ cairo_pattern_set_filter (pattern, CAIRO_FILTER_NEAREST);
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_NONE);
+
+ draw_grid (cr, pattern, 50, 0);
+ draw_grid (cr, pattern, 130, 0);
+ draw_grid (cr, pattern, 210, 0);
+ draw_grid (cr, pattern, 290, 0);
+
+ draw_grid (cr, pattern, 50, 230);
+ draw_grid (cr, pattern, 130, 230);
+ draw_grid (cr, pattern, 210, 230);
+ draw_grid (cr, pattern, 290, 230);
+
+ cairo_pattern_destroy (pattern);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (scale_offset_image,
+ "Tests drawing surfaces under various scales and transforms",
+ "XFAIL=!ps surface scale-offset", /* keywords */
+ NULL, /* requirements */
+ 320, 320,
+ NULL, draw)
+
diff --git a/test/scale-offset-image.ps.ref.png b/test/scale-offset-image.ps.ref.png
new file mode 100644
index 00000000..1aed28d3
--- /dev/null
+++ b/test/scale-offset-image.ps.ref.png
Binary files differ
diff --git a/test/scale-offset-image.ref.png b/test/scale-offset-image.ref.png
new file mode 100644
index 00000000..8c6b0fe2
--- /dev/null
+++ b/test/scale-offset-image.ref.png
Binary files differ
diff --git a/test/scale-offset-similar.c b/test/scale-offset-similar.c
new file mode 100644
index 00000000..074ce05e
--- /dev/null
+++ b/test/scale-offset-similar.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2008 Chris Wilson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Chris Wilson not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Chris Wilson makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+/*
+ * Test case derived from the bug report by Michel Iwaniec:
+ * http://lists.cairographics.org/archives/cairo/2008-November/015660.html
+ */
+
+#include "cairo-test.h"
+
+static cairo_surface_t *
+create_source (cairo_surface_t *target, int width, int height)
+{
+ cairo_surface_t *similar;
+ cairo_t *cr;
+
+ similar = cairo_surface_create_similar (target,
+ CAIRO_CONTENT_COLOR,
+ width, height);
+ cr = cairo_create (similar);
+ cairo_surface_destroy (similar);
+
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_rectangle (cr,
+ width - 4, height - 4,
+ 2, 2);
+ cairo_fill (cr);
+ cairo_set_source_rgb (cr, 1, 0, 0);
+ cairo_rectangle (cr,
+ width - 2, height - 4,
+ 2, 2);
+ cairo_fill (cr);
+ cairo_set_source_rgb (cr, 0, 1, 0);
+ cairo_rectangle (cr,
+ width - 4, height - 2,
+ 2, 2);
+ cairo_fill (cr);
+ cairo_set_source_rgb (cr, 0, 0, 1);
+ cairo_rectangle (cr,
+ width - 2, height - 2,
+ 2, 2);
+ cairo_fill (cr);
+
+ similar = cairo_surface_reference (cairo_get_target (cr));
+ cairo_destroy (cr);
+
+ return similar;
+}
+
+static void
+draw_grid (cairo_t *cr, cairo_pattern_t *pattern, int dst_x, int dst_y)
+{
+ cairo_matrix_t m;
+
+ cairo_save (cr);
+ cairo_translate (cr, dst_x, dst_y);
+ cairo_scale (cr, 16, 16);
+ cairo_rotate (cr, 1);
+
+ cairo_matrix_init_translate (&m, 2560-4, 1280-4);
+ cairo_pattern_set_matrix (pattern, &m);
+ cairo_set_source (cr, pattern);
+ cairo_rectangle (cr, 0, 0, 4, 4);
+ cairo_fill (cr);
+
+ cairo_set_source_rgb (cr, .7, .7, .7);
+ cairo_set_line_width (cr, 1./16);
+ cairo_move_to (cr, 0, 0);
+ cairo_line_to (cr, 4, 0);
+ cairo_move_to (cr, 0, 2);
+ cairo_line_to (cr, 4, 2);
+ cairo_move_to (cr, 0, 4);
+ cairo_line_to (cr, 4, 4);
+ cairo_move_to (cr, 0, 0);
+ cairo_line_to (cr, 0, 4);
+ cairo_move_to (cr, 2, 0);
+ cairo_line_to (cr, 2, 4);
+ cairo_move_to (cr, 4, 0);
+ cairo_line_to (cr, 4, 4);
+ cairo_stroke (cr);
+
+ cairo_restore (cr);
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_surface_t *source;
+ cairo_pattern_t *pattern;
+
+ cairo_paint (cr);
+
+ source = create_source (cairo_get_target (cr), 2560, 1280);
+ pattern = cairo_pattern_create_for_surface (source);
+ cairo_surface_destroy (source);
+
+ cairo_pattern_set_filter (pattern, CAIRO_FILTER_NEAREST);
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_NONE);
+
+ draw_grid (cr, pattern, 50, 0);
+ draw_grid (cr, pattern, 130, 0);
+ draw_grid (cr, pattern, 210, 0);
+ draw_grid (cr, pattern, 290, 0);
+
+ draw_grid (cr, pattern, 50, 230);
+ draw_grid (cr, pattern, 130, 230);
+ draw_grid (cr, pattern, 210, 230);
+ draw_grid (cr, pattern, 290, 230);
+
+ cairo_pattern_destroy (pattern);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (scale_offset_similar,
+ "Tests drawing surfaces under various scales and transforms",
+ "XFAIL=!ps surface scale-offset", /* keywords */
+ NULL, /* requirements */
+ 320, 320,
+ NULL, draw)
+
diff --git a/test/scale-offset-similar.ps.ref.png b/test/scale-offset-similar.ps.ref.png
new file mode 100644
index 00000000..7002b2ef
--- /dev/null
+++ b/test/scale-offset-similar.ps.ref.png
Binary files differ
diff --git a/test/scale-offset-similar.ref.png b/test/scale-offset-similar.ref.png
new file mode 100644
index 00000000..8c6b0fe2
--- /dev/null
+++ b/test/scale-offset-similar.ref.png
Binary files differ
diff --git a/test/scarab.jpg b/test/scarab.jpg
new file mode 100644
index 00000000..6a66ff78
--- /dev/null
+++ b/test/scarab.jpg
Binary files differ
diff --git a/test/smask-fill.pdf.argb32.ref.png b/test/smask-fill.pdf.argb32.ref.png
new file mode 100644
index 00000000..51d34d43
--- /dev/null
+++ b/test/smask-fill.pdf.argb32.ref.png
Binary files differ
diff --git a/test/smask-fill.pdf.rgb24.ref.png b/test/smask-fill.pdf.rgb24.ref.png
new file mode 100644
index 00000000..51d34d43
--- /dev/null
+++ b/test/smask-fill.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/smask-fill.ref.png b/test/smask-fill.ref.png
index c778a791..28ab7338 100644
--- a/test/smask-fill.ref.png
+++ b/test/smask-fill.ref.png
Binary files differ
diff --git a/test/smask-fill.svg11.argb32.ref.png b/test/smask-fill.svg11.argb32.ref.png
new file mode 100644
index 00000000..57ae76e6
--- /dev/null
+++ b/test/smask-fill.svg11.argb32.ref.png
Binary files differ
diff --git a/test/smask-fill.svg11.rgb24.ref.png b/test/smask-fill.svg11.rgb24.ref.png
new file mode 100644
index 00000000..57ae76e6
--- /dev/null
+++ b/test/smask-fill.svg11.rgb24.ref.png
Binary files differ
diff --git a/test/smask-fill.svg12.argb32.ref.png b/test/smask-fill.svg12.argb32.ref.png
new file mode 100644
index 00000000..57ae76e6
--- /dev/null
+++ b/test/smask-fill.svg12.argb32.ref.png
Binary files differ
diff --git a/test/smask-fill.svg12.rgb24.ref.png b/test/smask-fill.svg12.rgb24.ref.png
new file mode 100644
index 00000000..57ae76e6
--- /dev/null
+++ b/test/smask-fill.svg12.rgb24.ref.png
Binary files 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 00000000..3d375bba
--- /dev/null
+++ b/test/smask-fill.test-fallback.argb32.ref.png
Binary files 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 00000000..3d375bba
--- /dev/null
+++ b/test/smask-fill.test-fallback.rgb24.ref.png
Binary files differ
diff --git a/test/smask-fill.xlib-fallback.ref.png b/test/smask-fill.xlib-fallback.ref.png
new file mode 100644
index 00000000..28ab7338
--- /dev/null
+++ b/test/smask-fill.xlib-fallback.ref.png
Binary files differ
diff --git a/test/smask-fill.xlib.ref.png b/test/smask-fill.xlib.ref.png
new file mode 100644
index 00000000..c778a791
--- /dev/null
+++ b/test/smask-fill.xlib.ref.png
Binary files 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 00000000..19a20f48
--- /dev/null
+++ b/test/smask-image-mask.pdf.argb32.ref.png
Binary files 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 00000000..19a20f48
--- /dev/null
+++ b/test/smask-image-mask.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/smask-mask.pdf.argb32.ref.png b/test/smask-mask.pdf.argb32.ref.png
new file mode 100644
index 00000000..0dc2135d
--- /dev/null
+++ b/test/smask-mask.pdf.argb32.ref.png
Binary files differ
diff --git a/test/smask-mask.pdf.rgb24.ref.png b/test/smask-mask.pdf.rgb24.ref.png
new file mode 100644
index 00000000..0dc2135d
--- /dev/null
+++ b/test/smask-mask.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/smask-paint.pdf.argb32.ref.png b/test/smask-paint.pdf.argb32.ref.png
new file mode 100644
index 00000000..c6b1731f
--- /dev/null
+++ b/test/smask-paint.pdf.argb32.ref.png
Binary files differ
diff --git a/test/smask-paint.pdf.rgb24.ref.png b/test/smask-paint.pdf.rgb24.ref.png
new file mode 100644
index 00000000..c6b1731f
--- /dev/null
+++ b/test/smask-paint.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/smask-stroke.pdf.argb32.ref.png b/test/smask-stroke.pdf.argb32.ref.png
new file mode 100644
index 00000000..41321f23
--- /dev/null
+++ b/test/smask-stroke.pdf.argb32.ref.png
Binary files differ
diff --git a/test/smask-stroke.pdf.rgb24.ref.png b/test/smask-stroke.pdf.rgb24.ref.png
new file mode 100644
index 00000000..41321f23
--- /dev/null
+++ b/test/smask-stroke.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/smask-text.svg11.argb32.ref.png b/test/smask-text.svg11.argb32.ref.png
new file mode 100644
index 00000000..5034526a
--- /dev/null
+++ b/test/smask-text.svg11.argb32.ref.png
Binary files differ
diff --git a/test/smask-text.svg11.rgb24.ref.png b/test/smask-text.svg11.rgb24.ref.png
new file mode 100644
index 00000000..5034526a
--- /dev/null
+++ b/test/smask-text.svg11.rgb24.ref.png
Binary files differ
diff --git a/test/smask-text.svg12.argb32.ref.png b/test/smask-text.svg12.argb32.ref.png
new file mode 100644
index 00000000..5034526a
--- /dev/null
+++ b/test/smask-text.svg12.argb32.ref.png
Binary files differ
diff --git a/test/smask-text.svg12.rgb24.ref.png b/test/smask-text.svg12.rgb24.ref.png
new file mode 100644
index 00000000..5034526a
--- /dev/null
+++ b/test/smask-text.svg12.rgb24.ref.png
Binary files differ
diff --git a/test/smask.pdf.argb32.ref.png b/test/smask.pdf.argb32.ref.png
new file mode 100644
index 00000000..c6b1731f
--- /dev/null
+++ b/test/smask.pdf.argb32.ref.png
Binary files differ
diff --git a/test/smask.pdf.rgb24.ref.png b/test/smask.pdf.rgb24.ref.png
new file mode 100644
index 00000000..c6b1731f
--- /dev/null
+++ b/test/smask.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/surface-pattern-scale-down.pdf.argb32.ref.png b/test/surface-pattern-scale-down.pdf.argb32.ref.png
index c29d804c..dc4b3a31 100644
--- a/test/surface-pattern-scale-down.pdf.argb32.ref.png
+++ b/test/surface-pattern-scale-down.pdf.argb32.ref.png
Binary files differ
diff --git a/test/surface-pattern-scale-down.pdf.rgb24.ref.png b/test/surface-pattern-scale-down.pdf.rgb24.ref.png
index c29d804c..dc4b3a31 100644
--- a/test/surface-pattern-scale-down.pdf.rgb24.ref.png
+++ b/test/surface-pattern-scale-down.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/surface-pattern-scale-up.pdf.argb32.ref.png b/test/surface-pattern-scale-up.pdf.argb32.ref.png
index 6f3a53c5..c0a2896a 100644
--- a/test/surface-pattern-scale-up.pdf.argb32.ref.png
+++ b/test/surface-pattern-scale-up.pdf.argb32.ref.png
Binary files differ
diff --git a/test/surface-pattern-scale-up.pdf.rgb24.ref.png b/test/surface-pattern-scale-up.pdf.rgb24.ref.png
index 6f3a53c5..c0a2896a 100644
--- a/test/surface-pattern-scale-up.pdf.rgb24.ref.png
+++ b/test/surface-pattern-scale-up.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/surface-pattern.pdf.argb32.ref.png b/test/surface-pattern.pdf.argb32.ref.png
new file mode 100644
index 00000000..70a44767
--- /dev/null
+++ b/test/surface-pattern.pdf.argb32.ref.png
Binary files differ
diff --git a/test/surface-pattern.pdf.ref.png b/test/surface-pattern.pdf.ref.png
index bfb34788..ff9131c2 100644
--- a/test/surface-pattern.pdf.ref.png
+++ b/test/surface-pattern.pdf.ref.png
Binary files differ
diff --git a/test/surface-pattern.pdf.rgb24.ref.png b/test/surface-pattern.pdf.rgb24.ref.png
new file mode 100644
index 00000000..70a44767
--- /dev/null
+++ b/test/surface-pattern.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/surface-pattern.ref.png b/test/surface-pattern.ref.png
index d1c2b335..db60da6f 100644
--- a/test/surface-pattern.ref.png
+++ b/test/surface-pattern.ref.png
Binary files differ
diff --git a/test/surface-pattern.svg.ref.png b/test/surface-pattern.svg.ref.png
new file mode 100644
index 00000000..cdbcf476
--- /dev/null
+++ b/test/surface-pattern.svg.ref.png
Binary files differ
diff --git a/test/surface-pattern.svg11.ref.png b/test/surface-pattern.svg11.ref.png
deleted file mode 100644
index 5569a557..00000000
--- a/test/surface-pattern.svg11.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/surface-pattern.svg12.ref.png b/test/surface-pattern.svg12.ref.png
deleted file mode 100644
index 5569a557..00000000
--- a/test/surface-pattern.svg12.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/text-pattern.pdf.argb32.ref.png b/test/text-pattern.pdf.argb32.ref.png
index 2a70deb0..dfaed39f 100644
--- a/test/text-pattern.pdf.argb32.ref.png
+++ b/test/text-pattern.pdf.argb32.ref.png
Binary files differ
diff --git a/test/text-pattern.svg11.argb32.ref.png b/test/text-pattern.svg11.argb32.ref.png
index 97d7534c..47ee89c2 100644
--- a/test/text-pattern.svg11.argb32.ref.png
+++ b/test/text-pattern.svg11.argb32.ref.png
Binary files differ
diff --git a/test/text-pattern.svg12.argb32.ref.png b/test/text-pattern.svg12.argb32.ref.png
index 97d7534c..47ee89c2 100644
--- a/test/text-pattern.svg12.argb32.ref.png
+++ b/test/text-pattern.svg12.argb32.ref.png
Binary files differ
diff --git a/test/text-rotate.svg11.argb32.ref.png b/test/text-rotate.svg11.argb32.ref.png
new file mode 100644
index 00000000..4864046f
--- /dev/null
+++ b/test/text-rotate.svg11.argb32.ref.png
Binary files differ
diff --git a/test/text-rotate.svg11.rgb24.ref.png b/test/text-rotate.svg11.rgb24.ref.png
new file mode 100644
index 00000000..4864046f
--- /dev/null
+++ b/test/text-rotate.svg11.rgb24.ref.png
Binary files differ
diff --git a/test/text-rotate.svg12.argb32.ref.png b/test/text-rotate.svg12.argb32.ref.png
new file mode 100644
index 00000000..4864046f
--- /dev/null
+++ b/test/text-rotate.svg12.argb32.ref.png
Binary files differ
diff --git a/test/text-rotate.svg12.rgb24.ref.png b/test/text-rotate.svg12.rgb24.ref.png
new file mode 100644
index 00000000..4864046f
--- /dev/null
+++ b/test/text-rotate.svg12.rgb24.ref.png
Binary files differ
diff --git a/test/text-transform.svg11.argb32.ref.png b/test/text-transform.svg11.argb32.ref.png
new file mode 100644
index 00000000..0c4e57cc
--- /dev/null
+++ b/test/text-transform.svg11.argb32.ref.png
Binary files differ
diff --git a/test/text-transform.svg11.rgb24.ref.png b/test/text-transform.svg11.rgb24.ref.png
new file mode 100644
index 00000000..0c4e57cc
--- /dev/null
+++ b/test/text-transform.svg11.rgb24.ref.png
Binary files differ
diff --git a/test/text-transform.svg12.argb32.ref.png b/test/text-transform.svg12.argb32.ref.png
new file mode 100644
index 00000000..0c4e57cc
--- /dev/null
+++ b/test/text-transform.svg12.argb32.ref.png
Binary files differ
diff --git a/test/text-transform.svg12.rgb24.ref.png b/test/text-transform.svg12.rgb24.ref.png
new file mode 100644
index 00000000..0c4e57cc
--- /dev/null
+++ b/test/text-transform.svg12.rgb24.ref.png
Binary files differ
diff --git a/test/trap-clip.pdf.argb32.ref.png b/test/trap-clip.pdf.argb32.ref.png
index c3ee9971..15010164 100644
--- a/test/trap-clip.pdf.argb32.ref.png
+++ b/test/trap-clip.pdf.argb32.ref.png
Binary files differ
diff --git a/test/trap-clip.pdf.rgb24.ref.png b/test/trap-clip.pdf.rgb24.ref.png
index f787011c..06163675 100644
--- a/test/trap-clip.pdf.rgb24.ref.png
+++ b/test/trap-clip.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/trap-clip.ps2.argb32.ref.png b/test/trap-clip.ps2.argb32.ref.png
index 37121cde..957b9382 100644
--- a/test/trap-clip.ps2.argb32.ref.png
+++ b/test/trap-clip.ps2.argb32.ref.png
Binary files differ
diff --git a/test/trap-clip.ref.png b/test/trap-clip.ref.png
index 2cbbdb76..e8c26d32 100644
--- a/test/trap-clip.ref.png
+++ b/test/trap-clip.ref.png
Binary files differ
diff --git a/test/trap-clip.rgb24.ref.png b/test/trap-clip.rgb24.ref.png
index 15068aa5..e61992ff 100644
--- a/test/trap-clip.rgb24.ref.png
+++ b/test/trap-clip.rgb24.ref.png
Binary files 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 00000000..319d8356
--- /dev/null
+++ b/test/trap-clip.test-fallback.argb32.ref.png
Binary files 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 00000000..7ac5789b
--- /dev/null
+++ b/test/trap-clip.test-fallback.rgb24.ref.png
Binary files 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 00000000..dee57e7b
--- /dev/null
+++ b/test/trap-clip.test-paginated.argb32.ref.png
Binary files differ
diff --git a/test/trap-clip.xlib.ref.png b/test/trap-clip.xlib.ref.png
new file mode 100644
index 00000000..2cbbdb76
--- /dev/null
+++ b/test/trap-clip.xlib.ref.png
Binary files differ
diff --git a/test/trap-clip.xlib.rgb24.ref.png b/test/trap-clip.xlib.rgb24.ref.png
new file mode 100644
index 00000000..15068aa5
--- /dev/null
+++ b/test/trap-clip.xlib.rgb24.ref.png
Binary files differ
diff --git a/test/twin.c b/test/twin.c
index 34851f47..a53b796e 100644
--- a/test/twin.c
+++ b/test/twin.c
@@ -48,5 +48,5 @@ CAIRO_TEST (twin,
"Tests the internal font",
"twin, font", /* keywords */
NULL, /* requirements */
- 128, 20,
+ 132, 20,
NULL, draw)
diff --git a/test/twin.pdf.ref.png b/test/twin.pdf.ref.png
new file mode 100644
index 00000000..b9121e06
--- /dev/null
+++ b/test/twin.pdf.ref.png
Binary files differ
diff --git a/test/twin.ps2.ref.png b/test/twin.ps2.ref.png
index a58dc5b6..7fc3f35a 100644
--- a/test/twin.ps2.ref.png
+++ b/test/twin.ps2.ref.png
Binary files differ
diff --git a/test/twin.ps3.ref.png b/test/twin.ps3.ref.png
index a58dc5b6..7fc3f35a 100644
--- a/test/twin.ps3.ref.png
+++ b/test/twin.ps3.ref.png
Binary files differ
diff --git a/test/twin.ref.png b/test/twin.ref.png
index f2a5636d..29c2e9e0 100644
--- a/test/twin.ref.png
+++ b/test/twin.ref.png
Binary files differ
diff --git a/test/twin.svg11.argb32.ref.png b/test/twin.svg11.argb32.ref.png
new file mode 100644
index 00000000..0818c67c
--- /dev/null
+++ b/test/twin.svg11.argb32.ref.png
Binary files differ
diff --git a/test/twin.svg11.ref.png b/test/twin.svg11.ref.png
index 5b7d67d4..46503966 100644
--- a/test/twin.svg11.ref.png
+++ b/test/twin.svg11.ref.png
Binary files differ
diff --git a/test/twin.svg11.rgb24.ref.png b/test/twin.svg11.rgb24.ref.png
new file mode 100644
index 00000000..0818c67c
--- /dev/null
+++ b/test/twin.svg11.rgb24.ref.png
Binary files differ
diff --git a/test/twin.svg12.argb32.ref.png b/test/twin.svg12.argb32.ref.png
new file mode 100644
index 00000000..0818c67c
--- /dev/null
+++ b/test/twin.svg12.argb32.ref.png
Binary files differ
diff --git a/test/twin.svg12.ref.png b/test/twin.svg12.ref.png
index 5b7d67d4..46503966 100644
--- a/test/twin.svg12.ref.png
+++ b/test/twin.svg12.ref.png
Binary files differ
diff --git a/test/twin.svg12.rgb24.ref.png b/test/twin.svg12.rgb24.ref.png
new file mode 100644
index 00000000..0818c67c
--- /dev/null
+++ b/test/twin.svg12.rgb24.ref.png
Binary files differ
diff --git a/test/unbounded-operator.pdf.argb32.ref.png b/test/unbounded-operator.pdf.argb32.ref.png
new file mode 100644
index 00000000..4aa476de
--- /dev/null
+++ b/test/unbounded-operator.pdf.argb32.ref.png
Binary files differ
diff --git a/test/unbounded-operator.ps2.argb32.ref.png b/test/unbounded-operator.ps2.argb32.ref.png
new file mode 100644
index 00000000..4aa476de
--- /dev/null
+++ b/test/unbounded-operator.ps2.argb32.ref.png
Binary files differ
diff --git a/test/unbounded-operator.ps3.argb32.ref.png b/test/unbounded-operator.ps3.argb32.ref.png
new file mode 100644
index 00000000..4aa476de
--- /dev/null
+++ b/test/unbounded-operator.ps3.argb32.ref.png
Binary files differ
diff --git a/test/unbounded-operator.rgb24.ref.png b/test/unbounded-operator.rgb24.ref.png
index b2f1a84d..ad3225d0 100644
--- a/test/unbounded-operator.rgb24.ref.png
+++ b/test/unbounded-operator.rgb24.ref.png
Binary files 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 00000000..07c7ecff
--- /dev/null
+++ b/test/unbounded-operator.test-fallback.rgb24.ref.png
Binary files differ
diff --git a/test/unbounded-operator.xlib.rgb24.ref.png b/test/unbounded-operator.xlib.rgb24.ref.png
new file mode 100644
index 00000000..b2f1a84d
--- /dev/null
+++ b/test/unbounded-operator.xlib.rgb24.ref.png
Binary files 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 00000000..cffa9edb
--- /dev/null
+++ b/test/user-font-proxy.pdf.argb32.ref.png
Binary files 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 00000000..cffa9edb
--- /dev/null
+++ b/test/user-font-proxy.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/user-font-proxy.ref.png b/test/user-font-proxy.ref.png
index ebd97198..cffa9edb 100644
--- a/test/user-font-proxy.ref.png
+++ b/test/user-font-proxy.ref.png
Binary files 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 00000000..d2a7812b
--- /dev/null
+++ b/test/user-font-proxy.svg11.argb32.ref.png
Binary files 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 00000000..d2a7812b
--- /dev/null
+++ b/test/user-font-proxy.svg11.rgb24.ref.png
Binary files 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 00000000..d2a7812b
--- /dev/null
+++ b/test/user-font-proxy.svg12.argb32.ref.png
Binary files 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 00000000..d2a7812b
--- /dev/null
+++ b/test/user-font-proxy.svg12.rgb24.ref.png
Binary files 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 00000000..9cccf312
--- /dev/null
+++ b/test/user-font-proxy.test-fallback.argb32.ref.png
Binary files 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 00000000..9cccf312
--- /dev/null
+++ b/test/user-font-proxy.test-fallback.rgb24.ref.png
Binary files differ
diff --git a/test/user-font-proxy.xlib.ref.png b/test/user-font-proxy.xlib.ref.png
new file mode 100644
index 00000000..ebd97198
--- /dev/null
+++ b/test/user-font-proxy.xlib.ref.png
Binary files differ
diff --git a/test/user-font.ref.png b/test/user-font.ref.png
index abc31171..753fc7bc 100644
--- a/test/user-font.ref.png
+++ b/test/user-font.ref.png
Binary files differ
diff --git a/test/user-font.svg11.argb32.ref.png b/test/user-font.svg11.argb32.ref.png
new file mode 100644
index 00000000..3dc77ae4
--- /dev/null
+++ b/test/user-font.svg11.argb32.ref.png
Binary files differ
diff --git a/test/user-font.svg11.rgb24.ref.png b/test/user-font.svg11.rgb24.ref.png
new file mode 100644
index 00000000..3dc77ae4
--- /dev/null
+++ b/test/user-font.svg11.rgb24.ref.png
Binary files differ
diff --git a/test/user-font.svg12.argb32.ref.png b/test/user-font.svg12.argb32.ref.png
new file mode 100644
index 00000000..3dc77ae4
--- /dev/null
+++ b/test/user-font.svg12.argb32.ref.png
Binary files differ
diff --git a/test/user-font.svg12.rgb24.ref.png b/test/user-font.svg12.rgb24.ref.png
new file mode 100644
index 00000000..3dc77ae4
--- /dev/null
+++ b/test/user-font.svg12.rgb24.ref.png
Binary files 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 00000000..3080c694
--- /dev/null
+++ b/test/user-font.test-fallback.argb32.ref.png
Binary files 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 00000000..3080c694
--- /dev/null
+++ b/test/user-font.test-fallback.rgb24.ref.png
Binary files differ
diff --git a/test/user-font.xlib.ref.png b/test/user-font.xlib.ref.png
new file mode 100644
index 00000000..abc31171
--- /dev/null
+++ b/test/user-font.xlib.ref.png
Binary files differ
diff --git a/util/Makefile.am b/util/Makefile.am
index 42c831c9..f272e4c4 100644
--- a/util/Makefile.am
+++ b/util/Makefile.am
@@ -1,6 +1,6 @@
include $(top_srcdir)/build/Makefile.am.common
-SUBDIRS = .
+SUBDIRS = . cairo-script
if BUILD_TRACE
SUBDIRS += cairo-trace
diff --git a/util/cairo-script/.gitignore b/util/cairo-script/.gitignore
new file mode 100644
index 00000000..d56f76e8
--- /dev/null
+++ b/util/cairo-script/.gitignore
@@ -0,0 +1 @@
+csi-replay
diff --git a/util/cairo-script/COPYING b/util/cairo-script/COPYING
new file mode 100644
index 00000000..66ad7840
--- /dev/null
+++ b/util/cairo-script/COPYING
@@ -0,0 +1,17 @@
+Cairo is free software.
+
+Every source file in the implementation of cairo is available to be
+redistributed and/or modified under the terms of either the GNU Lesser
+General Public License (LGPL) version 2.1 or the Mozilla Public
+License (MPL) version 1.1. Some files are available under more
+liberal terms, but we believe that in all cases, each file may be used
+under either the LGPL or the MPL.
+
+See the following files in this directory for the precise terms and
+conditions of either license:
+
+ COPYING-LGPL-2.1
+ COPYING-MPL-1.1
+
+Please see each file in the implementation for copyright and licensing
+information, (in the opening comment of each file).
diff --git a/util/cairo-script/Makefile.am b/util/cairo-script/Makefile.am
new file mode 100644
index 00000000..b6ab355e
--- /dev/null
+++ b/util/cairo-script/Makefile.am
@@ -0,0 +1,26 @@
+lib_LTLIBRARIES = libcairo-script-interpreter.la
+noinst_PROGRAMS = csi-replay
+
+AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src
+
+cairoincludedir=$(includedir)/cairo
+cairoinclude_HEADERS = cairo-script-interpreter.h
+libcairo_script_interpreter_la_SOURCES = \
+ cairo-script-private.h \
+ cairo-script-file.c \
+ cairo-script-hash.c \
+ cairo-script-interpreter.c \
+ cairo-script-objects.c \
+ cairo-script-operators.c \
+ cairo-script-scanner.c \
+ cairo-script-stack.c \
+ $(NULL)
+libcairo_script_interpreter_la_CFLAGS = $(CAIRO_CFLAGS)
+libcairo_script_interpreter_la_LDFLAGS = -version-info $(CAIRO_LIBTOOL_VERSION_INFO) -no-undefined $(export_symbols)
+libcairo_script_interpreter_la_LIBADD = $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
+
+csi_replay_SOURCES = csi-replay.c
+csi_replay_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
+
+EXTRA_DIST = \
+ COPYING
diff --git a/util/cairo-script/cairo-script-file.c b/util/cairo-script/cairo-script-file.c
new file mode 100644
index 00000000..fcdccf14
--- /dev/null
+++ b/util/cairo-script/cairo-script-file.c
@@ -0,0 +1,1021 @@
+/*
+ * Copyright © 2008 Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Chris Wilson.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairo-script-private.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#define CHUNK_SIZE 32768
+
+csi_status_t
+csi_file_new (csi_t *ctx,
+ csi_object_t *obj,
+ const char *path, const char *mode)
+{
+ csi_file_t *file;
+
+ file = _csi_slab_alloc (ctx, sizeof (csi_file_t));
+ if (file == NULL)
+ return _csi_error (CAIRO_STATUS_NO_MEMORY);
+
+ file->base.type = CSI_OBJECT_TYPE_FILE;
+ file->base.ref = 1;
+
+ file->data = NULL;
+ file->type = STDIO;
+ file->src = fopen (path, mode);
+ if (file->src == NULL) {
+ _csi_slab_free (ctx, file, sizeof (csi_file_t));
+ return _csi_error (CAIRO_STATUS_FILE_NOT_FOUND);
+ }
+
+ file->data = _csi_alloc (ctx, CHUNK_SIZE);
+ if (file->data == NULL) {
+ _csi_slab_free (ctx, file, sizeof (csi_file_t));
+ return _csi_error (CAIRO_STATUS_NO_MEMORY);
+ }
+ file->bp = file->data;
+ file->rem = 0;
+
+ obj->type = CSI_OBJECT_TYPE_FILE;
+ obj->datum.file = file;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+csi_status_t
+csi_file_new_for_bytes (csi_t *ctx,
+ csi_object_t *obj,
+ const char *bytes,
+ unsigned int length)
+{
+ csi_file_t *file;
+
+ file = _csi_slab_alloc (ctx, sizeof (csi_file_t));
+ if (file == NULL)
+ return _csi_error (CAIRO_STATUS_NO_MEMORY);
+
+ file->base.type = CSI_OBJECT_TYPE_FILE;
+ file->base.ref = 1;
+
+ file->type = BYTES;
+ file->src = (uint8_t *) bytes;
+ file->data = (uint8_t *) bytes;
+ file->bp = (uint8_t *) bytes;
+ file->rem = length;
+
+ obj->type = CSI_OBJECT_TYPE_FILE;
+ obj->datum.file = file;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+csi_status_t
+csi_file_new_from_string (csi_t *ctx,
+ csi_object_t *obj,
+ csi_string_t *src)
+{
+ csi_file_t *file;
+
+ file = _csi_slab_alloc (ctx, sizeof (csi_file_t));
+ if (file == NULL)
+ return _csi_error (CAIRO_STATUS_NO_MEMORY);
+
+ file->base.type = CSI_OBJECT_TYPE_FILE;
+ file->base.ref = 1;
+
+ file->type = BYTES;
+ file->src = src; src->base.ref++;
+ file->data = src->string;
+ file->bp = file->data;
+ file->rem = src->len;
+
+ obj->type = CSI_OBJECT_TYPE_FILE;
+ obj->datum.file = file;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_csi_file_new_filter (csi_t *ctx,
+ csi_object_t *obj,
+ csi_object_t *src,
+ const csi_filter_funcs_t *funcs,
+ void *data)
+{
+ csi_file_t *file;
+ csi_object_t src_file;
+ csi_status_t status;
+
+ file = _csi_slab_alloc (ctx, sizeof (csi_file_t));
+ if (file == NULL)
+ return _csi_error (CAIRO_STATUS_NO_MEMORY);
+
+ obj->type = CSI_OBJECT_TYPE_FILE;
+ obj->datum.file = file;
+
+ file->base.type = CSI_OBJECT_TYPE_FILE;
+ file->base.ref = 1;
+
+ file->type = FILTER;
+ file->data = data;
+ file->filter = funcs;
+ status = csi_object_as_file (ctx, src, &src_file);
+ if (status) {
+ csi_object_free (ctx, obj);
+ return status;
+ }
+ file->src = src_file.datum.file;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+
+#if 0
+csi_status_t
+csi_file_new_from_stream (csi_t *ctx,
+ FILE *file,
+ csi_object_t **out)
+{
+ csi_file_t *obj;
+
+ obj = (csi_file_t *) _csi_object_new (ctx, CSI_OBJECT_TYPE_FILE);
+ if (obj == NULL)
+ return _csi_error (CAIRO_STATUS_NO_MEMORY);
+
+ obj->type = STDIO;
+ obj->src = file;
+ obj->data = _csi_alloc (ctx, CHUNK_SIZE);
+ if (obj->data == NULL) {
+ csi_object_free (&obj->base);
+ return _csi_error (CAIRO_STATUS_UNDEFINED_FILENAME_ERROR);
+ }
+ obj->bp = obj->data;
+ obj->rem = 0;
+
+ *out = &obj->base;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static csi_object_t *
+_csi_file_new_from_procedure (csi_t *ctx, csi_object_t *src)
+{
+ csi_file_t *obj;
+
+ obj = (csi_file_t *) _csi_object_new (ctx, CSI_OBJECT_TYPE_FILE);
+ if (obj == NULL)
+ return NULL;
+
+ obj->type = PROCEDURE;
+ obj->src = csi_object_reference (src);
+ obj->data = NULL;
+
+ return &obj->base;
+}
+#endif
+
+typedef struct _ascii85_decode_data {
+ uint8_t buf[CHUNK_SIZE];
+ uint8_t *bp;
+ short bytes_available;
+ short eod;
+} _ascii85_decode_data_t;
+
+static int
+_getc_skip_whitespace (csi_file_t *src)
+{
+ int c;
+
+ do switch ((c = csi_file_getc (src))) {
+ case 0x0:
+ case 0x9:
+ case 0xa:
+ case 0xc:
+ case 0xd:
+ case 0x20:
+ continue;
+
+ default:
+ return c;
+ } while (TRUE);
+
+ return c;
+}
+
+static void
+_ascii85_decode (csi_file_t *file)
+{
+ _ascii85_decode_data_t *data = file->data;
+ unsigned int n;
+
+ if (data->eod)
+ return;
+
+ data->bp = data->buf;
+
+ n = 0;
+ do {
+ unsigned int v = _getc_skip_whitespace (file->src);
+ if (v == 'z') {
+ data->buf[n+0] = 0;
+ data->buf[n+1] = 0;
+ data->buf[n+2] = 0;
+ data->buf[n+3] = 0;
+ } else if (v == '~') {
+ v = _getc_skip_whitespace (file->src);
+ /* c == '>' || IO_ERROR */
+ data->eod = TRUE;
+ break;
+ } else if (v < '!' || v > 'u') {
+ /* IO_ERROR */
+ data->eod = TRUE;
+ break;
+ } else {
+ unsigned int i;
+
+ v -= '!';
+ for (i = 1; i < 5; i++) {
+ int c = _getc_skip_whitespace (file->src);
+ if (c == '~') { /* short tuple */
+ c = _getc_skip_whitespace (file->src);
+ /* c == '>' || IO_ERROR */
+ data->eod = TRUE;
+ switch (i) {
+ case 0:
+ case 1:
+ /* IO_ERROR */
+ break;
+ case 2:
+ v = v * (85*85*85) + 85*85*85 -1;
+ goto odd1;
+ case 3:
+ v = v * (85*85) + 85*85 -1;
+ goto odd2;
+ case 4:
+ v = v * 85 + 84;
+ data->buf[n+2] = v >> 8 & 0xff;
+odd2:
+ data->buf[n+1] = v >> 16 & 0xff;
+odd1:
+ data->buf[n+0] = v >> 24 & 0xff;
+ data->bytes_available = n + i - 1;
+ return;
+ }
+ break;
+ }
+ v = 85*v + c-'!';
+ }
+
+ data->buf[n+0] = v >> 24 & 0xff;
+ data->buf[n+1] = v >> 16 & 0xff;
+ data->buf[n+2] = v >> 8 & 0xff;
+ data->buf[n+3] = v >> 0 & 0xff;
+ }
+ n += 4;
+ } while (n < sizeof (data->buf) && data->eod == FALSE);
+
+ data->bytes_available = n;
+}
+
+static int
+_ascii85_decode_getc (csi_file_t *file)
+{
+ _ascii85_decode_data_t *data = file->data;
+
+ if (data->bytes_available == 0) {
+ _ascii85_decode (file);
+
+ if (data->bytes_available == 0)
+ return EOF;
+ }
+
+ data->bytes_available--;
+ return *data->bp++;
+}
+
+static void
+_ascii85_decode_putc (csi_file_t *file, int c)
+{
+ _ascii85_decode_data_t *data = file->data;
+ data->bytes_available++;
+ data->bp--;
+}
+
+static int
+_ascii85_decode_read (csi_file_t *file, uint8_t *buf, int len)
+{
+ _ascii85_decode_data_t *data = file->data;
+
+ if (data->bytes_available == 0) {
+ _ascii85_decode (file);
+
+ if (data->bytes_available == 0)
+ return 0;
+ }
+
+ if (len > data->bytes_available)
+ len = data->bytes_available;
+ memcpy (buf, data->bp, len);
+ data->bp += len;
+ data->bytes_available -= len;
+ return len;
+}
+
+csi_status_t
+csi_file_new_ascii85_decode (csi_t *ctx,
+ csi_object_t *obj,
+ csi_dictionary_t *dict,
+ csi_object_t *src)
+{
+ static const csi_filter_funcs_t funcs = {
+ _ascii85_decode_getc,
+ _ascii85_decode_putc,
+ _ascii85_decode_read,
+ _csi_free,
+ };
+ _ascii85_decode_data_t *data;
+
+ data = _csi_alloc0 (ctx, sizeof (_ascii85_decode_data_t));
+ if (data == NULL)
+ return _csi_error (CAIRO_STATUS_NO_MEMORY);
+
+ return _csi_file_new_filter (ctx, obj, src, &funcs, data);
+}
+
+#if HAVE_ZLIB
+#include <zlib.h>
+
+typedef struct _deflate_decode_data {
+ z_stream zlib_stream;
+
+ uint8_t in[CHUNK_SIZE];
+ uint8_t out[CHUNK_SIZE];
+
+ int bytes_available;
+ uint8_t *bp;
+} _deflate_decode_data_t;
+
+static void
+_deflate_decode (csi_file_t *file)
+{
+ _deflate_decode_data_t *data = file->data;
+ uint8_t *bp;
+ int len;
+
+ data->zlib_stream.next_out = data->out;
+ data->zlib_stream.avail_out = sizeof (data->out);
+
+ bp = data->in;
+ len = sizeof (data->in);
+ if (data->zlib_stream.avail_in) {
+ memmove (data->in,
+ data->zlib_stream.next_in,
+ data->zlib_stream.avail_in);
+ len -= data->zlib_stream.avail_in;
+ bp += data->zlib_stream.avail_in;
+ }
+
+ len = csi_file_read (file->src, bp, len);
+
+ data->zlib_stream.next_in = data->in;
+ data->zlib_stream.avail_in += len;
+
+ inflate (&data->zlib_stream, len == 0 ? Z_FINISH : Z_NO_FLUSH);
+
+ data->bytes_available = data->zlib_stream.next_out - data->out;
+ data->bp = data->out;
+}
+
+static int
+_deflate_decode_getc (csi_file_t *file)
+{
+ _deflate_decode_data_t *data = file->data;
+
+ if (data->bytes_available == 0) {
+ _deflate_decode (file);
+
+ if (data->bytes_available == 0)
+ return EOF;
+ }
+
+ data->bytes_available--;
+ return *data->bp++;
+}
+
+static void
+_deflate_decode_putc (csi_file_t *file, int c)
+{
+ _deflate_decode_data_t *data = file->data;
+ data->bytes_available++;
+ data->bp--;
+}
+
+static int
+_deflate_decode_read (csi_file_t *file, uint8_t *buf, int len)
+{
+ _deflate_decode_data_t *data = file->data;
+
+ if (data->bytes_available == 0) {
+ _deflate_decode (file);
+
+ if (data->bytes_available == 0)
+ return 0;
+ }
+
+ if (len > (int) data->bytes_available)
+ len = data->bytes_available;
+ memcpy (buf, data->bp, len);
+ data->bp += len;
+ data->bytes_available -= len;
+ return len;
+}
+
+static void
+_deflate_destroy (csi_t *ctx, void *closure)
+{
+ _deflate_decode_data_t *data;
+
+ data = closure;
+
+ inflateEnd (&data->zlib_stream);
+
+ _csi_free (ctx, data);
+}
+
+csi_status_t
+csi_file_new_deflate_decode (csi_t *ctx,
+ csi_object_t *obj,
+ csi_dictionary_t *dict,
+ csi_object_t *src)
+{
+ static const csi_filter_funcs_t funcs = {
+ _deflate_decode_getc,
+ _deflate_decode_putc,
+ _deflate_decode_read,
+ _deflate_destroy,
+ };
+ _deflate_decode_data_t *data;
+
+ data = _csi_alloc (ctx, sizeof (_deflate_decode_data_t));
+ if (data == NULL)
+ return _csi_error (CAIRO_STATUS_NO_MEMORY);
+
+ data->zlib_stream.zalloc = Z_NULL;
+ data->zlib_stream.zfree = Z_NULL;
+ data->zlib_stream.opaque = Z_NULL;
+ data->zlib_stream.next_in = data->in;
+ data->zlib_stream.avail_in = 0;
+ data->zlib_stream.next_out = data->out;
+ data->zlib_stream.avail_out = sizeof (data->out);
+ data->bytes_available = 0;
+
+ if (inflateInit (&data->zlib_stream) != Z_OK) {
+ _csi_free (ctx, data);
+ return _csi_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ return _csi_file_new_filter (ctx, obj, src, &funcs, data);
+}
+#endif
+
+#if 0
+static int
+hex_value (int c)
+{
+ if (c < '0')
+ return EOF;
+ if (c <= '9')
+ return c - '0';
+ c |= 32;
+ if (c < 'a')
+ return EOF;
+ if (c <= 'f')
+ return c - 'a' + 0xa;
+ return EOF;
+}
+
+/* Adobe Type 1 Font Format book: p63 */
+typedef struct _decrypt_data {
+ uint8_t putback[32];
+ uint8_t nputback;
+ csi_bool_t is_hexadecimal;
+ unsigned short R;
+ int eod;
+} _decrypt_data_t;
+
+static uint8_t
+_decrypt (unsigned short *R, uint8_t cypher)
+{
+#define c1 52845
+#define c2 22719
+ uint8_t plain;
+
+ plain = cypher ^ (*R >> 8);
+ *R = (cypher + *R) * c1 + c2;
+ return plain;
+#undef c1
+#undef c2
+}
+
+int
+csi_decrypt (uint8_t *in, int length,
+ unsigned short salt, int binary,
+ uint8_t *out)
+{
+ const uint8_t * const end = in + length;
+ uint8_t *base = out;
+
+ while (in < end) {
+ int c;
+
+ if (! binary) {
+ int c_hi = -1, c_lo = 0;
+
+ while (in < end && (c_hi = *in++)) {
+ switch (c_hi) {
+ case 0x0:
+ case 0x9:
+ case 0xa:
+ case 0xc:
+ case 0xd:
+ case 0x20:
+ continue;
+
+ default:
+ break;
+ }
+ }
+ if (c_hi < 0)
+ break;
+
+ while (in < end && (c_lo = *in++)) {
+ switch (c_lo) {
+ case 0x0:
+ case 0x9:
+ case 0xa:
+ case 0xc:
+ case 0xd:
+ case 0x20:
+ continue;
+
+ default:
+ break;
+ }
+ }
+
+ c = (hex_value (c_hi) << 4) | hex_value (c_lo);
+ } else
+ c = *in++;
+
+ *out++ = _decrypt (&salt, c);
+ }
+
+ return out - base;
+}
+
+static uint8_t
+_encrypt (unsigned short *R, uint8_t plain)
+{
+#define c1 52845
+#define c2 22719
+ uint8_t cypher;
+
+ cypher = plain ^ (*R >> 8);
+ *R = (cypher + *R) * c1 + c2;
+ return cypher;
+#undef c1
+#undef c2
+}
+
+int
+csi_encrypt (uint8_t *in, int length,
+ unsigned short salt, int discard, int binary,
+ uint8_t *out)
+{
+ const char hex[]="0123456789abcdef";
+ const uint8_t * const end = in + length;
+ uint8_t *base = out;
+ int col = 0;
+
+ while (discard--) {
+ if (! binary) {
+ int c = _encrypt (&salt, ' ');
+ *out++ = hex[(c >> 4) & 0xf];
+ *out++ = hex[(c >> 0) & 0xf];
+ } else
+ *out++ = _encrypt (&salt, 0);
+ }
+
+ while (in < end) {
+ int c;
+
+ c = _encrypt (&salt, *in++);
+ if (! binary) {
+ if (col == 78) {
+ *out++ = '\n';
+ col = 0;
+ }
+ *out++ = hex[(c >> 4) & 0xf];
+ *out++ = hex[(c >> 0) & 0xf];
+ col += 2;
+ } else
+ *out++ = c;
+ }
+
+ return out - base;
+}
+
+static int
+_decrypt_getc (csi_file_t *file)
+{
+ _decrypt_data_t *data = file->data;
+ int c;
+
+ if (data->nputback)
+ return data->putback[--data->nputback];
+
+ if (data->is_hexadecimal) {
+ int c_hi, c_lo;
+
+ c_hi = _getc_skip_whitespace (file->src);
+ c_lo = _getc_skip_whitespace (file->src);
+ c = (hex_value (c_hi) << 4) | hex_value (c_lo);
+ } else
+ c = csi_file_getc (file->src);
+
+ if (c == EOF)
+ return EOF;
+
+ return _decrypt (&data->R, c);
+}
+
+static void
+_decrypt_putc (csi_file_t *file, int c)
+{
+ _decrypt_data_t *data;
+
+ data = file->data;
+
+ data->putback[data->nputback++] = c;
+}
+
+csi_object_t *
+csi_file_new_decrypt (csi_t *ctx, csi_object_t *src, int salt, int discard)
+{
+ csi_object_t *obj;
+ _decrypt_data_t *data;
+ int n;
+
+ data = _csi_alloc0 (ctx, sizeof (_decrypt_data_t));
+ if (data == NULL)
+ return NULL;
+
+ data->R = salt;
+
+ obj = _csi_file_new_filter (ctx, src,
+ _decrypt_getc,
+ _decrypt_putc,
+ NULL,
+ _csi_free,
+ data);
+ if (obj == NULL)
+ return NULL;
+
+ /* XXX determine encoding, eexec only? */
+ data->is_hexadecimal = salt != 4330;
+ for (n = 0; n < discard; n++) {
+ int c;
+ c = csi_file_getc (obj);
+ if (c == EOF) {
+ return obj;
+ }
+ }
+ return obj;
+}
+#endif
+
+csi_status_t
+_csi_file_execute (csi_t *ctx, csi_file_t *obj)
+{
+ return _csi_scan_file (ctx, &ctx->scanner, obj);
+}
+
+int
+csi_file_getc (csi_file_t *file)
+{
+ int c;
+
+ if (_csi_unlikely (file->src == NULL))
+ return EOF;
+
+ switch (file->type) {
+ case STDIO:
+ if (_csi_likely (file->rem)) {
+ c = *file->bp++;
+ file->rem--;
+ } else {
+ file->rem = fread (file->bp = file->data, 1, CHUNK_SIZE, file->src);
+ case BYTES:
+ if (_csi_likely (file->rem)) {
+ c = *file->bp++;
+ file->rem--;
+ } else
+ c = EOF;
+ }
+ break;
+
+ case PROCEDURE:
+#if 0
+ if (file->data == NULL) {
+ csi_status_t status;
+ csi_object_t *string;
+
+RERUN_PROCEDURE:
+ status = csi_object_execute (file->src);
+ if (status)
+ return EOF;
+
+ string = csi_pop_operand (file->base.ctx);
+ if (string == NULL)
+ return EOF;
+ file->data = csi_object_as_file (file->base.ctx, string);
+ csi_object_free (string);
+ if (file->data == NULL)
+ return EOF;
+ }
+ c = csi_file_getc (file->data);
+ if (c == EOF) {
+ csi_object_free (file->data);
+ file->data = NULL;
+ goto RERUN_PROCEDURE;
+ }
+#else
+ c = EOF;
+#endif
+ break;
+
+ case FILTER:
+ c = file->filter->filter_getc (file);
+ break;
+
+ default:
+ c = EOF;
+ break;
+ }
+
+ return c;
+}
+
+int
+csi_file_read (csi_file_t *file, void *buf, int len)
+{
+ int ret;
+
+ if (file->src == NULL)
+ return 0;
+
+ switch (file->type) {
+ case STDIO:
+ if (file->rem > 0) {
+ ret = len;
+ if (file->rem < ret)
+ ret = file->rem;
+ memcpy (buf, file->bp, ret);
+ file->bp += ret;
+ file->rem -= ret;
+ } else
+ ret = fread (buf, 1, len, file->src);
+ break;
+
+ case BYTES:
+ if (file->rem > 0) {
+ ret = len;
+ if (file->rem < ret)
+ ret = file->rem;
+ memcpy (buf, file->bp, ret);
+ file->bp += ret;
+ file->rem -= ret;
+ } else
+ ret = 0;
+ break;
+
+ case PROCEDURE:
+#if 0
+ if (file->data == NULL) {
+ csi_status_t status;
+ csi_object_t *string;
+
+RERUN_PROCEDURE:
+ status = csi_object_execute (file->src);
+ if (status)
+ return 0;
+
+ string = csi_pop_operand (file->base.ctx);
+ if (string == NULL)
+ return 0;
+ file->data = csi_object_as_file (file->base.ctx, string);
+ csi_object_free (string);
+ if (file->data == NULL)
+ return 0;
+ }
+ ret = csi_file_read (file->data, buf, len);
+ if (ret == 0) {
+ csi_object_free (file->data);
+ file->data = NULL;
+ goto RERUN_PROCEDURE;
+ }
+#else
+ ret = 0;
+#endif
+ break;
+
+ case FILTER:
+ ret = file->filter->filter_read (file, buf, len);
+ break;
+
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+void
+csi_file_putc (csi_file_t *file, int c)
+{
+ if (file->src == NULL)
+ return;
+
+ switch ((int) file->type) {
+ case STDIO:
+ case BYTES:
+ file->bp--;
+ file->rem++;
+ break;
+ case FILTER:
+ file->filter->filter_putc (file, c);
+ break;
+ default:
+ break;
+ }
+}
+
+void
+csi_file_flush (csi_file_t *file)
+{
+ int c;
+
+ if (file->src == NULL)
+ return;
+
+ switch ((int) file->type) {
+ case FILTER: /* need to eat EOD */
+ while ((c = csi_file_getc (file)) != EOF)
+ ;
+ break;
+ default:
+ break;
+ }
+}
+
+void
+csi_file_close (csi_t *ctx, csi_file_t *file)
+{
+ if (file->src == NULL)
+ return;
+
+ switch (file->type) {
+ case STDIO:
+ fclose (file->src);
+ break;
+ case BYTES:
+ if (file->src != file->data) {
+ csi_string_t *src = file->src;
+ if (src != NULL && --src->base.ref == 0)
+ csi_string_free (ctx, src);
+ }
+ break;
+ case FILTER:
+ {
+ csi_file_t *src = file->src;
+ if (src != NULL && --src->base.ref == 0)
+ _csi_file_free (ctx, src);
+ }
+ break;
+ case PROCEDURE:
+ default:
+ break;
+ }
+ file->src = NULL;
+}
+
+void
+_csi_file_free (csi_t *ctx, csi_file_t *file)
+{
+ csi_file_flush (file);
+ /* XXX putback */
+ csi_file_close (ctx, file);
+
+ switch (file->type) {
+ case BYTES:
+ break;
+ case PROCEDURE:
+#if 0
+ csi_object_free (ctx, file->data);
+#endif
+ break;
+ case STDIO:
+ _csi_free (ctx, file->data);
+ break;
+ case FILTER:
+ file->filter->filter_destroy (ctx, file->data);
+ break;
+ default:
+ break;
+ }
+
+ _csi_slab_free (ctx, file, sizeof (csi_file_t));
+}
+
+csi_status_t
+_csi_file_as_string (csi_t *ctx,
+ csi_file_t *file,
+ csi_object_t *obj)
+{
+ char *bytes;
+ unsigned int len;
+ unsigned int allocated;
+ csi_status_t status;
+
+ len = 0;
+ allocated = 16384;
+ bytes = _csi_alloc (ctx, allocated);
+ if (bytes == NULL)
+ return _csi_error (CAIRO_STATUS_NO_MEMORY);
+
+ len = 0;
+ do {
+ int ret;
+
+ ret = csi_file_read (file, bytes + len, allocated - len);
+ if (ret == 0)
+ break;
+
+ len += ret;
+ if (len > allocated / 2) {
+ char *newbytes;
+ int newlen;
+
+ if (_csi_unlikely (allocated > INT32_MAX / 2))
+ return _csi_error (CAIRO_STATUS_NO_MEMORY);
+
+ newlen = allocated * 2;
+ newbytes = _csi_realloc (ctx, bytes, newlen);
+ if (_csi_unlikely (newbytes == NULL)) {
+ _csi_free (ctx, bytes);
+ return _csi_error (CAIRO_STATUS_NO_MEMORY);
+ }
+ bytes = newbytes;
+ allocated = newlen;
+ }
+ } while (TRUE);
+
+ status = csi_string_new (ctx, obj, bytes, len);
+ if (status) {
+ _csi_free (ctx, bytes);
+ return status;
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
diff --git a/util/cairo-script/cairo-script-hash.c b/util/cairo-script/cairo-script-hash.c
new file mode 100644
index 00000000..c1e6bc28
--- /dev/null
+++ b/util/cairo-script/cairo-script-hash.c
@@ -0,0 +1,448 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2004 Red Hat, Inc.
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributor(s):
+ * Keith Packard <keithp@keithp.com>
+ * Graydon Hoare <graydon@redhat.com>
+ * Carl Worth <cworth@cworth.org>
+ */
+
+#include "cairo-script-private.h"
+
+#include <stdlib.h>
+
+/*
+ * An entry can be in one of three states:
+ *
+ * FREE: Entry has never been used, terminates all searches.
+ * Appears in the table as a %NULL pointer.
+ *
+ * DEAD: Entry had been live in the past. A dead entry can be reused
+ * but does not terminate a search for an exact entry.
+ * Appears in the table as a pointer to DEAD_ENTRY.
+ *
+ * LIVE: Entry is currently being used.
+ * Appears in the table as any non-%NULL, non-DEAD_ENTRY pointer.
+ */
+
+#define DEAD_ENTRY ((csi_hash_entry_t *) 0x1)
+
+#define ENTRY_IS_FREE(entry) ((entry) == NULL)
+#define ENTRY_IS_DEAD(entry) ((entry) == DEAD_ENTRY)
+#define ENTRY_IS_LIVE(entry) ((entry) > DEAD_ENTRY)
+
+/* We expect keys will not be destroyed frequently, so our table does not
+ * contain any explicit shrinking code nor any chain-coalescing code for
+ * entries randomly deleted by memory pressure (except during rehashing, of
+ * course). These assumptions are potentially bad, but they make the
+ * implementation straightforward.
+ *
+ * Revisit later if evidence appears that we're using excessive memory from
+ * a mostly-dead table.
+ *
+ * This table is open-addressed with double hashing. Each table size is a
+ * prime chosen to be a little more than double the high water mark for a
+ * given arrangement, so the tables should remain < 50% full. The table
+ * size makes for the "first" hash modulus; a second prime (2 less than the
+ * first prime) serves as the "second" hash modulus, which is co-prime and
+ * thus guarantees a complete permutation of table indices.
+ *
+ * This structure, and accompanying table, is borrowed/modified from the
+ * file xserver/render/glyph.c in the freedesktop.org x server, with
+ * permission (and suggested modification of doubling sizes) by Keith
+ * Packard.
+ */
+
+static const csi_hash_table_arrangement_t hash_table_arrangements [] = {
+ { 16, 43, 41 },
+ { 32, 73, 71 },
+ { 64, 151, 149 },
+ { 128, 283, 281 },
+ { 256, 571, 569 },
+ { 512, 1153, 1151 },
+ { 1024, 2269, 2267 },
+ { 2048, 4519, 4517 },
+ { 4096, 9013, 9011 },
+ { 8192, 18043, 18041 },
+ { 16384, 36109, 36107 },
+ { 32768, 72091, 72089 },
+ { 65536, 144409, 144407 },
+ { 131072, 288361, 288359 },
+ { 262144, 576883, 576881 },
+ { 524288, 1153459, 1153457 },
+ { 1048576, 2307163, 2307161 },
+ { 2097152, 4613893, 4613891 },
+ { 4194304, 9227641, 9227639 },
+ { 8388608, 18455029, 18455027 },
+ { 16777216, 36911011, 36911009 },
+ { 33554432, 73819861, 73819859 },
+ { 67108864, 147639589, 147639587 },
+ { 134217728, 295279081, 295279079 },
+ { 268435456, 590559793, 590559791 }
+};
+
+#define NUM_HASH_TABLE_ARRANGEMENTS ARRAY_LENGTH (hash_table_arrangements)
+
+/**
+ * _csi_hash_table_create:
+ * @keys_equal: a function to return %TRUE if two keys are equal
+ *
+ * Creates a new hash table which will use the keys_equal() function
+ * to compare hash keys. Data is provided to the hash table in the
+ * form of user-derived versions of #csi_hash_entry_t. A hash entry
+ * must be able to hold both a key (including a hash code) and a
+ * value. Sometimes only the key will be necessary, (as in
+ * _csi_hash_table_remove), and other times both a key and a value
+ * will be necessary, (as in _csi_hash_table_insert).
+ *
+ * See #csi_hash_entry_t for more details.
+ *
+ * Return value: the new hash table or %NULL if out of memory.
+ **/
+csi_status_t
+_csi_hash_table_init (csi_hash_table_t *hash_table,
+ csi_hash_keys_equal_func_t keys_equal)
+{
+ hash_table->keys_equal = keys_equal;
+
+ hash_table->arrangement = &hash_table_arrangements[0];
+
+ hash_table->entries = calloc (hash_table->arrangement->size,
+ sizeof(csi_hash_entry_t *));
+ if (hash_table->entries == NULL)
+ return _csi_error (CAIRO_STATUS_NO_MEMORY);
+
+ hash_table->live_entries = 0;
+ hash_table->iterating = 0;
+
+ return CSI_STATUS_SUCCESS;
+}
+
+/**
+ * _csi_hash_table_destroy:
+ * @hash_table: an empty hash table to destroy
+ *
+ * Immediately destroys the given hash table, freeing all resources
+ * associated with it.
+ *
+ * WARNING: The hash_table must have no live entries in it before
+ * _csi_hash_table_destroy is called. It is a fatal error otherwise,
+ * and this function will halt. The rationale for this behavior is to
+ * avoid memory leaks and to avoid needless complication of the API
+ * with destroy notifiy callbacks.
+ *
+ * WARNING: The hash_table must have no running iterators in it when
+ * _csi_hash_table_destroy is called. It is a fatal error otherwise,
+ * and this function will halt.
+ **/
+void
+_csi_hash_table_fini (csi_hash_table_t *hash_table)
+{
+ free (hash_table->entries);
+}
+
+static csi_hash_entry_t **
+_csi_hash_table_lookup_unique_key (csi_hash_table_t *hash_table,
+ csi_hash_entry_t *key)
+{
+ unsigned long table_size, i, idx, step;
+ csi_hash_entry_t **entry;
+
+ table_size = hash_table->arrangement->size;
+ idx = key->hash % table_size;
+
+ entry = &hash_table->entries[idx];
+ if (! ENTRY_IS_LIVE (*entry))
+ return entry;
+
+ i = 1;
+ step = key->hash % hash_table->arrangement->rehash;
+ if (step == 0)
+ step = 1;
+ do {
+ idx += step;
+ if (idx >= table_size)
+ idx -= table_size;
+
+ entry = &hash_table->entries[idx];
+ if (! ENTRY_IS_LIVE (*entry))
+ return entry;
+ } while (++i < table_size);
+
+ return NULL;
+}
+
+/**
+ * _csi_hash_table_resize:
+ * @hash_table: a hash table
+ *
+ * Resize the hash table if the number of entries has gotten much
+ * bigger or smaller than the ideal number of entries for the current
+ * size.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS if successful or
+ * %CAIRO_STATUS_NO_MEMORY if out of memory.
+ **/
+static csi_status_t
+_csi_hash_table_resize (csi_hash_table_t *hash_table)
+{
+ csi_hash_table_t tmp;
+ unsigned long new_size, i;
+
+ /* This keeps the hash table between 25% and 50% full. */
+ unsigned long high = hash_table->arrangement->high_water_mark;
+ unsigned long low = high >> 2;
+
+ if (hash_table->live_entries >= low && hash_table->live_entries <= high)
+ return CAIRO_STATUS_SUCCESS;
+
+ tmp = *hash_table;
+
+ if (hash_table->live_entries > high) {
+ tmp.arrangement = hash_table->arrangement + 1;
+ /* This code is being abused if we can't make a table big enough. */
+ } else { /* hash_table->live_entries < low */
+ /* Can't shrink if we're at the smallest size */
+ if (hash_table->arrangement == &hash_table_arrangements[0])
+ return CAIRO_STATUS_SUCCESS;
+ tmp.arrangement = hash_table->arrangement - 1;
+ }
+
+ new_size = tmp.arrangement->size;
+ tmp.entries = calloc (new_size, sizeof (csi_hash_entry_t*));
+ if (tmp.entries == NULL)
+ return _csi_error (CAIRO_STATUS_NO_MEMORY);
+
+ for (i = 0; i < hash_table->arrangement->size; ++i) {
+ if (ENTRY_IS_LIVE (hash_table->entries[i])) {
+ *_csi_hash_table_lookup_unique_key (&tmp, hash_table->entries[i])
+ = hash_table->entries[i];
+ }
+ }
+
+ free (hash_table->entries);
+ hash_table->entries = tmp.entries;
+ hash_table->arrangement = tmp.arrangement;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/**
+ * _csi_hash_table_lookup:
+ * @hash_table: a hash table
+ * @key: the key of interest
+ *
+ * Performs a lookup in @hash_table looking for an entry which has a
+ * key that matches @key, (as determined by the keys_equal() function
+ * passed to _csi_hash_table_create).
+ *
+ * Return value: the matching entry, of %NULL if no match was found.
+ **/
+void *
+_csi_hash_table_lookup (csi_hash_table_t *hash_table,
+ csi_hash_entry_t *key)
+{
+ csi_hash_entry_t **entry;
+ unsigned long table_size, i, idx, step;
+
+ table_size = hash_table->arrangement->size;
+ idx = key->hash % table_size;
+ entry = &hash_table->entries[idx];
+
+ if (ENTRY_IS_LIVE (*entry)) {
+ if (hash_table->keys_equal (key, *entry))
+ return *entry;
+ } else if (ENTRY_IS_FREE (*entry))
+ return NULL;
+
+ i = 1;
+ step = key->hash % hash_table->arrangement->rehash;
+ if (step == 0)
+ step = 1;
+ do {
+ idx += step;
+ if (idx >= table_size)
+ idx -= table_size;
+
+ entry = &hash_table->entries[idx];
+ if (ENTRY_IS_LIVE (*entry)) {
+ if (hash_table->keys_equal (key, *entry))
+ return *entry;
+ } else if (ENTRY_IS_FREE (*entry))
+ return NULL;
+ } while (++i < table_size);
+
+ return NULL;
+}
+
+/**
+ * _csi_hash_table_insert:
+ * @hash_table: a hash table
+ * @key_and_value: an entry to be inserted
+ *
+ * Insert the entry #key_and_value into the hash table.
+ *
+ * WARNING: There must not be an existing entry in the hash table
+ * with a matching key.
+ *
+ * WARNING: It is a fatal error to insert an element while
+ * an iterator is running
+ *
+ * Instead of using insert to replace an entry, consider just editing
+ * the entry obtained with _csi_hash_table_lookup. Or if absolutely
+ * necessary, use _csi_hash_table_remove first.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS if successful or
+ * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available.
+ **/
+csi_status_t
+_csi_hash_table_insert (csi_hash_table_t *hash_table,
+ csi_hash_entry_t *key_and_value)
+{
+ csi_status_t status;
+
+ hash_table->live_entries++;
+ status = _csi_hash_table_resize (hash_table);
+ if (_csi_unlikely (status)) {
+ /* abort the insert... */
+ hash_table->live_entries--;
+ return status;
+ }
+
+ *_csi_hash_table_lookup_unique_key (hash_table,
+ key_and_value) = key_and_value;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static csi_hash_entry_t **
+_csi_hash_table_lookup_exact_key (csi_hash_table_t *hash_table,
+ csi_hash_entry_t *key)
+{
+ unsigned long table_size, i, idx, step;
+ csi_hash_entry_t **entry;
+
+ table_size = hash_table->arrangement->size;
+ idx = key->hash % table_size;
+
+ entry = &hash_table->entries[idx];
+ if (*entry == key)
+ return entry;
+
+ i = 1;
+ step = key->hash % hash_table->arrangement->rehash;
+ if (step == 0)
+ step = 1;
+ do {
+ idx += step;
+ if (idx >= table_size)
+ idx -= table_size;
+
+ entry = &hash_table->entries[idx];
+ if (*entry == key)
+ return entry;
+ } while (++i < table_size);
+
+ return NULL;
+}
+/**
+ * _csi_hash_table_remove:
+ * @hash_table: a hash table
+ * @key: key of entry to be removed
+ *
+ * Remove an entry from the hash table which points to @key.
+ *
+ * Return value: %CAIRO_STATUS_SUCCESS if successful or
+ * %CAIRO_STATUS_NO_MEMORY if out of memory.
+ **/
+void
+_csi_hash_table_remove (csi_hash_table_t *hash_table,
+ csi_hash_entry_t *key)
+{
+ *_csi_hash_table_lookup_exact_key (hash_table, key) = DEAD_ENTRY;
+ hash_table->live_entries--;
+
+ /* Check for table resize. Don't do this when iterating as this will
+ * reorder elements of the table and cause the iteration to potentially
+ * skip some elements. */
+ if (hash_table->iterating == 0) {
+ /* This call _can_ fail, but only in failing to allocate new
+ * memory to shrink the hash table. It does leave the table in a
+ * consistent state, and we've already succeeded in removing the
+ * entry, so we don't examine the failure status of this call. */
+ _csi_hash_table_resize (hash_table);
+ }
+}
+
+/**
+ * _csi_hash_table_foreach:
+ * @hash_table: a hash table
+ * @hash_callback: function to be called for each live entry
+ * @closure: additional argument to be passed to @hash_callback
+ *
+ * Call @hash_callback for each live entry in the hash table, in a
+ * non-specified order.
+ *
+ * Entries in @hash_table may be removed by code executed from @hash_callback.
+ *
+ * Entries may not be inserted to @hash_table, nor may @hash_table
+ * be destroyed by code executed from @hash_callback. The relevant
+ * functions will halt in these cases.
+ **/
+void
+_csi_hash_table_foreach (csi_hash_table_t *hash_table,
+ csi_hash_callback_func_t hash_callback,
+ void *closure)
+{
+ unsigned long i;
+ csi_hash_entry_t *entry;
+
+ if (hash_table == NULL)
+ return;
+
+ /* Mark the table for iteration */
+ ++hash_table->iterating;
+ for (i = 0; i < hash_table->arrangement->size; i++) {
+ entry = hash_table->entries[i];
+ if (ENTRY_IS_LIVE(entry))
+ hash_callback (entry, closure);
+ }
+ /* If some elements were deleted during the iteration,
+ * the table may need resizing. Just do this every time
+ * as the check is inexpensive.
+ */
+ if (--hash_table->iterating == 0) {
+ /* Should we fail to shrink the hash table, it is left unaltered,
+ * and we don't need to propagate the error status. */
+ _csi_hash_table_resize (hash_table);
+ }
+}
diff --git a/util/cairo-script/cairo-script-interpreter.c b/util/cairo-script/cairo-script-interpreter.c
new file mode 100644
index 00000000..fea6a4ad
--- /dev/null
+++ b/util/cairo-script/cairo-script-interpreter.c
@@ -0,0 +1,472 @@
+/*
+ * Copyright © 2008 Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Chris Wilson.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include <cairo.h>
+
+#include "cairo-script-private.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+csi_status_t
+_csi_error (csi_status_t status)
+{
+ return status;
+}
+
+/* XXX track global/local memory, cap etc, mark/sweep GC */
+void *
+_csi_alloc (csi_t *ctx, int size)
+{
+ if (_csi_unlikely (ctx->status))
+ return NULL;
+
+ return malloc (size);
+}
+
+void *
+_csi_alloc0 (csi_t *ctx, int size)
+{
+ void *ptr;
+
+ ptr = _csi_alloc (ctx, size);
+ if (_csi_likely (ptr != NULL))
+ memset (ptr, 0, size);
+
+ return ptr;
+}
+
+void *
+_csi_realloc (csi_t *ctx, void *ptr, int size)
+{
+ if (_csi_unlikely (ctx->status))
+ return NULL;
+
+ return realloc (ptr, size);
+}
+
+void
+_csi_free (csi_t *ctx, void *ptr)
+{
+ if (_csi_unlikely (ptr == NULL))
+ return;
+
+ free (ptr);
+}
+
+void *
+_csi_slab_alloc (csi_t *ctx, int size)
+{
+ if (_csi_unlikely (ctx->status))
+ return NULL;
+
+ return malloc (size);
+}
+
+void
+_csi_slab_free (csi_t *ctx, void *ptr, int size)
+{
+ if (_csi_unlikely (ptr == NULL))
+ return;
+
+ free (ptr);
+}
+
+static csi_status_t
+_add_operator (csi_t *ctx,
+ csi_dictionary_t *dict,
+ const csi_operator_def_t *def)
+{
+ csi_object_t name;
+ csi_object_t operator;
+ csi_status_t status;
+
+ status = csi_name_new_static (ctx, &name, def->name);
+ if (status)
+ return status;
+
+ status = csi_operator_new (ctx, &operator, def->op);
+ if (status)
+ return status;
+
+ return csi_dictionary_put (ctx, dict, name.datum.name, &operator);
+}
+
+static csi_status_t
+_add_integer_constant (csi_t *ctx,
+ csi_dictionary_t *dict,
+ const csi_integer_constant_def_t *def)
+{
+ csi_object_t name;
+ csi_object_t constant;
+ csi_status_t status;
+
+ status = csi_name_new_static (ctx, &name, def->name);
+ if (status)
+ return status;
+
+ status = csi_integer_new (ctx, &constant, def->value);
+ if (status)
+ return status;
+
+ return csi_dictionary_put (ctx, dict, name.datum.name, &constant);
+}
+
+static csi_status_t
+_init_dictionaries (csi_t *ctx)
+{
+ csi_status_t status;
+ csi_stack_t *stack;
+ csi_object_t obj;
+ csi_dictionary_t *dict;
+ const csi_operator_def_t *odef;
+ const csi_integer_constant_def_t *idef;
+
+ stack = &ctx->dstack;
+
+ status = _csi_stack_init (ctx, stack, 4);
+ if (status)
+ return status;
+
+ /* systemdict */
+ status = csi_dictionary_new (ctx, &obj);
+ if (status)
+ return status;
+
+ status = _csi_stack_push (ctx, stack, &obj);
+ if (status)
+ return status;
+
+ dict = obj.datum.dictionary;
+
+ /* fill systemdict with operators */
+ for (odef = _csi_operators (); odef->name != NULL; odef++) {
+ status = _add_operator (ctx, dict, odef);
+ if (status)
+ return status;
+ }
+
+ /* add constants */
+ for (idef = _csi_integer_constants (); idef->name != NULL; idef++) {
+ status = _add_integer_constant (ctx, dict, idef);
+ if (status)
+ return status;
+ }
+
+ /* and seal */
+ //dict.type &= ~CSI_OBJECT_ATTR_WRITABLE;
+
+
+ /* globaldict */
+ status = csi_dictionary_new (ctx, &obj);
+ if (status)
+ return status;
+ status = _csi_stack_push (ctx, stack, &obj);
+ if (status)
+ return status;
+
+ /* userdict */
+ status = csi_dictionary_new (ctx, &obj);
+ if (status)
+ return status;
+ status = _csi_stack_push (ctx, stack, &obj);
+ if (status)
+ return status;
+
+ return CSI_STATUS_SUCCESS;
+}
+
+/* intern string */
+
+typedef struct _cairo_intern_string {
+ csi_hash_entry_t hash_entry;
+ int len;
+ char *string;
+} csi_intern_string_t;
+
+static unsigned long
+_intern_string_hash (const char *str, int len)
+{
+ const signed char *p = (const signed char *) str;
+ unsigned int h = *p;
+
+ for (p += 1; --len; p++)
+ h = (h << 5) - h + *p;
+
+ return h;
+}
+
+static cairo_bool_t
+_intern_string_equal (const void *_a, const void *_b)
+{
+ const csi_intern_string_t *a = _a;
+ const csi_intern_string_t *b = _b;
+
+ if (a->len != b->len)
+ return FALSE;
+
+ return memcmp (a->string, b->string, a->len) == 0;
+}
+
+static void
+_csi_init (csi_t *ctx)
+{
+ csi_status_t status;
+
+ ctx->status = CSI_STATUS_SUCCESS;
+ ctx->ref_count = 1;
+
+ status = _csi_hash_table_init (&ctx->strings, _intern_string_equal);
+ if (status)
+ goto FAIL;
+
+ status = _csi_stack_init (ctx, &ctx->ostack, 2048);
+ if (status)
+ goto FAIL;
+ status = _init_dictionaries (ctx);
+ if (status)
+ goto FAIL;
+
+ status = _csi_scanner_init (ctx, &ctx->scanner);
+ if (status)
+ goto FAIL;
+
+ return;
+
+FAIL:
+ if (ctx->status == CSI_STATUS_SUCCESS)
+ ctx->status = status;
+}
+
+static void
+_intern_string_pluck (void *entry, void *closure)
+{
+ csi_t *ctx = closure;
+
+ _csi_hash_table_remove (&ctx->strings, entry);
+ _csi_free (ctx, entry);
+}
+
+static void
+_csi_fini (csi_t *ctx)
+{
+ _csi_stack_fini (ctx, &ctx->ostack);
+ _csi_stack_fini (ctx, &ctx->dstack);
+ _csi_scanner_fini (ctx, &ctx->scanner);
+
+ _csi_hash_table_foreach (&ctx->strings, _intern_string_pluck, ctx);
+ _csi_hash_table_fini (&ctx->strings);
+}
+
+csi_status_t
+_csi_name_define (csi_t *ctx, csi_name_t name, csi_object_t *obj)
+{
+ return csi_dictionary_put (ctx,
+ ctx->dstack.objects[ctx->dstack.len-1].datum.dictionary,
+ name,
+ obj);
+}
+
+csi_status_t
+_csi_name_lookup (csi_t *ctx, csi_name_t name, csi_object_t *obj)
+{
+ int i;
+
+ for (i = ctx->dstack.len; i--; ) {
+ csi_dictionary_t *dict;
+ csi_dictionary_entry_t *entry;
+
+ dict = ctx->dstack.objects[i].datum.dictionary;
+ entry = _csi_hash_table_lookup (&dict->hash_table,
+ (csi_hash_entry_t *) &name);
+ if (entry != NULL) {
+ *obj = entry->value;
+ return CSI_STATUS_SUCCESS;
+ }
+ }
+
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+}
+
+csi_status_t
+_csi_name_undefine (csi_t *ctx, csi_name_t name)
+{
+ unsigned int i;
+
+ for (i = ctx->dstack.len; --i; ) {
+ if (csi_dictionary_has (ctx->dstack.objects[i].datum.dictionary,
+ name))
+ {
+ csi_dictionary_remove (ctx,
+ ctx->dstack.objects[i].datum.dictionary,
+ name);
+ return CSI_STATUS_SUCCESS;
+ }
+ }
+
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+}
+
+csi_status_t
+_csi_intern_string (csi_t *ctx, const char **str_inout, int len)
+{
+ char *str = (char *) *str_inout;
+ csi_intern_string_t tmpl, *istring;
+ csi_status_t status = CSI_STATUS_SUCCESS;
+
+ if (len < 0)
+ len = strlen (str);
+ tmpl.hash_entry.hash = _intern_string_hash (str, len);
+ tmpl.len = len;
+ tmpl.string = (char *) str;
+
+ istring = _csi_hash_table_lookup (&ctx->strings, &tmpl.hash_entry);
+ if (istring == NULL) {
+ istring = _csi_alloc (ctx, sizeof (csi_intern_string_t) + len + 1);
+ if (istring != NULL) {
+ istring->hash_entry.hash = tmpl.hash_entry.hash;
+ istring->len = tmpl.len;
+ istring->string = (char *) (istring + 1);
+ memcpy (istring->string, str, len);
+ istring->string[len] = '\0';
+
+ status = _csi_hash_table_insert (&ctx->strings,
+ &istring->hash_entry);
+ if (_csi_unlikely (status)) {
+ _csi_free (ctx, istring);
+ return status;
+ }
+ } else
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ }
+
+ *str_inout = istring->string;
+ return CSI_STATUS_SUCCESS;
+}
+
+/* Public */
+
+static csi_t _csi_nil = { -1, CSI_STATUS_NO_MEMORY };
+
+csi_t *
+cairo_script_interpreter_create (void)
+{
+ csi_t *ctx;
+
+ ctx = calloc (1, sizeof (csi_t));
+ if (ctx == NULL)
+ return (csi_t *) &_csi_nil;
+
+ _csi_init (ctx);
+
+ return ctx;
+}
+
+void
+cairo_script_interpreter_install_hooks (csi_t *ctx,
+ const csi_hooks_t *hooks)
+{
+ if (ctx->status)
+ return;
+
+ ctx->hooks = *hooks;
+}
+
+cairo_status_t
+cairo_script_interpreter_run (csi_t *ctx, const char *filename)
+{
+ csi_object_t file;
+
+ if (ctx->status)
+ return ctx->status;
+
+ ctx->status = csi_file_new (ctx, &file, filename, "r");
+ if (ctx->status)
+ return ctx->status;
+
+ file.type |= CSI_OBJECT_ATTR_EXECUTABLE;
+
+ ctx->status = csi_object_execute (ctx, &file);
+ csi_object_free (ctx, &file);
+
+ return ctx->status;
+}
+
+cairo_status_t
+cairo_script_interpreter_feed_string (csi_t *ctx, const char *line, int len)
+{
+ csi_object_t file;
+
+ if (ctx->status)
+ return ctx->status;
+
+ if (len < 0)
+ len = strlen (line);
+ ctx->status = csi_file_new_for_bytes (ctx, &file, line, len);
+ if (ctx->status)
+ return ctx->status;
+
+ file.type |= CSI_OBJECT_ATTR_EXECUTABLE;
+
+ ctx->status = csi_object_execute (ctx, &file);
+ csi_object_free (ctx, &file);
+
+ return ctx->status;
+}
+
+csi_t *
+cairo_script_interpreter_reference (csi_t *ctx)
+{
+ ctx->ref_count++;
+ return ctx;
+}
+slim_hidden_def (cairo_script_interpreter_reference);
+
+cairo_status_t
+cairo_script_interpreter_destroy (csi_t *ctx)
+{
+ csi_status_t status;
+
+ status = ctx->status;
+ if (--ctx->ref_count)
+ return status;
+
+ _csi_fini (ctx);
+ free (ctx);
+
+ return status;
+}
+slim_hidden_def (cairo_script_interpreter_destroy);
diff --git a/util/cairo-script/cairo-script-interpreter.h b/util/cairo-script/cairo-script-interpreter.h
new file mode 100644
index 00000000..d619388e
--- /dev/null
+++ b/util/cairo-script/cairo-script-interpreter.h
@@ -0,0 +1,98 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2008 Chris Wilson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Chris Wilson
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_SCRIPT_INTERPRETER_H
+#define CAIRO_SCRIPT_INTERPRETER_H
+
+#include <cairo.h>
+
+CAIRO_BEGIN_DECLS
+
+typedef struct _cairo_script_interpreter cairo_script_interpreter_t;
+
+/* XXX expose csi_dictionary_t and pass to hooks */
+typedef void
+(*csi_destroy_func_t) (void *closure,
+ void *ptr);
+typedef cairo_surface_t *
+(*csi_surface_create_func_t) (void *closure,
+ double width,
+ double height);
+typedef cairo_t *
+(*csi_context_create_func_t) (void *closure,
+ cairo_surface_t *surface);
+typedef void
+(*csi_show_page_func_t) (void *closure,
+ cairo_t *cr);
+
+typedef void
+(*csi_copy_page_func_t) (void *closure,
+ cairo_t *cr);
+
+typedef struct _cairo_script_interpreter_hooks {
+ void *closure;
+ csi_surface_create_func_t surface_create;
+ csi_destroy_func_t surface_destroy;
+ csi_context_create_func_t context_create;
+ csi_destroy_func_t context_destroy;
+ csi_show_page_func_t show_page;
+ csi_copy_page_func_t copy_page;
+} cairo_script_interpreter_hooks_t;
+
+cairo_public cairo_script_interpreter_t *
+cairo_script_interpreter_create (void);
+
+cairo_public void
+cairo_script_interpreter_install_hooks (cairo_script_interpreter_t *ctx,
+ const cairo_script_interpreter_hooks_t *hooks);
+
+cairo_public cairo_status_t
+cairo_script_interpreter_run (cairo_script_interpreter_t *ctx,
+ const char *filename);
+
+cairo_public cairo_status_t
+cairo_script_interpreter_feed_string (cairo_script_interpreter_t *ctx,
+ const char *line,
+ int len);
+
+cairo_public cairo_script_interpreter_t *
+cairo_script_interpreter_reference (cairo_script_interpreter_t *ctx);
+
+cairo_public cairo_status_t
+cairo_script_interpreter_destroy (cairo_script_interpreter_t *ctx);
+
+CAIRO_END_DECLS
+
+#endif /*CAIRO_SCRIPT_INTERPRETER_H*/
diff --git a/util/cairo-script/cairo-script-objects.c b/util/cairo-script/cairo-script-objects.c
new file mode 100644
index 00000000..f4726cef
--- /dev/null
+++ b/util/cairo-script/cairo-script-objects.c
@@ -0,0 +1,666 @@
+/*
+ * Copyright © 2008 Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Chris Wilson.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairo-script-private.h"
+
+#include <string.h>
+
+csi_status_t
+csi_array_new (csi_t *ctx,
+ csi_object_t *obj)
+
+{
+ csi_array_t *array;
+ csi_status_t status;
+
+ array = _csi_slab_alloc (ctx, sizeof (csi_array_t));
+ if (_csi_unlikely (array == NULL))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+
+ array->base.type = CSI_OBJECT_TYPE_ARRAY;
+ array->base.ref = 1;
+ status = _csi_stack_init (ctx, &array->stack, 32);
+ if (_csi_unlikely (status)) {
+ _csi_slab_free (ctx, array, sizeof (csi_array_t));
+ return status;
+ }
+
+ obj->type = CSI_OBJECT_TYPE_ARRAY;
+ obj->datum.array = array;
+
+ return CSI_STATUS_SUCCESS;
+}
+
+csi_status_t
+csi_array_put (csi_t *ctx,
+ csi_array_t *array,
+ csi_integer_t elem,
+ csi_object_t *value)
+{
+ if (_csi_unlikely (elem < 0))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ if (_csi_unlikely (elem >= array->stack.len)) {
+ csi_status_t status;
+
+ status = _csi_stack_grow (ctx, &array->stack, elem + 1);
+ if (_csi_unlikely (status))
+ return status;
+
+ memset (array->stack.objects + array->stack.len,
+ 0, (elem - array->stack.len + 1) * sizeof (csi_object_t));
+ array->stack.len = elem + 1;
+ }
+
+ csi_object_free (ctx, &array->stack.objects[elem]);
+ array->stack.objects[elem] = *csi_object_reference (value);
+
+ return CSI_STATUS_SUCCESS;
+}
+
+csi_status_t
+csi_array_get (csi_t *ctx,
+ csi_array_t *array,
+ csi_integer_t elem,
+ csi_object_t *value)
+{
+ if (_csi_unlikely (elem < 0))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ if (_csi_unlikely (elem > array->stack.len))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ *value = array->stack.objects[elem];
+ return CSI_STATUS_SUCCESS;
+}
+
+csi_status_t
+csi_array_append (csi_t *ctx,
+ csi_array_t *array,
+ csi_object_t *obj)
+{
+ return _csi_stack_push (ctx, &array->stack, csi_object_reference (obj));
+}
+
+inline csi_status_t
+_csi_array_execute (csi_t *ctx, csi_array_t *array)
+{
+ csi_integer_t i;
+ csi_status_t status;
+
+ if (_csi_unlikely (array->stack.len == 0))
+ return CSI_STATUS_SUCCESS;
+
+ for (i = 0; i < array->stack.len; i++) {
+ csi_object_t *obj = &array->stack.objects[i];
+
+ if (obj->type & CSI_OBJECT_ATTR_EXECUTABLE) {
+ if (obj->type == (CSI_OBJECT_TYPE_ARRAY |
+ CSI_OBJECT_ATTR_EXECUTABLE))
+ {
+ status = _csi_push_ostack_copy (ctx, &array->stack.objects[i]);
+ }
+ else
+ status = csi_object_execute (ctx, &array->stack.objects[i]);
+ } else
+ status = _csi_push_ostack_copy (ctx, &array->stack.objects[i]);
+ if (_csi_unlikely (status))
+ return status;
+ }
+
+ return CSI_STATUS_SUCCESS;
+}
+
+void
+csi_array_free (csi_t *ctx, csi_array_t *array)
+{
+ _csi_stack_fini (ctx, &array->stack);
+ _csi_slab_free (ctx, array, sizeof (csi_array_t));
+}
+
+csi_status_t
+csi_boolean_new (csi_t *ctx,
+ csi_object_t *obj,
+ csi_boolean_t v)
+{
+ obj->type = CSI_OBJECT_TYPE_BOOLEAN;
+ obj->datum.boolean = v;
+
+ return CSI_STATUS_SUCCESS;
+}
+
+static cairo_bool_t
+_dictionary_name_equal (const void *_a, const void *_b)
+{
+ const csi_dictionary_entry_t *a = _a;
+ const csi_dictionary_entry_t *b = _b;
+ return a->hash_entry.hash == b->hash_entry.hash;
+}
+
+csi_status_t
+csi_dictionary_new (csi_t *ctx,
+ csi_object_t *obj)
+
+{
+ csi_dictionary_t *dict;
+ csi_status_t status;
+
+ dict = _csi_slab_alloc (ctx, sizeof (csi_dictionary_t));
+ if (_csi_unlikely (dict == NULL))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+
+ dict->base.type = CSI_OBJECT_TYPE_DICTIONARY;
+ dict->base.ref = 1;
+ status = _csi_hash_table_init (&dict->hash_table, _dictionary_name_equal);
+ if (_csi_unlikely (status)) {
+ _csi_slab_free (ctx, dict, sizeof (csi_dictionary_t));
+ return status;
+ }
+
+ obj->type = CSI_OBJECT_TYPE_DICTIONARY;
+ obj->datum.dictionary = dict;
+
+ return CSI_STATUS_SUCCESS;
+}
+
+struct _dictionary_entry_pluck {
+ csi_t *ctx;
+ csi_hash_table_t *hash_table;
+};
+
+static void
+_dictionary_entry_pluck (void *entry, void *data)
+{
+ csi_dictionary_entry_t *dict_entry;
+ struct _dictionary_entry_pluck *pluck_data;
+
+ dict_entry = entry;
+ pluck_data = data;
+
+ _csi_hash_table_remove (pluck_data->hash_table, entry);
+ csi_object_free (pluck_data->ctx, &dict_entry->value);
+ _csi_slab_free (pluck_data->ctx, entry, sizeof (csi_dictionary_entry_t));
+}
+
+void
+csi_dictionary_free (csi_t *ctx,
+ csi_dictionary_t *dict)
+{
+ struct _dictionary_entry_pluck data;
+
+ data.ctx = ctx;
+ data.hash_table = &dict->hash_table;
+ _csi_hash_table_foreach (&dict->hash_table,
+ _dictionary_entry_pluck,
+ &data);
+ _csi_hash_table_fini (&dict->hash_table);
+
+ _csi_slab_free (ctx, dict, sizeof (csi_dictionary_t));
+}
+
+csi_status_t
+csi_dictionary_put (csi_t *ctx,
+ csi_dictionary_t *dict,
+ csi_name_t name,
+ csi_object_t *value)
+{
+ csi_dictionary_entry_t *entry;
+ csi_status_t status;
+
+ entry = _csi_hash_table_lookup (&dict->hash_table,
+ (csi_hash_entry_t *) &name);
+ if (entry != NULL) {
+ /* replace the existing entry */
+ csi_object_free (ctx, &entry->value);
+ entry->value = *csi_object_reference (value);
+ return CSI_STATUS_SUCCESS;
+ }
+
+ entry = _csi_slab_alloc (ctx, sizeof (*entry));
+ if (_csi_unlikely (entry == NULL))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+
+ entry->hash_entry.hash = name;
+ status = _csi_hash_table_insert (&dict->hash_table, &entry->hash_entry);
+ if (_csi_unlikely (status)) {
+ _csi_slab_free (ctx, entry, sizeof (*entry));
+ return status;
+ }
+
+ entry->value = *csi_object_reference (value);
+
+ return CSI_STATUS_SUCCESS;
+}
+
+csi_status_t
+csi_dictionary_get (csi_t *ctx,
+ csi_dictionary_t *dict,
+ csi_name_t name,
+ csi_object_t *value)
+{
+ csi_dictionary_entry_t *entry;
+
+ entry = _csi_hash_table_lookup (&dict->hash_table,
+ (csi_hash_entry_t *) &name);
+ if (_csi_unlikely (entry == NULL))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ *value = entry->value;
+ return CSI_STATUS_SUCCESS;
+}
+
+csi_boolean_t
+csi_dictionary_has (csi_dictionary_t *dict,
+ csi_name_t name)
+{
+ return _csi_hash_table_lookup (&dict->hash_table,
+ (csi_hash_entry_t *) &name) != NULL;
+}
+
+void
+csi_dictionary_remove (csi_t *ctx,
+ csi_dictionary_t *dict,
+ csi_name_t name)
+{
+ csi_dictionary_entry_t *entry;
+
+ entry = _csi_hash_table_lookup (&dict->hash_table,
+ (csi_hash_entry_t *) &name);
+ if (entry != NULL) {
+ _csi_hash_table_remove (&dict->hash_table, &entry->hash_entry);
+ csi_object_free (ctx, &entry->value);
+ _csi_slab_free (ctx, entry, sizeof (csi_dictionary_entry_t));
+ }
+}
+
+csi_status_t
+csi_integer_new (csi_t *ctx,
+ csi_object_t *obj,
+ csi_integer_t v)
+{
+ obj->type = CSI_OBJECT_TYPE_INTEGER;
+ obj->datum.integer = v;
+
+ return CSI_STATUS_SUCCESS;
+}
+
+csi_status_t
+csi_matrix_new (csi_t *ctx,
+ csi_object_t *obj)
+{
+ csi_matrix_t *matrix;
+
+ matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t));
+ if (_csi_unlikely (matrix == NULL))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+
+ matrix->base.type = CSI_OBJECT_TYPE_MATRIX;
+ matrix->base.ref = 1;
+ cairo_matrix_init_identity (&matrix->matrix);
+
+ obj->type = CSI_OBJECT_TYPE_MATRIX;
+ obj->datum.matrix = matrix;
+
+ return CSI_STATUS_SUCCESS;
+}
+
+csi_status_t
+csi_matrix_new_from_array (csi_t *ctx,
+ csi_object_t *obj,
+ csi_array_t *array)
+{
+ csi_matrix_t *matrix;
+
+ if (_csi_unlikely (array->stack.len != 6))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t));
+ if (_csi_unlikely (matrix == NULL))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+
+ matrix->base.type = CSI_OBJECT_TYPE_MATRIX;
+ matrix->base.ref = 1;
+ cairo_matrix_init (&matrix->matrix,
+ csi_number_get_value (&array->stack.objects[0]),
+ csi_number_get_value (&array->stack.objects[1]),
+ csi_number_get_value (&array->stack.objects[2]),
+ csi_number_get_value (&array->stack.objects[3]),
+ csi_number_get_value (&array->stack.objects[4]),
+ csi_number_get_value (&array->stack.objects[5]));
+
+ obj->type = CSI_OBJECT_TYPE_MATRIX;
+ obj->datum.matrix = matrix;
+
+ return CSI_STATUS_SUCCESS;
+}
+
+csi_status_t
+csi_matrix_new_from_matrix (csi_t *ctx,
+ csi_object_t *obj,
+ const cairo_matrix_t *m)
+{
+ csi_matrix_t *matrix;
+
+ matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t));
+ if (_csi_unlikely (matrix == NULL))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+
+ matrix->base.type = CSI_OBJECT_TYPE_MATRIX;
+ matrix->base.ref = 1;
+ matrix->matrix = *m;
+
+ obj->type = CSI_OBJECT_TYPE_MATRIX;
+ obj->datum.matrix = matrix;
+
+ return CSI_STATUS_SUCCESS;
+}
+
+csi_status_t
+csi_matrix_new_from_values (csi_t *ctx,
+ csi_object_t *obj,
+ double v[6])
+{
+ csi_matrix_t *matrix;
+
+ matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t));
+ if (_csi_unlikely (matrix == NULL))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+
+ matrix->base.type = CSI_OBJECT_TYPE_MATRIX;
+ matrix->base.ref = 1;
+ cairo_matrix_init (&matrix->matrix, v[0], v[1], v[2], v[3], v[4], v[5]);
+
+ obj->type = CSI_OBJECT_TYPE_MATRIX;
+ obj->datum.matrix = matrix;
+
+ return CSI_STATUS_SUCCESS;
+}
+
+void
+csi_matrix_free (csi_t *ctx,
+ csi_matrix_t *obj)
+{
+ _csi_slab_free (ctx, obj, sizeof (csi_matrix_t));
+}
+
+
+csi_status_t
+csi_name_new (csi_t *ctx,
+ csi_object_t *obj,
+ const char *str,
+ int len)
+{
+ csi_status_t status;
+
+ status = _csi_intern_string (ctx, &str, len);
+ if (_csi_unlikely (status))
+ return status;
+
+ obj->type = CSI_OBJECT_TYPE_NAME;
+ obj->datum.name = (csi_name_t) str;
+
+ return CSI_STATUS_SUCCESS;
+}
+
+csi_status_t
+csi_name_new_static (csi_t *ctx,
+ csi_object_t *obj,
+ const char *str)
+{
+ csi_status_t status;
+
+ status = _csi_intern_string (ctx, &str, -1);
+ if (_csi_unlikely (status))
+ return status;
+
+ obj->type = CSI_OBJECT_TYPE_NAME;
+ obj->datum.name = (csi_name_t) str;
+
+ return CSI_STATUS_SUCCESS;
+}
+
+csi_status_t
+csi_operator_new (csi_t *ctx,
+ csi_object_t *obj,
+ csi_operator_t op)
+{
+ obj->type = CSI_OBJECT_TYPE_OPERATOR | CSI_OBJECT_ATTR_EXECUTABLE;
+ obj->datum.op = op;
+
+ return CSI_STATUS_SUCCESS;
+}
+
+csi_status_t
+csi_real_new (csi_t *ctx,
+ csi_object_t *obj,
+ csi_real_t v)
+{
+ obj->type = CSI_OBJECT_TYPE_REAL;
+ obj->datum.real = v;
+
+ return CSI_STATUS_SUCCESS;
+}
+
+csi_status_t
+csi_string_new (csi_t *ctx,
+ csi_object_t *obj,
+ const char *str,
+ int len)
+{
+ csi_string_t *string;
+
+ string = _csi_slab_alloc (ctx, sizeof (csi_string_t));
+ if (_csi_unlikely (string == NULL))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+
+ string->base.type = CSI_OBJECT_TYPE_STRING;
+ string->base.ref = 1;
+
+ if (len < 0)
+ len = strlen (str);
+ if (_csi_unlikely (len >= INT32_MAX)) {
+ _csi_slab_free (ctx, string, sizeof (csi_string_t));
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ }
+ string->string = _csi_alloc (ctx, len + 1);
+ if (_csi_unlikely (string->string == NULL)) {
+ _csi_slab_free (ctx, string, sizeof (csi_string_t));
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ }
+ memcpy (string->string, str, len);
+ string->string[len] = '\0';
+ string->len = len;
+
+ obj->type = CSI_OBJECT_TYPE_STRING;
+ obj->datum.string = string;
+
+ return CSI_STATUS_SUCCESS;
+}
+
+static inline csi_status_t
+_csi_string_execute (csi_t *ctx, csi_string_t *string)
+{
+ csi_status_t status;
+ csi_object_t obj;
+
+ if (_csi_unlikely (string->len == 0))
+ return CSI_STATUS_SUCCESS;
+
+ status = csi_file_new_for_bytes (ctx, &obj, string->string, string->len);
+ if (_csi_unlikely (status))
+ return status;
+
+ status = _csi_scan_file (ctx, &ctx->scanner, obj.datum.file);
+ csi_object_free (ctx, &obj);
+
+ return status;
+}
+
+void
+csi_string_free (csi_t *ctx, csi_string_t *string)
+{
+ _csi_free (ctx, string->string);
+ _csi_slab_free (ctx, string, sizeof (csi_string_t));
+}
+
+csi_status_t
+csi_object_execute (csi_t *ctx, csi_object_t *obj)
+{
+ csi_status_t status;
+ csi_object_t indirect;
+
+ INDIRECT:
+ switch (obj->type & CSI_OBJECT_TYPE_MASK) {
+ case CSI_OBJECT_TYPE_NAME:
+ status = _csi_name_lookup (ctx, obj->datum.name, &indirect);
+ if (_csi_unlikely (status))
+ return status;
+ if (indirect.type & CSI_OBJECT_ATTR_EXECUTABLE) {
+ obj = &indirect;
+ goto INDIRECT;
+ } else
+ return _csi_push_ostack_copy (ctx, &indirect);
+
+ case CSI_OBJECT_TYPE_OPERATOR:
+ return obj->datum.op (ctx);
+
+ case CSI_OBJECT_TYPE_ARRAY:
+ return _csi_array_execute (ctx, obj->datum.array);
+ case CSI_OBJECT_TYPE_FILE:
+ return _csi_file_execute (ctx, obj->datum.file);
+ case CSI_OBJECT_TYPE_STRING:
+ return _csi_string_execute (ctx, obj->datum.string);
+
+ default:
+ return _csi_push_ostack_copy (ctx, obj);
+ }
+}
+
+csi_object_t *
+csi_object_reference (csi_object_t *obj)
+{
+ if (CSI_OBJECT_IS_CAIRO (obj)) {
+ switch (obj->type & CSI_OBJECT_TYPE_MASK) {
+ case CSI_OBJECT_TYPE_CONTEXT:
+ cairo_reference (obj->datum.cr);
+ break;
+ case CSI_OBJECT_TYPE_FONT:
+ cairo_font_face_reference (obj->datum.font_face);
+ break;
+ case CSI_OBJECT_TYPE_PATTERN:
+ cairo_pattern_reference (obj->datum.pattern);
+ break;
+ case CSI_OBJECT_TYPE_SCALED_FONT:
+ cairo_scaled_font_reference (obj->datum.scaled_font);
+ break;
+ case CSI_OBJECT_TYPE_SURFACE:
+ cairo_surface_reference (obj->datum.surface);
+ break;
+ }
+ } else if (CSI_OBJECT_IS_COMPOUND (obj)) {
+ obj->datum.object->ref++;
+ }
+
+ return obj;
+}
+
+void
+csi_object_free (csi_t *ctx,
+ csi_object_t *obj)
+{
+ if (CSI_OBJECT_IS_CAIRO (obj)) {
+ switch (obj->type & CSI_OBJECT_TYPE_MASK) {
+ case CSI_OBJECT_TYPE_CONTEXT:
+ cairo_destroy (obj->datum.cr);
+ break;
+ case CSI_OBJECT_TYPE_FONT:
+ cairo_font_face_destroy (obj->datum.font_face);
+ break;
+ case CSI_OBJECT_TYPE_PATTERN:
+ cairo_pattern_destroy (obj->datum.pattern);
+ break;
+ case CSI_OBJECT_TYPE_SCALED_FONT:
+ cairo_scaled_font_destroy (obj->datum.scaled_font);
+ break;
+ case CSI_OBJECT_TYPE_SURFACE:
+ cairo_surface_destroy (obj->datum.surface);
+ break;
+ }
+ } else if (CSI_OBJECT_IS_COMPOUND (obj)) {
+ if (--obj->datum.object->ref)
+ return;
+
+ switch (obj->type & CSI_OBJECT_TYPE_MASK) {
+ case CSI_OBJECT_TYPE_ARRAY:
+ csi_array_free (ctx, obj->datum.array);
+ break;
+ case CSI_OBJECT_TYPE_DICTIONARY:
+ csi_dictionary_free (ctx, obj->datum.dictionary);
+ break;
+ case CSI_OBJECT_TYPE_FILE:
+ _csi_file_free (ctx, obj->datum.file);
+ break;
+ case CSI_OBJECT_TYPE_MATRIX:
+ csi_matrix_free (ctx, obj->datum.matrix);
+ break;
+ case CSI_OBJECT_TYPE_STRING:
+ csi_string_free (ctx, obj->datum.string);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+csi_status_t
+csi_object_as_file (csi_t *ctx,
+ csi_object_t *src,
+ csi_object_t *file)
+{
+
+ switch ((int) csi_object_get_type (src)) {
+ case CSI_OBJECT_TYPE_FILE:
+ *file = *csi_object_reference (src);
+ return CSI_STATUS_SUCCESS;
+ case CSI_OBJECT_TYPE_STRING:
+ return csi_file_new_from_string (ctx, file, src->datum.string);
+ case CSI_OBJECT_TYPE_ARRAY:
+#if 0
+ if (src->type & CSI_OBJECT_ATTR_EXECUTABLE)
+ return _csi_file_new_from_procedure (cs, src);
+#endif
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+}
diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c
new file mode 100644
index 00000000..13d6f766
--- /dev/null
+++ b/util/cairo-script/cairo-script-operators.c
@@ -0,0 +1,5791 @@
+/*
+ * Copyright © 2008 Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Chris Wilson.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+/* TODO real path type */
+
+#include "cairo-script-private.h"
+
+#include <stdio.h> /* snprintf */
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+
+typedef struct _csi_proxy {
+ csi_t *ctx;
+ void *ptr;
+ csi_dictionary_t *dictionary;
+ csi_destroy_func_t destroy_func;
+ void *destroy_data;
+} csi_proxy_t;
+
+typedef struct _csi_blob {
+ csi_list_t list;
+ unsigned long hash;
+ uint8_t *bytes;
+ unsigned int len;
+} csi_blob_t;
+
+static const cairo_user_data_key_t _csi_proxy_key;
+static const cairo_user_data_key_t _csi_blob_key;
+
+enum mime_type {
+ MIME_TYPE_NONE = 0,
+ MIME_TYPE_PNG
+};
+
+#define check(CNT) do {\
+ if (_csi_unlikely (! _csi_check_ostack (ctx, (CNT)))) \
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT); \
+} while (0)
+#define pop(CNT) _csi_pop_ostack (ctx, (CNT))
+#define push(OBJ) _csi_push_ostack (ctx, (OBJ))
+
+static csi_proxy_t *
+_csi_proxy_create (csi_t *ctx,
+ void *ptr,
+ csi_dictionary_t *dictionary,
+ csi_destroy_func_t destroy_func,
+ void *destroy_data)
+{
+ csi_proxy_t *proxy;
+
+ proxy = _csi_slab_alloc (ctx, sizeof (csi_proxy_t));
+ if (proxy == NULL)
+ return NULL;
+
+ proxy->ctx = cairo_script_interpreter_reference (ctx);
+ proxy->ptr = ptr;
+ proxy->destroy_func = destroy_func;
+ proxy->destroy_data = destroy_data;
+ proxy->dictionary = dictionary;
+ if (dictionary != NULL)
+ dictionary->base.ref++;
+
+ return proxy;
+}
+
+static void
+_csi_proxy_destroy (void *closure)
+{
+ csi_proxy_t *proxy = closure;
+ csi_t *ctx = proxy->ctx;
+
+ /* XXX this doesn't work because user_data_destroy is called too late.
+ * Considering another hook into the (cairo internal) object system.
+ */
+ if (proxy->destroy_func != NULL)
+ proxy->destroy_func (proxy->destroy_data, proxy->ptr);
+
+ if (proxy->dictionary != NULL && --proxy->dictionary->base.ref == 0)
+ csi_dictionary_free (ctx, proxy->dictionary);
+
+ _csi_slab_free (ctx, proxy, sizeof (csi_proxy_t));
+ cairo_script_interpreter_destroy (ctx);
+}
+
+static unsigned long
+_csi_blob_hash (const uint8_t *bytes, int len)
+{
+ /* very simple! */
+ unsigned long hash = 5381;
+ unsigned long *data = (unsigned long *) bytes;
+ len /= sizeof (unsigned long);
+ while (len--) {
+ unsigned long c = *data++;
+ hash *= 33;
+ hash ^= c;
+ }
+ return hash;
+}
+
+static csi_boolean_t
+_csi_blob_equal (const csi_list_t *link, void *data)
+{
+ csi_blob_t *A, *B;
+
+ A = csi_container_of (link, csi_blob_t, list);
+ B = data;
+
+ if (A->len != B->len)
+ return FALSE;
+
+ if (A->hash == 0)
+ A->hash = _csi_blob_hash (A->bytes, A->len);
+ if (B->hash == 0)
+ B->hash = _csi_blob_hash (B->bytes, B->len);
+ if (A->hash != B->hash)
+ return FALSE;
+
+ return memcmp (A->bytes, B->bytes, A->len) == 0;
+}
+
+static void
+_csi_blob_init (csi_blob_t *blob, uint8_t *bytes, int len)
+{
+ blob->hash = 0;
+ blob->len = len;
+ blob->bytes = bytes;
+}
+
+static csi_list_t *
+_csi_list_unlink (csi_list_t *head, csi_list_t *link)
+{
+ if (link->next != NULL)
+ link->next->prev = link->prev;
+ if (link->prev != NULL)
+ link->prev->next = link->next;
+ else
+ head = link->next;
+ return head;
+}
+
+static csi_list_t *
+_csi_list_prepend (csi_list_t *head, csi_list_t *link)
+{
+ if (head != NULL)
+ head->prev = link;
+ link->next = head;
+ link->prev = NULL;
+ return link;
+}
+
+static csi_list_t *
+_csi_list_find (csi_list_t *head,
+ csi_boolean_t (*predicate) (const csi_list_t *link, void *data),
+ void *data)
+{
+ while (head != NULL) {
+ if (predicate (head, data))
+ return head;
+ head = head->next;
+ }
+
+ return NULL;
+}
+
+static csi_status_t
+_csi_ostack_get_boolean (csi_t *ctx, unsigned int i, csi_boolean_t *out)
+{
+ csi_object_t *obj;
+
+ obj = _csi_peek_ostack (ctx, i);
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_BOOLEAN:
+ *out = obj->datum.boolean;
+ break;
+ case CSI_OBJECT_TYPE_INTEGER:
+ *out = !! obj->datum.integer;
+ break;
+ case CSI_OBJECT_TYPE_REAL:
+ *out = obj->datum.real != 0.;
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_csi_ostack_get_integer (csi_t *ctx, unsigned int i, csi_integer_t *out)
+{
+ csi_object_t *obj;
+
+ obj = _csi_peek_ostack (ctx, i);
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_BOOLEAN:
+ *out = obj->datum.boolean;
+ break;
+ case CSI_OBJECT_TYPE_INTEGER:
+ *out = obj->datum.integer;
+ break;
+ case CSI_OBJECT_TYPE_REAL:
+ *out = obj->datum.real;
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_csi_ostack_get_number (csi_t *ctx, unsigned int i, double *out)
+{
+ csi_object_t *obj;
+
+ obj = _csi_peek_ostack (ctx, i);
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_BOOLEAN:
+ *out = obj->datum.boolean;
+ break;
+ case CSI_OBJECT_TYPE_INTEGER:
+ *out = obj->datum.integer;
+ break;
+ case CSI_OBJECT_TYPE_REAL:
+ *out = obj->datum.real;
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_csi_ostack_get_name (csi_t *ctx, unsigned int i, csi_name_t *out)
+{
+ csi_object_t *obj;
+
+ obj = _csi_peek_ostack (ctx, i);
+ if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_NAME))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ *out = obj->datum.name;
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_csi_ostack_get_context (csi_t *ctx, unsigned int i, cairo_t **out)
+{
+ csi_object_t *obj;
+
+ obj = _csi_peek_ostack (ctx, i);
+ if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_CONTEXT))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ *out = obj->datum.cr;
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_csi_ostack_get_font_face (csi_t *ctx, unsigned int i, cairo_font_face_t **out)
+{
+ csi_object_t *obj;
+
+ obj = _csi_peek_ostack (ctx, i);
+ if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_FONT))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ *out = obj->datum.font_face;
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_csi_ostack_get_pattern (csi_t *ctx, unsigned int i, cairo_pattern_t **out)
+{
+ csi_object_t *obj;
+
+ obj = _csi_peek_ostack (ctx, i);
+ if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_PATTERN))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ *out = obj->datum.pattern;
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_csi_ostack_get_scaled_font (csi_t *ctx, unsigned int i,
+ cairo_scaled_font_t **out)
+{
+ csi_object_t *obj;
+
+ obj = _csi_peek_ostack (ctx, i);
+ if (_csi_unlikely
+ (csi_object_get_type (obj) != CSI_OBJECT_TYPE_SCALED_FONT))
+ {
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ *out = obj->datum.scaled_font;
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_csi_ostack_get_surface (csi_t *ctx, unsigned int i, cairo_surface_t **out)
+{
+ csi_object_t *obj;
+
+ obj = _csi_peek_ostack (ctx, i);
+ if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_SURFACE))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ *out = obj->datum.surface;
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_csi_ostack_get_array (csi_t *ctx, unsigned int i, csi_array_t **out)
+{
+ csi_object_t *obj;
+
+ obj = _csi_peek_ostack (ctx, i);
+ if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_ARRAY))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ *out = obj->datum.array;
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_csi_ostack_get_procedure (csi_t *ctx, unsigned int i, csi_array_t **out)
+{
+ csi_object_t *obj;
+
+ obj = _csi_peek_ostack (ctx, i);
+ if (_csi_unlikely (! csi_object_is_procedure (obj)))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ *out = obj->datum.array;
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_csi_ostack_get_dictionary (csi_t *ctx, unsigned int i, csi_dictionary_t **out)
+{
+ csi_object_t *obj;
+
+ obj = _csi_peek_ostack (ctx, i);
+ if (_csi_unlikely
+ (csi_object_get_type (obj) != CSI_OBJECT_TYPE_DICTIONARY))
+ {
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ *out = obj->datum.dictionary;
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_csi_ostack_get_matrix (csi_t *ctx, unsigned int i, cairo_matrix_t *out)
+{
+ csi_object_t *obj;
+
+ obj = _csi_peek_ostack (ctx, i);
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_MATRIX:
+ *out = obj->datum.matrix->matrix;
+ return CSI_STATUS_SUCCESS;
+
+ case CSI_OBJECT_TYPE_ARRAY:
+ if (obj->datum.array->stack.len == 6) {
+ cairo_matrix_init (out,
+ csi_number_get_value (&obj->datum.array->stack.objects[0]),
+ csi_number_get_value (&obj->datum.array->stack.objects[1]),
+ csi_number_get_value (&obj->datum.array->stack.objects[2]),
+ csi_number_get_value (&obj->datum.array->stack.objects[3]),
+ csi_number_get_value (&obj->datum.array->stack.objects[4]),
+ csi_number_get_value (&obj->datum.array->stack.objects[5]));
+ return CSI_STATUS_SUCCESS;
+ }
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+}
+
+static csi_status_t
+_csi_dictionary_get_integer (csi_t *ctx,
+ csi_dictionary_t *dict,
+ const char *name,
+ csi_boolean_t optional,
+ long *value)
+{
+ csi_status_t status;
+ csi_object_t key, obj;
+
+ status = csi_name_new_static (ctx, &key, name);
+ if (_csi_unlikely (status))
+ return status;
+
+ if (optional && ! csi_dictionary_has (dict, key.datum.name))
+ return CSI_STATUS_SUCCESS;
+
+ status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
+ if (_csi_unlikely (status))
+ return status;
+
+ switch ((int) csi_object_get_type (&obj)) {
+ case CSI_OBJECT_TYPE_BOOLEAN:
+ *value = obj.datum.boolean;
+ break;
+ case CSI_OBJECT_TYPE_INTEGER:
+ *value = obj.datum.integer;
+ break;
+ case CSI_OBJECT_TYPE_REAL:
+ *value = obj.datum.real;
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_csi_dictionary_get_number (csi_t *ctx,
+ csi_dictionary_t *dict,
+ const char *name,
+ csi_boolean_t optional,
+ double *value)
+{
+ csi_status_t status;
+ csi_object_t key, obj;
+
+ status = csi_name_new_static (ctx, &key, name);
+ if (_csi_unlikely (status))
+ return status;
+
+ if (optional && ! csi_dictionary_has (dict, key.datum.name))
+ return CSI_STATUS_SUCCESS;
+
+ status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
+ if (_csi_unlikely (status))
+ return status;
+
+ *value = csi_number_get_value (&obj);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_csi_ostack_get_string (csi_t *ctx, unsigned int i, csi_string_t **out)
+{
+ csi_object_t *obj;
+
+ obj = _csi_peek_ostack (ctx, i);
+ if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_STRING))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ *out = obj->datum.string;
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_csi_ostack_get_string_constant (csi_t *ctx, unsigned int i, const char **out)
+{
+ csi_object_t *obj;
+
+ obj = _csi_peek_ostack (ctx, i);
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_NAME:
+ *out = (const char *) obj->datum.name;
+ break;
+ case CSI_OBJECT_TYPE_STRING:
+ *out = obj->datum.string->string;
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_do_cairo_op (csi_t *ctx, void (*op) (cairo_t *))
+{
+ cairo_t *cr;
+ csi_status_t status;
+
+ check (1);
+
+ status = _csi_ostack_get_context (ctx, 0, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ op (cr);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+end_dict_construction (csi_t *ctx)
+{
+ csi_object_t obj;
+ csi_dictionary_t *dict;
+ csi_status_t status;
+
+ status = csi_dictionary_new (ctx, &obj);
+ if (_csi_unlikely (status))
+ return status;
+
+ dict = obj.datum.dictionary;
+ do {
+ csi_object_t *name, *value;
+
+ check (1);
+
+ value = _csi_peek_ostack (ctx, 0);
+ if (csi_object_get_type (value) == CSI_OBJECT_TYPE_MARK) {
+ pop (1);
+ break;
+ }
+
+ check (1);
+
+ name = _csi_peek_ostack (ctx, 0);
+ if (_csi_unlikely
+ (csi_object_get_type (name) != CSI_OBJECT_TYPE_NAME))
+ {
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ status = csi_dictionary_put (ctx, dict, name->datum.name, value);
+ if (_csi_unlikely (status))
+ return status;
+
+ pop (2);
+ } while (TRUE);
+
+ return push (&obj);
+}
+
+static csi_status_t
+end_array_construction (csi_t *ctx)
+{
+ csi_object_t obj;
+ csi_array_t *array;
+ csi_status_t status;
+
+ status = csi_array_new (ctx, &obj);
+ if (_csi_unlikely (status))
+ return status;
+
+ array = obj.datum.array;
+ do {
+ csi_object_t *value;
+
+ check (1);
+
+ value = _csi_peek_ostack (ctx, 0);
+ if (csi_object_get_type (value) == CSI_OBJECT_TYPE_MARK) {
+ pop (1);
+ break;
+ }
+
+ status = csi_array_append (ctx, array, value);
+ if (_csi_unlikely (status))
+ return status;
+
+ pop (1);
+ } while (TRUE);
+
+ /* and reverse */
+ if (array->stack.len) {
+ unsigned int i, j;
+
+ for (i = 0, j = array->stack.len; i < --j; i++) {
+ csi_object_t tmp;
+
+ tmp = array->stack.objects[i];
+ array->stack.objects[i] = array->stack.objects[j];
+ array->stack.objects[j] = tmp;
+ }
+ }
+
+ return push (&obj);
+}
+
+static csi_status_t
+_alpha (csi_t *ctx)
+{
+ csi_object_t obj;
+ csi_status_t status;
+ double a;
+
+ check (1);
+
+ status = _csi_ostack_get_number (ctx, 0, &a);
+ if (_csi_unlikely (status))
+ return status;
+
+ pop (1);
+
+ obj.type = CSI_OBJECT_TYPE_PATTERN;
+ obj.datum.pattern = cairo_pattern_create_rgba (0, 0, 0, a);
+ return push (&obj);
+}
+
+static csi_status_t
+_add (csi_t *ctx)
+{
+ csi_object_t *A;
+ csi_object_t *B;
+ csi_object_type_t type_a, type_b;
+
+ check (2);
+
+ B = _csi_peek_ostack (ctx, 0);
+ A = _csi_peek_ostack (ctx, 1);
+
+ type_a = csi_object_get_type (A);
+ if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER ||
+ type_a == CSI_OBJECT_TYPE_REAL)))
+ {
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ type_b = csi_object_get_type (B);
+ if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER ||
+ type_b == CSI_OBJECT_TYPE_REAL)))
+ {
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ pop (2);
+
+ if (type_a == CSI_OBJECT_TYPE_REAL &&
+ type_b == CSI_OBJECT_TYPE_REAL)
+ {
+ return _csi_push_ostack_real (ctx, A->datum.real + B->datum.real);
+
+ }
+ else if (type_a == CSI_OBJECT_TYPE_INTEGER &&
+ type_b == CSI_OBJECT_TYPE_INTEGER)
+ {
+ return _csi_push_ostack_integer (ctx,
+ A->datum.integer + B->datum.integer);
+ }
+ else
+ {
+ double v;
+
+ if (type_a == CSI_OBJECT_TYPE_REAL)
+ v = A->datum.real;
+ else
+ v = A->datum.integer;
+
+ if (type_b == CSI_OBJECT_TYPE_REAL)
+ v += B->datum.real;
+ else
+ v += B->datum.integer;
+
+ return _csi_push_ostack_real (ctx, v);
+ }
+}
+
+static csi_status_t
+_add_color_stop (csi_t *ctx)
+{
+ csi_status_t status;
+ double offset, r, g, b, a;
+ cairo_pattern_t *pattern;
+
+ check (6);
+
+ status = _csi_ostack_get_number (ctx, 0, &a);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 1, &b);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 2, &g);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 3, &r);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 4, &offset);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_pattern (ctx, 5, &pattern);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_pattern_add_color_stop_rgba (pattern, offset, r, g, b, a);
+
+ pop (5);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_and (csi_t *ctx)
+{
+ csi_object_t *a, *b;
+
+ check (2);
+
+ a = _csi_peek_ostack (ctx, 0);
+ b = _csi_peek_ostack (ctx, 1);
+ if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b)))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ pop (2);
+ switch ((int) csi_object_get_type (a)) {
+ case CSI_OBJECT_TYPE_INTEGER:
+ return _csi_push_ostack_integer (ctx,
+ a->datum.integer & b->datum.integer);
+ case CSI_OBJECT_TYPE_BOOLEAN:
+ return _csi_push_ostack_boolean (ctx,
+ a->datum.boolean & b->datum.boolean);
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+}
+
+static csi_status_t
+_arc (csi_t *ctx)
+{
+ csi_status_t status;
+ double x, y, r;
+ double theta1, theta2;
+ cairo_t *cr;
+
+ check (6);
+
+ status = _csi_ostack_get_number (ctx, 0, &theta2);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 1, &theta1);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 2, &r);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 3, &y);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 4, &x);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 5, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ /* XXX handle path object */
+
+ cairo_arc (cr, x, y, r, theta1, theta2);
+ pop (5);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_arc_negative (csi_t *ctx)
+{
+ csi_status_t status;
+ double x, y, r;
+ double theta1, theta2;
+ cairo_t *cr;
+
+ check (6);
+
+ status = _csi_ostack_get_number (ctx, 0, &theta2);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 1, &theta1);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 2, &r);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 3, &y);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 4, &x);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 5, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ /* XXX handle path object */
+
+ cairo_arc_negative (cr, x, y, r, theta1, theta2);
+ pop (5);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_array (csi_t *ctx)
+{
+ csi_object_t obj;
+ csi_status_t status;
+
+ status = csi_array_new (ctx, &obj);
+ if (_csi_unlikely (status))
+ return status;
+
+ return push (&obj);
+}
+
+static csi_status_t
+_bind_substitute (csi_t *ctx, csi_array_t *array)
+{
+ csi_status_t status;
+ csi_integer_t i, n;
+ csi_dictionary_t *dict;
+
+ /* perform operator substitution on the executable array (procedure) */
+ dict = ctx->dstack.objects[0].datum.dictionary;
+ n = array->stack.len;
+ for (i = 0; i < n; i++) {
+ csi_object_t *obj = &array->stack.objects[i];
+
+ if (obj->type == (CSI_OBJECT_TYPE_NAME | CSI_OBJECT_ATTR_EXECUTABLE)) {
+ csi_dictionary_entry_t *entry;
+
+ entry = _csi_hash_table_lookup (&dict->hash_table,
+ (csi_hash_entry_t *)
+ &obj->datum.name);
+ if (entry != NULL)
+ *obj = entry->value;
+ } else if (csi_object_is_procedure (obj)) {
+ status = _bind_substitute (ctx, obj->datum.array);
+ if (_csi_unlikely (status))
+ return status;
+ }
+ }
+
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_idiom_substitute (csi_t *ctx, csi_array_t *array)
+{
+#if 0
+ csi_status_t status;
+ csi_integer_t i, j;
+
+ /* XXX substring search, build array once then search for
+ * longest matching idiom, repeat. */
+
+ /* scan the top-most array for sequences we can pre-compile */
+
+ /* now recurse for subroutines */
+ j = array->stack.len;
+ for (i = 0; i < j; i++) {
+ csi_object_t *obj = &array->stack.objects[i];
+
+ if (csi_object_is_procedure (obj)) {
+ status = _idiom_substitute (ctx, obj->datum.array);
+ if (_csi_unlikely (_cairo_is_error (status))
+ return status;
+ }
+ }
+#endif
+
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_bind (csi_t *ctx)
+{
+ csi_array_t *array;
+ csi_status_t status;
+
+ check (1);
+
+ status = _csi_ostack_get_procedure (ctx, 0, &array);
+ if (_csi_unlikely (status))
+ return status;
+
+ status = _bind_substitute (ctx, array);
+ if (_csi_unlikely (status))
+ return status;
+
+ status = _idiom_substitute (ctx, array);
+ if (_csi_unlikely (status))
+ return status;
+
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_bitshift (csi_t *ctx)
+{
+ long v, shift;
+ csi_status_t status;
+
+ check (2);
+
+ status = _csi_ostack_get_integer (ctx, 0, &shift);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_integer (ctx, 1, &v);
+ if (_csi_unlikely (status))
+ return status;
+
+ if (shift < 0) {
+ shift = -shift;
+ v <<= shift;
+ } else
+ v >>= shift;
+
+ pop (1);
+ _csi_peek_ostack (ctx, 0)->datum.integer = v;
+
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_clip (csi_t *ctx)
+{
+ return _do_cairo_op (ctx, cairo_clip);
+}
+
+static csi_status_t
+_clip_preserve (csi_t *ctx)
+{
+ return _do_cairo_op (ctx, cairo_clip_preserve);
+}
+
+static csi_status_t
+_close_path (csi_t *ctx)
+{
+ return _do_cairo_op (ctx, cairo_close_path);
+}
+
+static csi_status_t
+_context (csi_t *ctx)
+{
+ csi_object_t obj;
+ csi_status_t status;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ csi_proxy_t *proxy;
+
+ check (1);
+
+ status = _csi_ostack_get_surface (ctx, 0, &surface);
+ if (_csi_unlikely (status))
+ return status;
+
+ cr = cairo_create (surface);
+
+ proxy = _csi_proxy_create (ctx, cr, NULL,
+ ctx->hooks.context_destroy,
+ ctx->hooks.closure);
+ if (_csi_unlikely (proxy == NULL)) {
+ cairo_destroy (cr);
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ }
+
+ status = cairo_set_user_data (cr, &_csi_proxy_key,
+ proxy, _csi_proxy_destroy);
+ if (_csi_unlikely (status)) {
+ _csi_proxy_destroy (proxy);
+ cairo_destroy (cr);
+ return status;
+ }
+
+ pop (1);
+ obj.type = CSI_OBJECT_TYPE_CONTEXT;
+ obj.datum.cr = cr;
+ return push (&obj);
+}
+
+static csi_status_t
+_copy (csi_t *ctx)
+{
+ csi_object_t *obj;
+
+ check (1);
+
+ obj = csi_object_reference (_csi_peek_ostack (ctx, 0));
+ pop (1);
+
+ switch ((int) csi_object_get_type (obj)) {
+ /*XXX array, string, dictionary, etc */
+ case CSI_OBJECT_TYPE_INTEGER:
+ {
+ long i, n;
+
+ n = obj->datum.integer;
+ if (_csi_unlikely (n < 0))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ check (n);
+
+ for (i = n; i--; ) {
+ csi_status_t status;
+
+ status = _csi_push_ostack_copy (ctx,
+ _csi_peek_ostack (ctx, n-1));
+ if (_csi_unlikely (status))
+ return status;
+ }
+ break;
+ }
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_copy_page (csi_t *ctx)
+{
+ csi_object_t *obj;
+
+ check (1);
+
+ obj = _csi_peek_ostack (ctx, 0);
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_CONTEXT:
+ cairo_copy_page (obj->datum.cr);
+ if (ctx->hooks.copy_page != NULL)
+ ctx->hooks.copy_page (ctx->hooks.closure, obj->datum.cr);
+ break;
+ case CSI_OBJECT_TYPE_SURFACE:
+ cairo_surface_copy_page (obj->datum.surface);
+ /* XXX hook? */
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_curve_to (csi_t *ctx)
+{
+ csi_status_t status;
+ double x1, y1;
+ double x2, y2;
+ double x3, y3;
+ cairo_t *cr;
+
+ check (7);
+
+ status = _csi_ostack_get_number (ctx, 0, &y3);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 1, &x3);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 2, &y2);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 3, &x2);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 4, &y1);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 5, &x1);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 6, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ /* XXX handle path object */
+
+ cairo_curve_to (cr, x1, y1, x2, y2, x3, y3);
+ pop (6);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_def (csi_t *ctx)
+{
+ csi_name_t name;
+ csi_status_t status;
+
+ check (2);
+
+ status = _csi_ostack_get_name (ctx, 1, &name);
+ if (_csi_unlikely (status))
+ return status;
+
+ status = _csi_name_define (ctx, name, _csi_peek_ostack (ctx, 0));
+ if (_csi_unlikely (status))
+ return status;
+
+ pop (2);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_dict (csi_t *ctx)
+{
+ csi_object_t obj;
+ csi_status_t status;
+
+ status = csi_dictionary_new (ctx, &obj);
+ if (_csi_unlikely (status))
+ return status;
+
+ return push (&obj);
+}
+
+static csi_status_t
+_div (csi_t *ctx)
+{
+ csi_object_t *A;
+ csi_object_t *B;
+ csi_object_type_t type_a, type_b;
+
+ check (2);
+
+ B = _csi_peek_ostack (ctx, 0);
+ A = _csi_peek_ostack (ctx, 1);
+
+ type_a = csi_object_get_type (A);
+ if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER ||
+ type_a == CSI_OBJECT_TYPE_REAL)))
+ {
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ type_b = csi_object_get_type (B);
+ if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER ||
+ type_b == CSI_OBJECT_TYPE_REAL)))
+ {
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ pop (2);
+
+ if (type_a == CSI_OBJECT_TYPE_REAL &&
+ type_b == CSI_OBJECT_TYPE_REAL)
+ {
+ return _csi_push_ostack_real (ctx, A->datum.real / B->datum.real);
+
+ }
+ else if (type_a == CSI_OBJECT_TYPE_INTEGER &&
+ type_b == CSI_OBJECT_TYPE_INTEGER)
+ {
+ return _csi_push_ostack_integer (ctx,
+ A->datum.integer / B->datum.integer);
+ }
+ else
+ {
+ double v;
+
+ if (type_a == CSI_OBJECT_TYPE_REAL)
+ v = A->datum.real;
+ else
+ v = A->datum.integer;
+
+ if (type_b == CSI_OBJECT_TYPE_REAL)
+ v /= B->datum.real;
+ else
+ v /= B->datum.integer;
+
+ return _csi_push_ostack_real (ctx, v);
+ }
+}
+
+static csi_status_t
+_dup (csi_t *ctx)
+{
+ check (1);
+
+ return _csi_push_ostack_copy (ctx, _csi_peek_ostack (ctx, 0));
+}
+
+static csi_status_t
+_eq (csi_t *ctx)
+{
+ csi_object_t *a, *b;
+ csi_boolean_t v;
+
+ check (2);
+
+ b = _csi_peek_ostack (ctx, 0);
+ a = _csi_peek_ostack (ctx, 1);
+
+ if (csi_object_get_type (a) != csi_object_get_type (b)) {
+ switch ((int) csi_object_get_type (a)) {
+ case CSI_OBJECT_TYPE_BOOLEAN:
+ switch ((int) csi_object_get_type (b)) {
+ case CSI_OBJECT_TYPE_INTEGER:
+ v = a->datum.boolean == !! b->datum.integer;
+ break;
+ case CSI_OBJECT_TYPE_REAL:
+ v = a->datum.boolean == (b->datum.real != 0);
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+ break;
+
+ case CSI_OBJECT_TYPE_INTEGER:
+ switch ((int) csi_object_get_type (b)) {
+ case CSI_OBJECT_TYPE_BOOLEAN:
+ v = a->datum.integer == b->datum.boolean;
+ break;
+ case CSI_OBJECT_TYPE_REAL:
+ v = a->datum.integer == b->datum.real;
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+ break;
+
+ case CSI_OBJECT_TYPE_REAL:
+ switch ((int) csi_object_get_type (b)) {
+ case CSI_OBJECT_TYPE_BOOLEAN:
+ v = a->datum.real == b->datum.boolean;
+ break;
+ case CSI_OBJECT_TYPE_INTEGER:
+ v = a->datum.real == b->datum.integer;
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+ break;
+
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+ } else {
+ if (CSI_OBJECT_IS_CAIRO (a)) {
+ v = a->datum.ptr == b->datum.ptr;
+ } else if (CSI_OBJECT_IS_COMPOUND (a)) {
+ v = a->datum.object == b->datum.object;
+ } else switch ((int) csi_object_get_type (a)) {
+ case CSI_OBJECT_TYPE_BOOLEAN:
+ v = a->datum.boolean == b->datum.boolean;
+ break;
+ case CSI_OBJECT_TYPE_INTEGER:
+ v = a->datum.integer == b->datum.integer;
+ break;
+ case CSI_OBJECT_TYPE_REAL:
+ v = a->datum.real == b->datum.real;
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+ }
+
+ pop (2);
+ return _csi_push_ostack_boolean (ctx, v);
+}
+
+static csi_status_t
+_exch (csi_t *ctx)
+{
+ return _csi_stack_exch (&ctx->ostack);
+}
+
+static csi_status_t
+_false (csi_t *ctx)
+{
+ return _csi_push_ostack_boolean (ctx, FALSE);
+}
+
+static csi_status_t
+_fill (csi_t *ctx)
+{
+ return _do_cairo_op (ctx, cairo_fill);
+}
+
+static csi_status_t
+_fill_preserve (csi_t *ctx)
+{
+ return _do_cairo_op (ctx, cairo_fill_preserve);
+}
+
+static csi_status_t
+_filter (csi_t *ctx)
+{
+ csi_object_t *src;
+ csi_dictionary_t *dict = NULL;
+ csi_status_t status;
+ const char *name;
+ const struct filters {
+ const char *name;
+ csi_status_t (*constructor) (csi_t *t,
+ csi_object_t *,
+ csi_dictionary_t *,
+ csi_object_t *);
+ } filters[] = {
+ { "ascii85", csi_file_new_ascii85_decode },
+#if HAVE_ZLIB
+ { "deflate", csi_file_new_deflate_decode },
+#endif
+#if 0
+ { "lzw", csi_file_new_lzw_decode },
+#endif
+ { NULL, NULL }
+ }, *filter;
+ int cnt;
+
+ check (2);
+
+ status = _csi_ostack_get_string_constant (ctx, 0, &name);
+ if (_csi_unlikely (status))
+ return status;
+
+ src = _csi_peek_ostack (ctx, 1);
+ cnt = 2;
+ if (csi_object_get_type (src) == CSI_OBJECT_TYPE_DICTIONARY) {
+ dict = src->datum.dictionary;
+
+ check (3);
+
+ src = _csi_peek_ostack (ctx, 2);
+ cnt = 3;
+ }
+
+ for (filter = filters; filter->name != NULL; filter++) {
+ if (strcmp (name, filter->name) == 0) {
+ csi_object_t file;
+
+ status = filter->constructor (ctx, &file, dict, src);
+ if (_csi_unlikely (status))
+ return status;
+
+ pop (cnt);
+ return push (&file);
+ }
+ }
+
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+}
+
+static cairo_status_t
+_type3_init (cairo_scaled_font_t *scaled_font,
+ cairo_t *cr,
+ cairo_font_extents_t *metrics)
+{
+ cairo_font_face_t *face;
+ csi_proxy_t *proxy;
+ csi_t *ctx;
+ csi_dictionary_t *font;
+ csi_object_t key;
+ csi_object_t obj;
+ csi_array_t *array;
+ csi_status_t status;
+
+ face = cairo_scaled_font_get_font_face (scaled_font);
+ proxy = cairo_font_face_get_user_data (face, &_csi_proxy_key);
+ if (_csi_unlikely (proxy == NULL))
+ return CAIRO_STATUS_NO_MEMORY;
+
+ ctx = proxy->ctx;
+ font = proxy->dictionary;
+
+ status = csi_name_new_static (ctx, &key, "metrics");
+ if (_csi_unlikely (status))
+ return CAIRO_STATUS_NO_MEMORY;
+
+ if (! csi_dictionary_has (font, key.datum.name))
+ return CAIRO_STATUS_SUCCESS;
+
+ status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
+ if (_csi_unlikely (status))
+ return status;
+
+ if (csi_object_get_type (&obj) != CSI_OBJECT_TYPE_ARRAY)
+ return CAIRO_STATUS_USER_FONT_ERROR;
+
+ array = obj.datum.array;
+ if (array->stack.len != 5)
+ return CAIRO_STATUS_USER_FONT_ERROR;
+
+ metrics->ascent = csi_number_get_value (&array->stack.objects[0]);
+ metrics->descent = csi_number_get_value (&array->stack.objects[1]);
+ metrics->height = csi_number_get_value (&array->stack.objects[2]);
+ metrics->max_x_advance = csi_number_get_value (&array->stack.objects[3]);
+ metrics->max_y_advance = csi_number_get_value (&array->stack.objects[4]);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_type3_lookup (cairo_scaled_font_t *scaled_font,
+ unsigned long unicode,
+ unsigned long *glyph)
+{
+ cairo_font_face_t *face;
+ csi_proxy_t *proxy;
+ csi_t *ctx;
+ csi_dictionary_t *font;
+ csi_object_t obj, key;
+ csi_array_t *array;
+ char buf[12];
+ csi_integer_t i;
+ cairo_status_t status;
+
+ face = cairo_scaled_font_get_font_face (scaled_font);
+ proxy = cairo_font_face_get_user_data (face, &_csi_proxy_key);
+ if (_csi_unlikely (proxy == NULL))
+ return CAIRO_STATUS_USER_FONT_ERROR;
+
+ ctx = proxy->ctx;
+ font = proxy->dictionary;
+
+ status = csi_name_new_static (ctx, &key, "encoding");
+ if (_csi_unlikely (status))
+ return CAIRO_STATUS_USER_FONT_ERROR;
+
+ if (! csi_dictionary_has (font, key.datum.name)) {
+ *glyph = unicode;
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
+ if (_csi_unlikely (status))
+ return CAIRO_STATUS_USER_FONT_ERROR;
+
+ if (_csi_unlikely (csi_object_get_type (&obj) != CSI_OBJECT_TYPE_ARRAY))
+ return CAIRO_STATUS_USER_FONT_ERROR;
+
+ snprintf (buf, sizeof (buf), "uni%04lu", unicode);
+ array = obj.datum.array;
+ for (i = 0; i < array->stack.len; i++) {
+ csi_object_t *name;
+
+ name = &array->stack.objects[i];
+ if (csi_object_get_type (name) != CSI_OBJECT_TYPE_NAME)
+ continue;
+
+ if (strcmp ((char *) name->datum.name, buf) == 0) {
+ *glyph = i;
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+
+ return CAIRO_STATUS_USER_FONT_ERROR;
+}
+
+static cairo_status_t
+_type3_render (cairo_scaled_font_t *scaled_font,
+ unsigned long glyph_index,
+ cairo_t *cr,
+ cairo_text_extents_t *metrics)
+{
+ cairo_font_face_t *face;
+ csi_proxy_t *proxy;
+ csi_t *ctx;
+ csi_dictionary_t *font;
+ csi_array_t *glyphs;
+ csi_object_t *glyph;
+ csi_object_t key;
+ csi_object_t obj;
+ csi_object_t render;
+ csi_status_t status;
+
+ face = cairo_scaled_font_get_font_face (scaled_font);
+ proxy = cairo_font_face_get_user_data (face, &_csi_proxy_key);
+ if (_csi_unlikely (proxy == NULL))
+ return CAIRO_STATUS_USER_FONT_ERROR;
+
+ ctx = proxy->ctx;
+ font = proxy->dictionary;
+
+ status = csi_name_new_static (ctx, &key, "glyphs");
+ if (_csi_unlikely (status))
+ return CAIRO_STATUS_USER_FONT_ERROR;
+
+ status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
+ if (_csi_unlikely (status))
+ return CAIRO_STATUS_USER_FONT_ERROR;
+
+ if (_csi_unlikely (csi_object_get_type (&obj) != CSI_OBJECT_TYPE_ARRAY))
+ return CAIRO_STATUS_USER_FONT_ERROR;
+
+ glyphs = obj.datum.array;
+ glyph = &glyphs->stack.objects[glyph_index];
+ if (csi_object_get_type (glyph) == CSI_OBJECT_TYPE_NULL)
+ return CAIRO_STATUS_SUCCESS; /* .notdef */
+
+ if (_csi_unlikely (csi_object_get_type (glyph) != CSI_OBJECT_TYPE_DICTIONARY))
+ return CAIRO_STATUS_USER_FONT_ERROR;
+
+ status = csi_name_new_static (ctx, &key, "metrics");
+ if (_csi_unlikely (status))
+ return CAIRO_STATUS_USER_FONT_ERROR;
+
+ font = glyph->datum.dictionary;
+ if (csi_dictionary_has (font, key.datum.name)) {
+ csi_array_t *array;
+
+ status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
+ if (_csi_unlikely (status))
+ return CAIRO_STATUS_USER_FONT_ERROR;
+
+ if (_csi_unlikely (csi_object_get_type (&obj) !=
+ CSI_OBJECT_TYPE_ARRAY))
+ return CAIRO_STATUS_USER_FONT_ERROR;
+
+ array = obj.datum.array;
+ if (_csi_unlikely (array->stack.len != 6))
+ return CAIRO_STATUS_USER_FONT_ERROR;
+
+ metrics->x_bearing = csi_number_get_value (&array->stack.objects[0]);
+ metrics->y_bearing = csi_number_get_value (&array->stack.objects[1]);
+ metrics->width = csi_number_get_value (&array->stack.objects[2]);
+ metrics->height = csi_number_get_value (&array->stack.objects[3]);
+ metrics->x_advance = csi_number_get_value (&array->stack.objects[4]);
+ metrics->y_advance = csi_number_get_value (&array->stack.objects[5]);
+ }
+
+ status = csi_name_new_static (ctx, &key, "render");
+ if (_csi_unlikely (status))
+ return CAIRO_STATUS_USER_FONT_ERROR;
+
+ status = csi_dictionary_get (ctx, font, key.datum.name, &render);
+ if (_csi_unlikely (status))
+ return CAIRO_STATUS_USER_FONT_ERROR;
+
+ if (_csi_unlikely (! csi_object_is_procedure (&render)))
+ return CAIRO_STATUS_USER_FONT_ERROR;
+
+ obj.type = CSI_OBJECT_TYPE_CONTEXT;
+ obj.datum.cr = cairo_reference (cr);
+ status = push (&obj);
+ if (_csi_unlikely (status)) {
+ cairo_destroy (cr);
+ return CAIRO_STATUS_USER_FONT_ERROR;
+ }
+
+ status = csi_object_execute (ctx, &render);
+ pop (1);
+ return CAIRO_STATUS_USER_FONT_ERROR;
+}
+
+static csi_status_t
+_font_type3 (csi_t *ctx,
+ csi_dictionary_t *font,
+ cairo_font_face_t **font_face_out)
+{
+ cairo_font_face_t *font_face;
+
+ font_face = cairo_user_font_face_create ();
+ cairo_user_font_face_set_init_func (font_face, _type3_init);
+ cairo_user_font_face_set_unicode_to_glyph_func (font_face, _type3_lookup);
+ cairo_user_font_face_set_render_glyph_func (font_face, _type3_render);
+
+ *font_face_out = font_face;
+ return CSI_STATUS_SUCCESS;
+}
+
+#if CAIRO_HAS_FT_FONT
+#include <cairo-ft.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+static FT_Library _ft_lib;
+
+struct _ft_face_data {
+ csi_t *ctx;
+ csi_blob_t blob;
+ FT_Face face;
+ csi_string_t *source;
+ cairo_font_face_t *font_face;
+};
+
+static void
+_ft_done_face (void *closure)
+{
+ struct _ft_face_data *data = closure;
+ csi_t *ctx;
+
+ ctx = data->ctx;
+
+ if (data->face != NULL)
+ FT_Done_Face (data->face);
+
+ ctx->_faces = _csi_list_unlink (ctx->_faces, &data->blob.list);
+
+ if (--data->source->base.ref == 0)
+ csi_string_free (ctx, data->source);
+ _csi_slab_free (ctx, data, sizeof (*data));
+
+ cairo_script_interpreter_destroy (ctx);
+}
+
+static csi_status_t
+_ft_create_for_source (csi_t *ctx,
+ csi_string_t *source,
+ int index, int load_flags,
+ cairo_font_face_t **font_face_out)
+{
+ csi_blob_t tmpl;
+ struct _ft_face_data *data;
+ csi_list_t *link;
+ FT_Face face;
+ FT_Error err;
+ cairo_font_face_t *font_face;
+ csi_status_t status;
+
+ /* check for an existing FT_Face (kept alive by the font cache) */
+ /* XXX index/flags */
+ _csi_blob_init (&tmpl, (uint8_t *) source->string, source->len);
+ link = _csi_list_find (ctx->_faces, _csi_blob_equal, &tmpl);
+ if (link) {
+ if (--source->base.ref == 0)
+ csi_string_free (ctx, source);
+ data = csi_container_of (link, struct _ft_face_data, blob.list);
+ *font_face_out = cairo_font_face_reference (data->font_face);
+ return CSI_STATUS_SUCCESS;
+ }
+
+ /* no existing font_face, create new FT_Face */
+ if (_ft_lib == NULL) {
+ err = FT_Init_FreeType (&_ft_lib);
+ if (_csi_unlikely (err != FT_Err_Ok))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ }
+
+ err = FT_New_Memory_Face (_ft_lib,
+ (uint8_t *) source->string,
+ source->len, index,
+ &face);
+ if (_csi_unlikely (err != FT_Err_Ok)) {
+ if (err == FT_Err_Out_Of_Memory)
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ data = _csi_slab_alloc (ctx, sizeof (*data));
+ ctx->_faces = _csi_list_prepend (ctx->_faces, &data->blob.list);
+ data->ctx = cairo_script_interpreter_reference (ctx);
+ data->blob.hash = tmpl.hash;
+ data->blob.bytes = tmpl.bytes;
+ data->blob.len = tmpl.len;
+ data->face = face;
+ data->source = source;
+
+ font_face = cairo_ft_font_face_create_for_ft_face (face, load_flags);
+ status = cairo_font_face_set_user_data (font_face,
+ &_csi_blob_key,
+ data, _ft_done_face);
+ if (_csi_unlikely (status)) {
+ _ft_done_face (data);
+ cairo_font_face_destroy (font_face);
+ return status;
+ }
+
+ data->font_face = font_face;
+ *font_face_out = font_face;
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_ft_create_for_pattern (csi_t *ctx,
+ csi_string_t *string,
+ cairo_font_face_t **font_face_out)
+{
+ csi_blob_t tmpl;
+ struct _ft_face_data *data;
+ csi_list_t *link;
+ cairo_font_face_t *font_face;
+ FcPattern *pattern, *resolved;
+ FcResult result;
+ csi_status_t status;
+
+ _csi_blob_init (&tmpl, (uint8_t *) string->string, string->len);
+ link = _csi_list_find (ctx->_faces, _csi_blob_equal, &tmpl);
+ if (link) {
+ if (--string->base.ref == 0)
+ csi_string_free (ctx, string);
+ data = csi_container_of (link, struct _ft_face_data, blob.list);
+ *font_face_out = cairo_font_face_reference (data->font_face);
+ return CSI_STATUS_SUCCESS;
+ }
+
+ pattern = FcNameParse ((FcChar8 *) string->string);
+ if (_csi_unlikely (pattern == NULL))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+
+ FcConfigSubstitute (NULL, pattern, FcMatchPattern);
+ FcDefaultSubstitute (pattern);
+
+ resolved = FcFontMatch (NULL, pattern, &result);
+ if (_csi_unlikely (resolved == NULL)) {
+ FcPatternDestroy (pattern);
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ }
+
+ font_face = cairo_ft_font_face_create_for_pattern (resolved);
+
+ FcPatternDestroy (resolved);
+ FcPatternDestroy (pattern);
+
+ data = _csi_slab_alloc (ctx, sizeof (*data));
+ ctx->_faces = _csi_list_prepend (ctx->_faces, &data->blob.list);
+ data->ctx = cairo_script_interpreter_reference (ctx);
+ data->blob.hash = tmpl.hash;
+ data->blob.bytes = tmpl.bytes;
+ data->blob.len = tmpl.len;
+ data->face = NULL;
+ data->source = string;
+
+ status = cairo_font_face_set_user_data (font_face,
+ &_csi_blob_key,
+ data, _ft_done_face);
+ if (_csi_unlikely (status)) {
+ _ft_done_face (data);
+ cairo_font_face_destroy (font_face);
+ return status;
+ }
+
+ data->font_face = font_face;
+ *font_face_out = font_face;
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_ft_type42_create (csi_t *ctx,
+ csi_dictionary_t *font,
+ cairo_font_face_t **font_face_out)
+{
+ csi_object_t key;
+ csi_status_t status;
+
+ /* two basic sub-types, either an FcPattern or embedded font */
+ status = csi_name_new_static (ctx, &key, "pattern");
+ if (csi_dictionary_has (font, key.datum.name)) {
+ csi_object_t obj;
+
+ status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
+ if (_csi_unlikely (status))
+ return status;
+
+ switch ((int) csi_object_get_type (&obj)) {
+ case CSI_OBJECT_TYPE_FILE:
+ status = _csi_file_as_string (ctx, obj.datum.file, &obj);
+ if (_csi_unlikely (status))
+ return status;
+ break;
+ case CSI_OBJECT_TYPE_STRING:
+ obj.datum.object->ref++;
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ return _ft_create_for_pattern (ctx,
+ obj.datum.string,
+ font_face_out);
+ }
+
+ status = csi_name_new_static (ctx, &key, "source");
+ if (_csi_unlikely (status))
+ return status;
+
+ if (csi_dictionary_has (font, key.datum.name)) {
+ csi_object_t obj;
+ long index, flags;
+
+ index = 0;
+ status = _csi_dictionary_get_integer (ctx, font, "index", TRUE, &index);
+ if (_csi_unlikely (status))
+ return status;
+
+ flags = 0;
+ status = _csi_dictionary_get_integer (ctx, font, "flags", TRUE, &flags);
+ if (_csi_unlikely (status))
+ return status;
+
+ status = csi_name_new_static (ctx, &key, "source");
+ if (_csi_unlikely (status))
+ return status;
+ status = csi_dictionary_get (ctx, font, key.datum.name, &obj);
+ if (_csi_unlikely (status))
+ return status;
+ switch ((int) csi_object_get_type (&obj)) {
+ case CSI_OBJECT_TYPE_FILE:
+ status = _csi_file_as_string (ctx, obj.datum.file, &obj);
+ if (_csi_unlikely (status))
+ return status;
+ break;
+ case CSI_OBJECT_TYPE_STRING:
+ obj.datum.object->ref++;
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ return _ft_create_for_source (ctx, obj.datum.string,
+ index, flags,
+ font_face_out);
+ }
+
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+}
+#else
+#define _ft_type42_create(ctx, font, face_out) CSI_INT_STATUS_UNSUPPORTED
+#endif
+
+static csi_status_t
+_font_type42 (csi_t *ctx, csi_dictionary_t *font, cairo_font_face_t **font_face)
+{
+ csi_status_t status;
+
+ status = _ft_type42_create (ctx, font, font_face);
+ if (_csi_likely (status != CSI_INT_STATUS_UNSUPPORTED))
+ return status;
+
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+}
+
+static csi_status_t
+_font (csi_t *ctx)
+{
+ csi_dictionary_t *font;
+ csi_status_t status;
+ cairo_font_face_t *font_face;
+ csi_proxy_t *proxy;
+ csi_object_t obj;
+ long type;
+
+ check (1);
+
+ status = _csi_ostack_get_dictionary (ctx, 0, &font);
+ if (_csi_unlikely (status))
+ return status;
+
+ status = _csi_dictionary_get_integer (ctx, font, "type", FALSE, &type);
+ if (_csi_unlikely (status))
+ return status;
+
+ switch (type) {
+ case 3:
+ status = _font_type3 (ctx, font, &font_face);
+ break;
+ case 42:
+ status = _font_type42 (ctx, font, &font_face);
+ break;
+ default:
+ status = _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ break;
+ }
+
+ if (_csi_unlikely (status))
+ return status;
+
+ /* transfer ownership of dictionary to cairo_font_face_t */
+ proxy = _csi_proxy_create (ctx, font_face, font, NULL, NULL);
+ if (_csi_likely (proxy == NULL)) {
+ cairo_font_face_destroy (font_face);
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ }
+
+ status = cairo_font_face_set_user_data (font_face,
+ &_csi_proxy_key,
+ proxy, _csi_proxy_destroy);
+ if (_csi_unlikely (status)) {
+ _csi_proxy_destroy (proxy);
+ cairo_font_face_destroy (font_face);
+ return status;
+ }
+
+ obj.type = CSI_OBJECT_TYPE_FONT;
+ obj.datum.font_face = font_face;
+
+ pop (1);
+ status = push (&obj);
+ if (_csi_unlikely (status)) {
+ cairo_font_face_destroy (font_face);
+ return status;
+ }
+
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_for (csi_t *ctx)
+{
+ csi_array_t *proc;
+ csi_status_t status;
+ long i, inc, limit;
+
+ check (4);
+
+ status = _csi_ostack_get_procedure (ctx, 0, &proc);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_integer (ctx, 1, &limit);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_integer (ctx, 2, &inc);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_integer (ctx, 3, &i);
+ if (_csi_unlikely (status))
+ return status;
+
+ proc->base.ref++;
+ pop (4);
+
+ for (; i <= limit; i += inc) {
+ status = _csi_push_ostack_integer (ctx, i);
+ if (_csi_unlikely (status))
+ break;
+
+ status = _csi_array_execute (ctx, proc);
+ if (_csi_unlikely (status))
+ break;
+ }
+
+ if (--proc->base.ref == 0)
+ csi_array_free (ctx, proc);
+ return status;
+}
+
+static csi_status_t
+_ge (csi_t *ctx)
+{
+ csi_object_t *a, *b;
+ csi_boolean_t v;
+
+ check (2);
+
+ b = _csi_peek_ostack (ctx, 0);
+ a = _csi_peek_ostack (ctx, 1);
+
+ if (csi_object_get_type (a) != csi_object_get_type (b)) {
+ if (csi_object_is_number (a) && csi_object_is_number (b)) {
+ double ia, ib;
+ ia = csi_number_get_value (a);
+ ib = csi_number_get_value (b);
+ v = ia >= ib;
+ } else {
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+ } else switch ((int) csi_object_get_type (a)) {
+ case CSI_OBJECT_TYPE_BOOLEAN:
+ v = a->datum.boolean >= b->datum.boolean;
+ break;
+ case CSI_OBJECT_TYPE_INTEGER:
+ v = a->datum.integer >= b->datum.integer;
+ break;
+ case CSI_OBJECT_TYPE_REAL:
+ v = a->datum.real >= b->datum.real;
+ break;
+ case CSI_OBJECT_TYPE_STRING:
+ v = strcmp (a->datum.string->string, b->datum.string->string) >= 0;
+ break;
+ case CSI_OBJECT_TYPE_NAME:
+ v = strcmp ((char *) a->datum.name, (char *) b->datum.name) >= 0;
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ pop (2);
+ return _csi_push_ostack_boolean (ctx, v);
+}
+
+static csi_status_t
+_proxy_get (csi_proxy_t *proxy,
+ csi_name_t key)
+{
+ csi_object_t obj;
+ csi_status_t status;
+
+ if (_csi_unlikely (proxy == NULL || proxy->dictionary == NULL))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ status = csi_dictionary_get (proxy->ctx, proxy->dictionary, key, &obj);
+ if (_csi_unlikely (status))
+ return status;
+
+ return _csi_push_ostack_copy (proxy->ctx, &obj);
+}
+
+static csi_status_t
+_context_get (csi_t *ctx,
+ cairo_t *cr,
+ csi_name_t key)
+{
+ csi_status_t status;
+
+ if (strcmp ((char *) key, "current-point") == 0) {
+ double x, y;
+
+ cairo_get_current_point (cr, &x, &y);
+
+ status = _csi_push_ostack_real (ctx, x);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_push_ostack_real (ctx, y);
+ if (_csi_unlikely (status))
+ return status;
+
+ return CSI_STATUS_SUCCESS;
+ }
+
+ if (strcmp ((char *) key, "source") == 0) {
+ csi_object_t obj;
+
+ obj.type = CSI_OBJECT_TYPE_PATTERN;
+ obj.datum.pattern = cairo_pattern_reference (cairo_get_source (cr));
+ return push (&obj);
+ }
+
+ if (strcmp ((char *) key, "target") == 0) {
+ csi_object_t obj;
+
+ obj.type = CSI_OBJECT_TYPE_SURFACE;
+ obj.datum.surface = cairo_surface_reference (cairo_get_target (cr));
+ return push (&obj);
+ }
+
+ if (strcmp ((char *) key, "group-target") == 0) {
+ csi_object_t obj;
+
+ obj.type = CSI_OBJECT_TYPE_SURFACE;
+ obj.datum.surface = cairo_surface_reference (cairo_get_group_target (cr));
+ return push (&obj);
+ }
+
+ if (strcmp ((char *) key, "scaled-font") == 0) {
+ csi_object_t obj;
+
+ obj.type = CSI_OBJECT_TYPE_SCALED_FONT;
+ obj.datum.scaled_font = cairo_scaled_font_reference (cairo_get_scaled_font (cr));
+ return push (&obj);
+ }
+
+ if (strcmp ((char *) key, "font-face") == 0) {
+ csi_object_t obj;
+
+ obj.type = CSI_OBJECT_TYPE_FONT;
+ obj.datum.font_face = cairo_font_face_reference (cairo_get_font_face (cr));
+ return push (&obj);
+ }
+
+ return _proxy_get (cairo_get_user_data (cr, &_csi_proxy_key), key);
+}
+
+static csi_status_t
+_font_get (csi_t *ctx,
+ cairo_font_face_t *font_face,
+ csi_name_t key)
+{
+ return _proxy_get (cairo_font_face_get_user_data (font_face,
+ &_csi_proxy_key),
+ key);
+}
+
+static csi_status_t
+_pattern_get (csi_t *ctx,
+ cairo_pattern_t *pattern,
+ csi_name_t key)
+{
+ csi_status_t status;
+
+ if (strcmp ((char *) key, "type") == 0)
+ return _csi_push_ostack_integer (ctx, cairo_pattern_get_type (pattern));
+
+ if (strcmp ((char *) key, "filter") == 0)
+ return _csi_push_ostack_integer (ctx, cairo_pattern_get_filter (pattern));
+
+ if (strcmp ((char *) key, "extend") == 0)
+ return _csi_push_ostack_integer (ctx, cairo_pattern_get_extend (pattern));
+
+ if (strcmp ((char *) key, "matrix") == 0) {
+ csi_object_t obj;
+ cairo_matrix_t m;
+
+ cairo_pattern_get_matrix (pattern, &m);
+ status = csi_matrix_new_from_matrix (ctx, &obj, &m);
+ if (_csi_unlikely (status))
+ return status;
+
+ return push (&obj);
+ }
+
+ return _proxy_get (cairo_pattern_get_user_data (pattern, &_csi_proxy_key),
+ key);
+}
+
+static csi_status_t
+_scaled_font_get (csi_t *ctx,
+ cairo_scaled_font_t *font,
+ csi_name_t key)
+{
+ return _proxy_get (cairo_scaled_font_get_user_data (font, &_csi_proxy_key),
+ key);
+}
+
+static csi_status_t
+_surface_get (csi_t *ctx,
+ cairo_surface_t *surface,
+ csi_name_t key)
+{
+ if (strcmp ((char *) key, "type") == 0) {
+ return _csi_push_ostack_integer (ctx, cairo_surface_get_type (surface));
+ }
+
+ if (strcmp ((char *) key, "content") == 0) {
+ return _csi_push_ostack_integer (ctx,
+ cairo_surface_get_content (surface));
+ }
+
+ return _proxy_get (cairo_surface_get_user_data (surface, &_csi_proxy_key),
+ key);
+}
+
+static csi_status_t
+_get (csi_t *ctx)
+{
+ csi_object_t *key, *src, obj;
+ csi_status_t status;
+
+ check (2);
+
+ key = _csi_peek_ostack (ctx, 0);
+ src = _csi_peek_ostack (ctx, 1);
+ pop (1);
+ switch ((int) csi_object_get_type (src)) {
+ case CSI_OBJECT_TYPE_DICTIONARY:
+ if (_csi_unlikely (csi_object_get_type (key) !=
+ CSI_OBJECT_TYPE_NAME))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ status = csi_dictionary_get (ctx,
+ src->datum.dictionary,
+ key->datum.name,
+ &obj);
+ break;
+ case CSI_OBJECT_TYPE_ARRAY:
+ if (_csi_unlikely (csi_object_get_type (key) !=
+ CSI_OBJECT_TYPE_INTEGER))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ status = csi_array_get (ctx,
+ src->datum.array,
+ key->datum.integer,
+ &obj);
+ break;
+#if 0
+ case CSI_OBJECT_TYPE_STRING:
+ status = csi_string_get (src, key, &obj);
+ break;
+#endif
+
+ case CSI_OBJECT_TYPE_CONTEXT:
+ if (_csi_unlikely (csi_object_get_type (key) !=
+ CSI_OBJECT_TYPE_NAME))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ return _context_get (ctx, src->datum.cr, key->datum.name);
+
+ case CSI_OBJECT_TYPE_FONT:
+ if (_csi_unlikely (csi_object_get_type (key) !=
+ CSI_OBJECT_TYPE_NAME))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ return _font_get (ctx, src->datum.font_face, key->datum.name);
+
+ case CSI_OBJECT_TYPE_PATTERN:
+ if (_csi_unlikely (csi_object_get_type (key) !=
+ CSI_OBJECT_TYPE_NAME))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ return _pattern_get (ctx, src->datum.pattern, key->datum.name);
+
+ case CSI_OBJECT_TYPE_SCALED_FONT:
+ if (_csi_unlikely (csi_object_get_type (key) !=
+ CSI_OBJECT_TYPE_NAME))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ return _scaled_font_get (ctx, src->datum.scaled_font, key->datum.name);
+
+ case CSI_OBJECT_TYPE_SURFACE:
+ if (_csi_unlikely (csi_object_get_type (key) !=
+ CSI_OBJECT_TYPE_NAME))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ return _surface_get (ctx, src->datum.surface, key->datum.name);
+
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ if (_csi_unlikely (status))
+ return status;
+
+ return _csi_push_ostack_copy (ctx, &obj);
+}
+
+static csi_status_t
+_glyph_path (csi_t *ctx)
+{
+ csi_object_t *obj;
+ csi_array_t *array;
+ csi_array_t *glyph_array;
+ csi_string_t *glyph_string;
+ csi_status_t status;
+ cairo_t *cr;
+ cairo_scaled_font_t *scaled_font;
+ cairo_glyph_t stack_glyphs[256], *glyphs;
+ double x,y;
+ csi_integer_t nglyphs, i, j;
+ double glyph_advance[256][2];
+ int have_glyph_advance[256];
+
+ check (2);
+
+ status = _csi_ostack_get_array (ctx, 0, &array);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 1, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ /* count glyphs */
+ nglyphs = 0;
+ for (i = 0; i < array->stack.len; i++) {
+ obj = &array->stack.objects[i];
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_ARRAY:
+ nglyphs += obj->datum.array->stack.len;
+ break;
+ case CSI_OBJECT_TYPE_STRING:
+ nglyphs += obj->datum.string->len;
+ break;
+ }
+ }
+ if (nglyphs == 0) {
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+ }
+
+ if (nglyphs > ARRAY_LENGTH (stack_glyphs)) {
+ if (_csi_unlikely ((unsigned) nglyphs >= INT32_MAX / sizeof (cairo_glyph_t)))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs);
+ if (_csi_unlikely (glyphs == NULL))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ } else
+ glyphs = stack_glyphs;
+
+ scaled_font = cairo_get_scaled_font (cr);
+
+ nglyphs = 0;
+ memset (have_glyph_advance, 0, sizeof (have_glyph_advance));
+ x = y = 0;
+ for (i = 0; i < array->stack.len; i++) {
+ obj = &array->stack.objects[i];
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_ARRAY: /* glyphs */
+ glyph_array = obj->datum.array;
+ for (j = 0; j < glyph_array->stack.len; j++) {
+ unsigned long g;
+ cairo_bool_t have_advance;
+
+ obj = &glyph_array->stack.objects[j];
+ if (csi_object_get_type (obj) != CSI_OBJECT_TYPE_INTEGER)
+ break;
+ g = obj->datum.integer;
+
+ glyphs[nglyphs].index = g;
+ glyphs[nglyphs].x = x;
+ glyphs[nglyphs].y = y;
+
+ if (g < ARRAY_LENGTH (have_glyph_advance)) {
+ if (! have_glyph_advance[g]) {
+ cairo_text_extents_t extents;
+
+ cairo_scaled_font_glyph_extents (scaled_font,
+ &glyphs[nglyphs], 1,
+ &extents);
+
+ glyph_advance[g][0] = extents.x_advance;
+ glyph_advance[g][1] = extents.y_advance;
+ have_glyph_advance[g] = TRUE;
+
+ }
+
+ have_advance = glyph_advance[g][0] != 0.0;
+ x += glyph_advance[g][0];
+ y += glyph_advance[g][1];
+ } else {
+ cairo_text_extents_t extents;
+
+ cairo_scaled_font_glyph_extents (scaled_font,
+ &glyphs[nglyphs], 1,
+ &extents);
+
+ have_advance = extents.x_advance != 0.0;
+ x += extents.x_advance;
+ y += extents.y_advance;
+ }
+
+ nglyphs += have_advance;
+ }
+ break;
+
+ case CSI_OBJECT_TYPE_STRING: /* glyphs */
+ glyph_string = obj->datum.string;
+ for (j = 0; j < glyph_string->len; j++) {
+ uint8_t g;
+ cairo_bool_t have_advance;
+
+ g = glyph_string->string[j];
+ glyphs[nglyphs].index = g;
+ glyphs[nglyphs].x = x;
+ glyphs[nglyphs].y = y;
+
+ if (! have_glyph_advance[g]) {
+ cairo_text_extents_t extents;
+
+ cairo_scaled_font_glyph_extents (scaled_font,
+ &glyphs[nglyphs], 1,
+ &extents);
+
+ glyph_advance[g][0] = extents.x_advance;
+ glyph_advance[g][1] = extents.y_advance;
+ have_glyph_advance[g] = TRUE;
+ }
+
+ have_advance = glyph_advance[g][0] != 0.0;
+ x += glyph_advance[g][0];
+ y += glyph_advance[g][1];
+
+ nglyphs += have_advance;
+ }
+ break;
+
+ case CSI_OBJECT_TYPE_INTEGER:
+ case CSI_OBJECT_TYPE_REAL: /* dx */
+ x = csi_number_get_value (obj);
+ if (++i == array->stack.len)
+ break;
+ y = csi_number_get_value (&array->stack.objects[i]);
+ break;
+ }
+ }
+
+ cairo_glyph_path (cr, glyphs, nglyphs);
+
+ if (glyphs != stack_glyphs)
+ _csi_free (ctx, glyphs);
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_gray (csi_t *ctx)
+{
+ csi_object_t obj;
+ csi_status_t status;
+ double g;
+
+ check (1);
+
+ status = _csi_ostack_get_number (ctx, 0, &g);
+ if (_csi_unlikely (status))
+ return status;
+
+ pop (1);
+
+ obj.type = CSI_OBJECT_TYPE_PATTERN;
+ obj.datum.pattern = cairo_pattern_create_rgba (g, g, g, 1);
+ return push (&obj);
+}
+
+static csi_status_t
+_gt (csi_t *ctx)
+{
+ csi_object_t *a, *b;
+ csi_boolean_t v;
+
+ check (2);
+
+ b = _csi_peek_ostack (ctx, 0);
+ a = _csi_peek_ostack (ctx, 1);
+
+ if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b))) {
+ if (_csi_likely (csi_object_is_number (a) && csi_object_is_number (b))){
+ double ia, ib;
+ ia = csi_number_get_value (a);
+ ib = csi_number_get_value (b);
+ v = ia > ib;
+ } else {
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+ } else switch ((int) csi_object_get_type (a)) {
+ case CSI_OBJECT_TYPE_BOOLEAN:
+ v = a->datum.boolean > b->datum.boolean;
+ break;
+ case CSI_OBJECT_TYPE_INTEGER:
+ v = a->datum.integer > b->datum.integer;
+ break;
+ case CSI_OBJECT_TYPE_REAL:
+ v = a->datum.real > b->datum.real;
+ break;
+ case CSI_OBJECT_TYPE_STRING:
+ v = strcmp (a->datum.string->string, b->datum.string->string) > 0;
+ break;
+ case CSI_OBJECT_TYPE_NAME:
+ v = strcmp ((char *) a->datum.name, (char *) b->datum.name) > 0;
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ pop (2);
+ return _csi_push_ostack_boolean (ctx, v);
+}
+
+static csi_status_t
+_identity (csi_t *ctx)
+{
+ csi_object_t obj;
+ csi_status_t status;
+
+ status = csi_matrix_new (ctx, &obj);
+ if (_csi_unlikely (status))
+ return status;
+
+ return push (&obj);
+}
+
+static csi_status_t
+_if (csi_t *ctx)
+{
+ csi_array_t *proc;
+ csi_boolean_t predicate;
+ csi_status_t status;
+
+ check (2);
+
+ status = _csi_ostack_get_procedure (ctx, 0, &proc);
+ if (_csi_unlikely (status))
+ return status;
+
+ status = _csi_ostack_get_boolean (ctx, 1, &predicate);
+ if (_csi_unlikely (status))
+ return status;
+
+ proc->base.ref++;
+ pop (2);
+
+ if (predicate)
+ status = _csi_array_execute (ctx, proc);
+
+ if (--proc->base.ref == 0)
+ csi_array_free (ctx, proc);
+
+ return status;
+}
+
+static csi_status_t
+_ifelse (csi_t *ctx)
+{
+ csi_array_t *true_proc, *false_proc;
+ csi_boolean_t predicate;
+ csi_status_t status;
+
+ check (3);
+
+ status = _csi_ostack_get_procedure (ctx, 0, &false_proc);
+ if (_csi_unlikely (status))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ status = _csi_ostack_get_procedure (ctx, 1, &true_proc);
+ if (_csi_unlikely (status))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ status = _csi_ostack_get_boolean (ctx, 2, &predicate);
+ if (_csi_unlikely (status))
+ return status;
+
+ true_proc->base.ref++;
+ false_proc->base.ref++;
+ pop (3);
+
+ if (predicate)
+ status = _csi_array_execute (ctx, true_proc);
+ else
+ status = _csi_array_execute (ctx, false_proc);
+
+ if (--true_proc->base.ref == 0)
+ csi_array_free (ctx, true_proc);
+ if (--false_proc->base.ref == 0)
+ csi_array_free (ctx, false_proc);
+
+ return status;
+}
+
+static csi_status_t
+_image_read_raw (csi_file_t *src,
+ cairo_format_t format,
+ int width, int height,
+ cairo_surface_t **image_out)
+{
+ cairo_surface_t *image;
+ uint8_t *bp, *data;
+ int rem, len, ret, x, stride;
+ cairo_status_t status;
+
+ image = cairo_image_surface_create (format, width, height);
+ status = cairo_surface_status (image);
+ if (status)
+ return status;
+
+ switch (format) {
+ case CAIRO_FORMAT_A1:
+ len = (width+7)/8 * height;
+ break;
+ case CAIRO_FORMAT_A8:
+ len = width * height;
+ break;
+ case CAIRO_FORMAT_RGB24:
+ len = 3 * width * height;
+ break;
+ case CAIRO_FORMAT_ARGB32:
+ len = 4 * width * height;
+ break;
+ default:
+ break;
+ }
+
+ stride = cairo_image_surface_get_stride (image);
+ data = cairo_image_surface_get_data (image);
+ bp = data;
+ rem = len;
+ while (rem) {
+ ret = csi_file_read (src, bp, rem);
+ if (_csi_unlikely (ret == 0)) {
+ cairo_surface_destroy (image);
+ return _csi_error (CSI_STATUS_READ_ERROR);
+ }
+ rem -= ret;
+ bp += ret;
+ }
+
+ if (len != height * stride) {
+ while (--height) {
+ uint8_t *row = data + height * stride;
+
+ /* XXX pixel conversion */
+ switch (format) {
+ case CAIRO_FORMAT_A1:
+ for (x = (width+7)/8; x--; ) {
+ uint8_t byte = *--bp;
+ row[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
+ }
+ break;
+ case CAIRO_FORMAT_A8:
+ for (x = width; x--; )
+ row[x] = *--bp;
+ break;
+ case CAIRO_FORMAT_RGB24:
+ for (x = width; x--; ) {
+#ifdef WORDS_BIGENDIAN
+ row[4*x + 3] = *--bp;
+ row[4*x + 2] = *--bp;
+ row[4*x + 1] = *--bp;
+ row[4*x + 0] = 0;
+#else
+ row[4*x + 0] = *--bp;
+ row[4*x + 1] = *--bp;
+ row[4*x + 2] = *--bp;
+ row[4*x + 3] = 0;
+#endif
+ }
+ break;
+ case CAIRO_FORMAT_ARGB32:
+ /* stride == width */
+ break;
+ }
+ }
+
+ /* need to treat last row carefully */
+ switch (format) {
+ case CAIRO_FORMAT_A1:
+ for (x = (width+7)/8; x--; ) {
+ uint8_t byte = *--bp;
+ data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
+ }
+ break;
+ case CAIRO_FORMAT_A8:
+ for (x = width; x--; )
+ data[x] = *--bp;
+ break;
+ case CAIRO_FORMAT_RGB24:
+ for (x = width; --x>1; ) {
+#ifdef WORDS_BIGENDIAN
+ data[4*x + 3] = *--bp;
+ data[4*x + 2] = *--bp;
+ data[4*x + 1] = *--bp;
+ data[4*x + 0] = 0;
+#else
+ data[4*x + 0] = *--bp;
+ data[4*x + 1] = *--bp;
+ data[4*x + 2] = *--bp;
+ data[4*x + 3] = 0;
+#endif
+ }
+ if (width > 1) {
+ uint8_t rgb[2][3];
+ /* shuffle the last couple of overlapping pixels */
+ rgb[1][0] = data[5];
+ rgb[1][1] = data[4];
+ rgb[1][2] = data[3];
+ rgb[0][0] = data[2];
+ rgb[0][1] = data[1];
+ rgb[0][2] = data[0];
+#ifdef WORDS_BIGENDIAN
+ data[4] = 0;
+ data[5] = rgb[1][2];
+ data[6] = rgb[1][1];
+ data[7] = rgb[1][0];
+ data[0] = 0;
+ data[1] = rgb[0][2];
+ data[2] = rgb[0][1];
+ data[3] = rgb[0][0];
+#else
+ data[7] = 0;
+ data[6] = rgb[1][2];
+ data[5] = rgb[1][1];
+ data[4] = rgb[1][0];
+ data[3] = 0;
+ data[2] = rgb[0][2];
+ data[1] = rgb[0][1];
+ data[0] = rgb[0][0];
+#endif
+ } else {
+#ifdef WORDS_BIGENDIAN
+ data[0] = 0;
+ data[1] = data[0];
+ data[2] = data[1];
+ data[3] = data[2];
+#else
+ data[3] = data[0];
+ data[0] = data[2];
+ data[2] = data[3];
+ data[3] = 0;
+#endif
+ }
+ break;
+ case CAIRO_FORMAT_ARGB32:
+ /* stride == width */
+ break;
+ }
+ } else {
+#ifndef WORDS_BIGENDIAN
+ switch (format) {
+ case CAIRO_FORMAT_A1:
+ for (x = 0; x < len; x++) {
+ uint8_t byte = data[x];
+ data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
+ }
+ break;
+ case CAIRO_FORMAT_ARGB32:
+ {
+ uint32_t *rgba = (uint32_t *) data;
+ for (x = len/4; x--; rgba++) {
+ *rgba = bswap_32 (*rgba);
+ }
+ }
+ break;
+
+ case CAIRO_FORMAT_A8:
+ break;
+
+ case CAIRO_FORMAT_RGB24:
+ default:
+ break;
+ }
+#endif
+ }
+
+ *image_out = image;
+ return CSI_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+png_read_func (void *closure, uint8_t *data, unsigned int len)
+{
+ int ret;
+
+ ret = csi_file_read (closure, data, len);
+ if ((unsigned int) ret != len)
+ return CAIRO_STATUS_READ_ERROR;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_image_read_png (csi_file_t *src, cairo_surface_t **out)
+{
+ *out = cairo_image_surface_create_from_png_stream (png_read_func, src);
+ return cairo_surface_status (*out);
+}
+
+struct _image_tag {
+ csi_t *ctx;
+ csi_blob_t blob;
+ cairo_surface_t *surface;
+};
+
+static void
+_image_tag_done (void *closure)
+{
+ struct _image_tag *tag = closure;
+ csi_t *ctx = tag->ctx;
+
+ ctx->_images = _csi_list_unlink (ctx->_images, &tag->blob.list);
+ _csi_slab_free (ctx, tag, sizeof (*tag));
+ cairo_script_interpreter_destroy (ctx);
+}
+
+static cairo_surface_t *
+_image_cached (csi_t *ctx, cairo_surface_t *surface)
+{
+ csi_blob_t tmpl;
+ csi_list_t *link;
+ uint8_t *data;
+ int stride, height;
+ struct _image_tag *tag;
+
+ /* check for an existing image */
+
+ data = cairo_image_surface_get_data (surface);
+ stride = cairo_image_surface_get_stride (surface);
+ height = cairo_image_surface_get_height (surface);
+ _csi_blob_init (&tmpl, data, stride * height);
+ link = _csi_list_find (ctx->_images, _csi_blob_equal, &tmpl);
+ if (link) {
+ cairo_surface_destroy (surface);
+ tag = csi_container_of (link, struct _image_tag, blob.list);
+ return cairo_surface_reference (tag->surface);
+ }
+
+ /* none found, insert a tag for this one */
+
+ tag = _csi_slab_alloc (ctx, sizeof (struct _image_tag));
+ if (tag == NULL)
+ return surface;
+
+ ctx->_images = _csi_list_prepend (ctx->_images, &tag->blob.list);
+ tag->ctx = cairo_script_interpreter_reference (ctx);
+ tag->blob.hash = tmpl.hash;
+ tag->blob.bytes = tmpl.bytes;
+ tag->blob.len = tmpl.len;
+ tag->surface = surface;
+
+ if (cairo_surface_set_user_data (surface, &_csi_blob_key,
+ tag, _image_tag_done))
+ {
+ _image_tag_done (tag);
+ }
+
+ return surface;
+}
+
+static csi_status_t
+_image_load_from_dictionary (csi_t *ctx,
+ csi_dictionary_t *dict,
+ cairo_surface_t **image_out)
+{
+ csi_object_t obj, key;
+ long width;
+ long height;
+ long format;
+ cairo_surface_t *image;
+ csi_status_t status;
+
+ /* check for "status? */
+
+ status = _csi_dictionary_get_integer (ctx, dict, "width", FALSE, &width);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_dictionary_get_integer (ctx, dict, "height", FALSE, &height);
+ if (_csi_unlikely (status))
+ return status;
+
+ format = CAIRO_FORMAT_ARGB32;
+ status = _csi_dictionary_get_integer (ctx, dict, "format", TRUE, &format);
+ if (_csi_unlikely (status))
+ return status;
+
+ status = csi_name_new_static (ctx, &key, "source");
+ if (csi_dictionary_has (dict, key.datum.name)) {
+ enum mime_type type;
+ csi_object_t file;
+
+ status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
+ if (_csi_unlikely (status))
+ return status;
+
+ status = csi_name_new_static (ctx, &key, "mime-type");
+ if (_csi_unlikely (status))
+ return status;
+
+ type = MIME_TYPE_NONE;
+ if (csi_dictionary_has (dict, key.datum.name)) {
+ csi_object_t type_obj;
+ const char *type_str;
+
+ status = csi_dictionary_get (ctx, dict, key.datum.name, &type_obj);
+ if (_csi_unlikely (status))
+ return status;
+
+ switch ((int) csi_object_get_type (&type_obj)){
+ case CSI_OBJECT_TYPE_STRING:
+ type_str = type_obj.datum.string->string;
+ break;
+ case CSI_OBJECT_TYPE_NAME:
+ type_str = (char *) type_obj.datum.name;
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ if (strcmp (type_str, CAIRO_MIME_TYPE_PNG) == 0)
+ type = MIME_TYPE_PNG;
+ }
+
+ status = csi_object_as_file (ctx, &obj, &file);
+ if (_csi_unlikely (status))
+ return status;
+
+ /* XXX hook for general mime-type decoder */
+
+ switch (type) {
+ case MIME_TYPE_NONE:
+ status = _image_read_raw (file.datum.file,
+ format, width, height, &image);
+ break;
+ case MIME_TYPE_PNG:
+ status = _image_read_png (file.datum.file, &image);
+ break;
+ }
+ csi_object_free (ctx, &file);
+ if (_csi_unlikely (status))
+ return status;
+
+ image = _image_cached (ctx, image);
+ } else
+ image = cairo_image_surface_create (format, width, height);
+
+ *image_out = image;
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_image (csi_t *ctx)
+{
+ csi_dictionary_t *dict;
+ cairo_surface_t *image;
+ csi_status_t status;
+ csi_object_t obj;
+
+ check (1);
+
+ status = _csi_ostack_get_dictionary (ctx, 0, &dict);
+ if (_csi_unlikely (status))
+ return status;
+
+ status = _image_load_from_dictionary (ctx, dict, &image);
+ if (_csi_unlikely (status))
+ return status;
+
+ pop (1);
+ obj.type = CSI_OBJECT_TYPE_SURFACE;
+ obj.datum.surface = image;
+ return push (&obj);
+}
+
+static csi_status_t
+_index (csi_t *ctx)
+{
+ csi_status_t status;
+ long n;
+
+ check (1);
+
+ status = _csi_ostack_get_integer (ctx, 0, &n);
+ if (_csi_unlikely (status))
+ return status;
+
+ pop (1);
+
+ check (n);
+ return _csi_push_ostack_copy (ctx, _csi_peek_ostack (ctx, n));
+}
+
+static csi_status_t
+_le (csi_t *ctx)
+{
+ csi_object_t *a, *b;
+ csi_boolean_t v;
+
+ check (2);
+
+ b = _csi_peek_ostack (ctx, 0);
+ a = _csi_peek_ostack (ctx, 1);
+
+ if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b))) {
+ if (_csi_likely (csi_object_is_number (a) && csi_object_is_number (b))) {
+ double ia, ib;
+ ia = csi_number_get_value (a);
+ ib = csi_number_get_value (b);
+ v = ia <= ib;
+ } else {
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+ } else switch ((int) csi_object_get_type (a)) {
+ case CSI_OBJECT_TYPE_BOOLEAN:
+ v = a->datum.boolean <= b->datum.boolean;
+ break;
+ case CSI_OBJECT_TYPE_INTEGER:
+ v = a->datum.integer <= b->datum.integer;
+ break;
+ case CSI_OBJECT_TYPE_REAL:
+ v = a->datum.real <= b->datum.real;
+ break;
+ case CSI_OBJECT_TYPE_STRING:
+ v = strcmp (a->datum.string->string, b->datum.string->string) <= 0;
+ break;
+ case CSI_OBJECT_TYPE_NAME:
+ v = strcmp ((char *) a->datum.name, (char *) b->datum.name) <= 0;
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ pop (2);
+ return _csi_push_ostack_boolean (ctx, v);
+}
+
+static csi_status_t
+_linear (csi_t *ctx)
+{
+ csi_object_t obj;
+ csi_status_t status;
+ double x1, y1, x2, y2;
+
+ check (4);
+
+ status = _csi_ostack_get_number (ctx, 0, &y2);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 1, &x2);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 2, &y1);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 3, &x1);
+ if (_csi_unlikely (status))
+ return status;
+
+ pop (4);
+
+ obj.type = CSI_OBJECT_TYPE_PATTERN;
+ obj.datum.pattern = cairo_pattern_create_linear (x1, y1, x2, y2);
+ return push (&obj);
+}
+
+static csi_status_t
+_line_to (csi_t *ctx)
+{
+ csi_status_t status;
+ double x, y;
+ cairo_t *cr;
+
+ check (3);
+
+ status = _csi_ostack_get_number (ctx, 0, &y);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 1, &x);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 2, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ /* XXX path object */
+
+ pop (2);
+ cairo_line_to (cr, x, y);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_lt (csi_t *ctx)
+{
+ csi_object_t *a, *b;
+ csi_boolean_t v;
+
+ check (2);
+
+ b = _csi_peek_ostack (ctx, 0);
+ a = _csi_peek_ostack (ctx, 1);
+
+ if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b))) {
+ if (_csi_likely (csi_object_is_number (a) && csi_object_is_number (b))) {
+ double ia, ib;
+ ia = csi_number_get_value (a);
+ ib = csi_number_get_value (b);
+ v = ia < ib;
+ } else {
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+ } else switch ((int) csi_object_get_type (a)) {
+ case CSI_OBJECT_TYPE_BOOLEAN:
+ v = a->datum.boolean < b->datum.boolean;
+ break;
+ case CSI_OBJECT_TYPE_INTEGER:
+ v = a->datum.integer < b->datum.integer;
+ break;
+ case CSI_OBJECT_TYPE_REAL:
+ v = a->datum.real < b->datum.real;
+ break;
+ case CSI_OBJECT_TYPE_STRING:
+ v = strcmp (a->datum.string->string, b->datum.string->string) < 0;
+ break;
+ case CSI_OBJECT_TYPE_NAME:
+ v = strcmp ((char *) a->datum.name, (char *) b->datum.name) < 0;
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ pop (2);
+ return _csi_push_ostack_boolean (ctx, v);
+}
+
+static csi_status_t
+_mark (csi_t *ctx)
+{
+ return _csi_push_ostack_mark (ctx);
+}
+
+static csi_status_t
+_neg (csi_t *ctx)
+{
+ csi_object_t *obj;
+
+ check (1);
+
+ obj = _csi_peek_ostack (ctx, 0);
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_INTEGER:
+ obj->datum.integer = -obj->datum.integer;
+ break;
+ case CSI_OBJECT_TYPE_REAL:
+ obj->datum.real = -obj->datum.real;
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_not (csi_t *ctx)
+{
+ csi_object_t *obj;
+
+ check (1);
+
+ obj = _csi_peek_ostack (ctx, 0);
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_BOOLEAN:
+ obj->datum.boolean = ! obj->datum.boolean;
+ break;
+ case CSI_OBJECT_TYPE_INTEGER:
+ obj->type = CSI_OBJECT_TYPE_BOOLEAN;
+ obj->datum.boolean = ! obj->datum.integer;
+ break;
+ case CSI_OBJECT_TYPE_REAL:
+ obj->type = CSI_OBJECT_TYPE_BOOLEAN;
+ obj->datum.boolean = obj->datum.real == 0.0;
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_new_path (csi_t *ctx)
+{
+ /* XXX handle path object */
+ return _do_cairo_op (ctx, cairo_new_path);
+}
+
+static csi_status_t
+_new_sub_path (csi_t *ctx)
+{
+ /* XXX handle path object */
+ return _do_cairo_op (ctx, cairo_new_sub_path);
+}
+
+static csi_status_t
+_mask (csi_t *ctx)
+{
+ csi_status_t status;
+ cairo_t *cr;
+ cairo_pattern_t *pattern;
+
+ check (2);
+
+ status = _csi_ostack_get_pattern (ctx, 0, &pattern);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 1, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_mask (cr, pattern);
+ pop (1);
+
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_matrix (csi_t *ctx)
+{
+ csi_object_t *obj, matrix;
+ double v[6];
+ csi_status_t status;
+ int n;
+
+ check (1);
+
+ obj = _csi_peek_ostack (ctx, 0);
+ if (csi_object_is_number (obj)) {
+ check (6);
+
+ for (n = 6; n--; ) {
+ status = _csi_ostack_get_number (ctx, 5-n, &v[n]);
+ if (_csi_unlikely (status))
+ return status;
+ }
+ status = csi_matrix_new_from_values (ctx, &matrix, v);
+ if (_csi_unlikely (status))
+ return status;
+
+ pop (6);
+ } else {
+ csi_array_t *array;
+
+ status = _csi_ostack_get_array (ctx, 0, &array);
+ if (_csi_unlikely (status))
+ return status;
+
+ status = csi_matrix_new_from_array (ctx, &matrix, array);
+ if (_csi_unlikely (status))
+ return status;
+
+ pop (1);
+ }
+
+ return push (&matrix);
+}
+
+static csi_status_t
+_move_to (csi_t *ctx)
+{
+ csi_status_t status;
+ double x, y;
+ cairo_t *cr;
+
+ check (3);
+
+ status = _csi_ostack_get_number (ctx, 0, &y);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 1, &x);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 2, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ /* XXX path object */
+
+ pop (2);
+ cairo_move_to (cr, x, y);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_mul (csi_t *ctx)
+{
+ csi_object_t *A;
+ csi_object_t *B;
+ csi_object_type_t type_a, type_b;
+
+ check (2);
+
+ B = _csi_peek_ostack (ctx, 0);
+ A = _csi_peek_ostack (ctx, 1);
+
+ type_a = csi_object_get_type (A);
+ if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER ||
+ type_a == CSI_OBJECT_TYPE_REAL)))
+ {
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+ type_b = csi_object_get_type (B);
+ if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER ||
+ type_b == CSI_OBJECT_TYPE_REAL)))
+ {
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ pop (2);
+
+ if (type_a == CSI_OBJECT_TYPE_REAL &&
+ type_b == CSI_OBJECT_TYPE_REAL)
+ {
+ return _csi_push_ostack_real (ctx, A->datum.real * B->datum.real);
+
+ }
+ else if (type_a == CSI_OBJECT_TYPE_INTEGER &&
+ type_b == CSI_OBJECT_TYPE_INTEGER)
+ {
+ return _csi_push_ostack_integer (ctx,
+ A->datum.integer * B->datum.integer);
+ }
+ else
+ {
+ double v;
+
+ if (type_a == CSI_OBJECT_TYPE_REAL)
+ v = A->datum.real;
+ else
+ v = A->datum.integer;
+
+ if (type_b == CSI_OBJECT_TYPE_REAL)
+ v *= B->datum.real;
+ else
+ v *= B->datum.integer;
+
+ return _csi_push_ostack_real (ctx, v);
+ }
+}
+
+static csi_status_t
+_or (csi_t *ctx)
+{
+ csi_object_t *a, *b;
+
+ check (2);
+
+ a = _csi_peek_ostack (ctx, 0);
+ b = _csi_peek_ostack (ctx, 1);
+ if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b)))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ pop (2);
+ switch ((int) csi_object_get_type (a)) {
+ case CSI_OBJECT_TYPE_INTEGER:
+ return _csi_push_ostack_integer (ctx,
+ a->datum.integer | b->datum.integer);
+ case CSI_OBJECT_TYPE_BOOLEAN:
+ return _csi_push_ostack_boolean (ctx,
+ a->datum.boolean | b->datum.boolean);
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+}
+
+static csi_status_t
+_paint (csi_t *ctx)
+{
+ return _do_cairo_op (ctx, cairo_paint);
+}
+
+static csi_status_t
+_paint_with_alpha (csi_t *ctx)
+{
+ cairo_t *cr;
+ csi_status_t status;
+ double alpha;
+
+ check (2);
+
+ status = _csi_ostack_get_number (ctx, 0, &alpha);
+ if (_csi_unlikely (status))
+ return status;
+
+ status = _csi_ostack_get_context (ctx, 1, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_paint_with_alpha (cr, alpha);
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_pattern (csi_t *ctx)
+{
+ csi_object_t obj;
+ csi_status_t status;
+ cairo_surface_t *surface;
+
+ check (1);
+
+ status = _csi_ostack_get_surface (ctx, 0, &surface);
+ if (_csi_unlikely (status))
+ return status;
+
+ obj.type = CSI_OBJECT_TYPE_PATTERN;
+ obj.datum.pattern = cairo_pattern_create_for_surface (surface);
+
+ pop (1);
+ return push (&obj);
+}
+
+static csi_status_t
+_pop (csi_t *ctx)
+{
+ check (1);
+ pop (1);
+
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_pop_group (csi_t *ctx)
+{
+ csi_object_t obj;
+ csi_status_t status;
+ cairo_t *cr;
+
+ check (1);
+
+ status = _csi_ostack_get_context (ctx, 0, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ obj.type = CSI_OBJECT_TYPE_PATTERN;
+ obj.datum.pattern = cairo_pop_group (cr);
+
+ return push (&obj);
+}
+
+static csi_status_t
+_push_group (csi_t *ctx)
+{
+ csi_status_t status;
+ cairo_t *cr;
+ long content;
+
+ check (2);
+
+ status = _csi_ostack_get_integer (ctx, 0, &content);
+ if (_csi_unlikely (status))
+ return status;
+
+ status = _csi_ostack_get_context (ctx, 1, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_push_group_with_content (cr, content);
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_radial (csi_t *ctx)
+{
+ csi_object_t obj;
+ csi_status_t status;
+ double x1, y1, r1, x2, y2, r2;
+
+ check (6);
+
+ status = _csi_ostack_get_number (ctx, 0, &r2);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 1, &y2);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 2, &x2);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 3, &r1);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 4, &y1);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 5, &x1);
+ if (_csi_unlikely (status))
+ return status;
+
+ obj.type = CSI_OBJECT_TYPE_PATTERN;
+ obj.datum.pattern = cairo_pattern_create_radial (x1, y1, r1, x2, y2, r2);
+ pop (6);
+ return push (&obj);
+}
+
+static csi_status_t
+_rectangle (csi_t *ctx)
+{
+ csi_status_t status;
+ double x, y;
+ double w, h;
+ cairo_t *cr;
+
+ check (5);
+
+ status = _csi_ostack_get_number (ctx, 0, &h);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 1, &w);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 2, &y);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 3, &x);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 4, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ /* XXX path object */
+
+ cairo_rectangle (cr, x, y, w, h);
+ pop(4);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_rel_curve_to (csi_t *ctx)
+{
+ csi_status_t status;
+ double x1, y1;
+ double x2, y2;
+ double x3, y3;
+ cairo_t *cr;
+
+ check (7);
+
+ status = _csi_ostack_get_number (ctx, 0, &y3);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 1, &x3);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 2, &y2);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 3, &x2);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 4, &y1);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 5, &x1);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 6, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ /* XXX path object */
+
+ cairo_rel_curve_to (cr, x1, y1, x2, y2, x3, y3);
+ pop (6);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_rel_line_to (csi_t *ctx)
+{
+ csi_status_t status;
+ double x, y;
+ cairo_t *cr;
+
+ check (3);
+
+ status = _csi_ostack_get_number (ctx, 0, &y);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 1, &x);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 2, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ /* XXX path object */
+
+ cairo_rel_line_to (cr, x, y);
+ pop (2);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_rel_move_to (csi_t *ctx)
+{
+ csi_status_t status;
+ double x, y;
+ cairo_t *cr;
+
+ check (3);
+
+ status = _csi_ostack_get_number (ctx, 0, &y);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 1, &x);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 2, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ /* XXX path object */
+ cairo_rel_move_to (cr, x, y);
+ pop (2);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_reset_clip (csi_t *ctx)
+{
+ return _do_cairo_op (ctx, cairo_reset_clip);
+}
+
+static csi_status_t
+_restore (csi_t *ctx)
+{
+ return _do_cairo_op (ctx, cairo_restore);
+}
+
+static csi_status_t
+_rgb (csi_t *ctx)
+{
+ csi_object_t obj;
+ csi_status_t status;
+ double r,g,b;
+
+ check (3);
+
+ status = _csi_ostack_get_number (ctx, 0, &b);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 1, &g);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 2, &r);
+ if (_csi_unlikely (status))
+ return status;
+
+ obj.type = CSI_OBJECT_TYPE_PATTERN;
+ obj.datum.pattern = cairo_pattern_create_rgb (r, g, b);
+ pop (3);
+ return push (&obj);
+}
+
+static csi_status_t
+_rgba (csi_t *ctx)
+{
+ csi_object_t obj;
+ csi_status_t status;
+ double r,g,b,a;
+
+ check (4);
+
+ status = _csi_ostack_get_number (ctx, 0, &a);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 1, &b);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 2, &g);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 3, &r);
+ if (_csi_unlikely (status))
+ return status;
+
+ obj.type = CSI_OBJECT_TYPE_PATTERN;
+ obj.datum.pattern = cairo_pattern_create_rgba (r, g, b, a);
+ pop (4);
+ return push (&obj);
+}
+
+static csi_status_t
+_roll (csi_t *ctx)
+{
+ csi_status_t status;
+ long j, n;
+
+ check (2);
+
+ status = _csi_ostack_get_integer (ctx, 0, &j);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_integer (ctx, 1, &n);
+ if (_csi_unlikely (status))
+ return status;
+
+ pop (2);
+ check (n);
+ return _csi_stack_roll (ctx, &ctx->ostack, j, n);
+}
+
+static csi_status_t
+_rotate (csi_t *ctx)
+{
+ csi_object_t *obj;
+ csi_status_t status;
+ double theta;
+
+ check (2);
+
+ status = _csi_ostack_get_number (ctx, 0, &theta);
+ if (_csi_unlikely (status))
+ return status;
+
+ obj = _csi_peek_ostack (ctx, 1);
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_CONTEXT:
+ cairo_rotate (obj->datum.cr, theta);
+ break;
+
+ case CSI_OBJECT_TYPE_PATTERN:
+ {
+ cairo_matrix_t ctm;
+ cairo_pattern_get_matrix (obj->datum.pattern, &ctm);
+ cairo_matrix_rotate (&ctm, theta);
+ cairo_pattern_set_matrix (obj->datum.pattern, &ctm);
+ }
+ break;
+
+
+ case CSI_OBJECT_TYPE_MATRIX:
+ cairo_matrix_rotate (&obj->datum.matrix->matrix, theta);
+ break;
+
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_save (csi_t *ctx)
+{
+ return _do_cairo_op (ctx, cairo_save);
+}
+
+static csi_status_t
+_scale (csi_t *ctx)
+{
+ csi_object_t *obj;
+ csi_status_t status;
+ double x, y;
+
+ check (3);
+
+ status = _csi_ostack_get_number (ctx, 0, &y);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 1, &x);
+ if (_csi_unlikely (status))
+ return status;
+
+ obj = _csi_peek_ostack (ctx, 2);
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_CONTEXT:
+ cairo_scale (obj->datum.cr, x, y);
+ break;
+
+ case CSI_OBJECT_TYPE_PATTERN:
+ {
+ cairo_matrix_t ctm;
+ cairo_pattern_get_matrix (obj->datum.pattern, &ctm);
+ cairo_matrix_scale (&ctm, x, y);
+ cairo_pattern_set_matrix (obj->datum.pattern, &ctm);
+ }
+ break;
+
+
+ case CSI_OBJECT_TYPE_MATRIX:
+ cairo_matrix_scale (&obj->datum.matrix->matrix, x, y);
+ break;
+
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ pop (2);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_font_options_load_from_dictionary (csi_t *ctx,
+ csi_dictionary_t *dict,
+ cairo_font_options_t *options)
+{
+ const struct {
+ const char *key;
+ void (*setter) (cairo_font_options_t *, int val);
+ } properties[] = {
+ { "antialias",
+ (void (*)(cairo_font_options_t *, int val))
+ cairo_font_options_set_antialias },
+ { "subpixel-order",
+ (void (*)(cairo_font_options_t *, int val))
+ cairo_font_options_set_subpixel_order },
+ { "hint-style",
+ (void (*)(cairo_font_options_t *, int val))
+ cairo_font_options_set_hint_style },
+ { "hint-metrics",
+ (void (*)(cairo_font_options_t *, int val))
+ cairo_font_options_set_hint_metrics },
+ { NULL, NULL },
+ }, *prop = properties;
+
+ while (prop->key != NULL) {
+ csi_object_t key, value;
+ csi_status_t status;
+
+ status = csi_name_new_static (ctx, &key, prop->key);
+ if (_csi_unlikely (status))
+ return status;
+
+ if (csi_dictionary_has (dict, key.datum.name)) {
+ status = csi_dictionary_get (ctx, dict, key.datum.name, &value);
+ if (_csi_unlikely (status))
+ return status;
+
+ if (_csi_unlikely (csi_object_get_type (&value) !=
+ CSI_OBJECT_TYPE_INTEGER))
+ {
+ csi_object_free (ctx, &value);
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ prop->setter (options, value.datum.integer);
+ }
+
+ prop++;
+ }
+
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_scaled_font (csi_t *ctx)
+{
+ csi_object_t obj;
+ csi_dictionary_t *dict;
+ csi_status_t status;
+ cairo_font_face_t *font_face;
+ cairo_matrix_t font_matrix, ctm;
+ cairo_font_options_t *options;
+
+ check (4);
+
+ status = _csi_ostack_get_dictionary (ctx, 0, &dict);
+ if (_csi_unlikely (status))
+ return status;
+ options = cairo_font_options_create ();
+ status = _font_options_load_from_dictionary (ctx, dict, options);
+ if (_csi_unlikely (status)) {
+ cairo_font_options_destroy (options);
+ return status;
+ }
+
+ status = _csi_ostack_get_matrix (ctx, 1, &ctm);
+ if (_csi_unlikely (status)) {
+ cairo_font_options_destroy (options);
+ return status;
+ }
+
+ status = _csi_ostack_get_matrix (ctx, 2, &font_matrix);
+ if (_csi_unlikely (status)) {
+ cairo_font_options_destroy (options);
+ return status;
+ }
+
+ status = _csi_ostack_get_font_face (ctx, 3, &font_face);
+ if (_csi_unlikely (status)) {
+ cairo_font_options_destroy (options);
+ return status;
+ }
+
+ obj.type = CSI_OBJECT_TYPE_SCALED_FONT;
+ obj.datum.scaled_font = cairo_scaled_font_create (font_face,
+ &font_matrix,
+ &ctm,
+ options);
+ cairo_font_options_destroy (options);
+ pop (4);
+ return push (&obj);
+}
+
+static csi_status_t
+_select_font_face (csi_t *ctx)
+{
+ cairo_t *cr;
+ long weight;
+ long slant;
+ csi_string_t *family;
+ csi_status_t status;
+
+ check (4);
+
+ status = _csi_ostack_get_integer (ctx, 0, &weight);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_integer (ctx, 1, &slant);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_string (ctx, 2, &family);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 3, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_select_font_face (cr, family->string, slant, weight);
+ pop (3);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_context_set (csi_t *ctx,
+ cairo_t *cr,
+ csi_name_t key,
+ csi_object_t *obj)
+{
+ if (strcmp ((char *) key, "source") == 0) {
+ if (_csi_unlikely (csi_object_get_type (obj) !=
+ CSI_OBJECT_TYPE_PATTERN))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ cairo_set_source (cr, obj->datum.pattern);
+ return CSI_STATUS_SUCCESS;
+ }
+
+ if (strcmp ((char *) key, "scaled-font") == 0) {
+ if (_csi_unlikely (csi_object_get_type (obj) !=
+ CSI_OBJECT_TYPE_SCALED_FONT))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ cairo_set_scaled_font (cr, obj->datum.scaled_font);
+ return CSI_STATUS_SUCCESS;
+ }
+
+ if (strcmp ((char *) key, "font-face") == 0) {
+ if (_csi_unlikely (csi_object_get_type (obj) !=
+ CSI_OBJECT_TYPE_FONT))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ cairo_set_font_face (cr, obj->datum.font_face);
+ return CSI_STATUS_SUCCESS;
+ }
+
+ /* return _proxy_set()? */
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+}
+
+static csi_status_t
+_set (csi_t *ctx)
+{
+ csi_object_t *key, *value, *dst;
+ csi_status_t status;
+
+ check (3);
+
+ value = _csi_peek_ostack (ctx, 0);
+ key = _csi_peek_ostack (ctx, 1);
+ dst = _csi_peek_ostack (ctx, 2);
+
+ switch ((int) csi_object_get_type (dst)) {
+ case CSI_OBJECT_TYPE_DICTIONARY:
+ if (_csi_unlikely (csi_object_get_type (key) !=
+ CSI_OBJECT_TYPE_NAME))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ status = csi_dictionary_put (ctx,
+ dst->datum.dictionary,
+ key->datum.name,
+ value);
+ break;
+ case CSI_OBJECT_TYPE_ARRAY:
+ if (_csi_unlikely (csi_object_get_type (key) !=
+ CSI_OBJECT_TYPE_INTEGER))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ status = csi_array_put (ctx,
+ dst->datum.array,
+ key->datum.integer,
+ value);
+ break;
+
+ case CSI_OBJECT_TYPE_CONTEXT:
+ if (_csi_unlikely (csi_object_get_type (key) !=
+ CSI_OBJECT_TYPE_NAME))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ status = _context_set (ctx,
+ dst->datum.cr,
+ key->datum.name,
+ value);
+ break;
+
+ case CSI_OBJECT_TYPE_STRING:
+#if 0
+ status = csi_string_put (dst, key, value);
+ break;
+#endif
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ pop (2);
+ return status;
+}
+
+static csi_status_t
+_set_antialias (csi_t *ctx)
+{
+ csi_status_t status;
+ cairo_t *cr;
+ long antialias;
+
+ check (2);
+
+ status = _csi_ostack_get_integer (ctx, 0, &antialias);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 1, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_set_antialias (cr, antialias);
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_set_dash (csi_t *ctx)
+{
+ csi_array_t *array;
+ csi_status_t status;
+ cairo_t *cr;
+ double offset;
+
+ check (3);
+
+ status = _csi_ostack_get_number (ctx, 0, &offset);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_array (ctx, 1, &array);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 2, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ if (array->stack.len == 0) {
+ cairo_set_dash (cr, NULL, 0., 0.);
+ } else {
+ double stack_dashes[8];
+ double *dashes;
+ csi_integer_t n;
+
+ if (_csi_likely (array->stack.len < ARRAY_LENGTH (stack_dashes))) {
+ dashes = stack_dashes;
+ } else {
+ if (_csi_unlikely ((unsigned) array->stack.len >= INT32_MAX / sizeof (double)))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ dashes = _csi_alloc (ctx, sizeof (double) * array->stack.len);
+ if (_csi_unlikely (dashes == NULL))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ }
+
+ for (n = 0; n < array->stack.len; n++) {
+ if (_csi_unlikely (! csi_object_is_number
+ (&array->stack.objects[n])))
+ {
+ if (dashes != stack_dashes)
+ _csi_free (ctx, dashes);
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ dashes[n] = csi_number_get_value (&array->stack.objects[n]);
+ }
+
+ cairo_set_dash (cr, dashes, n, offset);
+
+ if (dashes != stack_dashes)
+ _csi_free (ctx, dashes);
+ }
+
+ pop (2);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_set_device_offset (csi_t *ctx)
+{
+ csi_status_t status;
+ cairo_surface_t *surface;
+ double x, y;
+
+ check (3);
+
+ status = _csi_ostack_get_number (ctx, 0, &y);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 1, &x);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_surface (ctx, 2, &surface);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_surface_set_device_offset (surface, x, y);
+ pop (2);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_set_extend (csi_t *ctx)
+{
+ csi_status_t status;
+ csi_object_t *obj;
+ long extend;
+
+ check (2);
+
+ status = _csi_ostack_get_integer (ctx, 0, &extend);
+ if (_csi_unlikely (status))
+ return status;
+
+ obj = _csi_peek_ostack (ctx, 1);
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_CONTEXT:
+ cairo_pattern_set_extend (cairo_get_source (obj->datum.cr),
+ extend);
+ break;
+ case CSI_OBJECT_TYPE_PATTERN:
+ cairo_pattern_set_extend (obj->datum.pattern, extend);
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_set_fallback_resolution (csi_t *ctx)
+{
+ csi_status_t status;
+ cairo_surface_t *surface;
+ double dpi_x, dpi_y;
+
+ check (3);
+
+ status = _csi_ostack_get_number (ctx, 0, &dpi_y);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 1, &dpi_x);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_surface (ctx, 2, &surface);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_surface_set_fallback_resolution (surface, dpi_x, dpi_y);
+ pop (2);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_set_fill_rule (csi_t *ctx)
+{
+ csi_status_t status;
+ cairo_t *cr;
+ long fill_rule;
+
+ check (2);
+
+ status = _csi_ostack_get_integer (ctx, 0, &fill_rule);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 1, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_set_fill_rule (cr, fill_rule);
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_set_filter (csi_t *ctx)
+{
+ csi_status_t status;
+ csi_object_t *obj;
+ long filter;
+
+ check (2);
+
+ status = _csi_ostack_get_integer (ctx, 0, &filter);
+ if (_csi_unlikely (status))
+ return status;
+
+ obj = _csi_peek_ostack (ctx, 1);
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_CONTEXT:
+ cairo_pattern_set_filter (cairo_get_source (obj->datum.cr),
+ filter);
+ break;
+ case CSI_OBJECT_TYPE_PATTERN:
+ cairo_pattern_set_filter (obj->datum.pattern, filter);
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_set_font_face (csi_t *ctx)
+{
+ csi_status_t status;
+ cairo_font_face_t *font;
+ cairo_t *cr;
+
+ check (2);
+
+ status = _csi_ostack_get_font_face (ctx, 0, &font);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 1, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_set_font_face (cr, font);
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_set_font_options (csi_t *ctx)
+{
+ csi_status_t status;
+ cairo_t *cr;
+ csi_dictionary_t *dict;
+ cairo_font_options_t *options;
+
+ check (2);
+
+ status = _csi_ostack_get_dictionary (ctx, 0, &dict);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 1, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ options = cairo_font_options_create ();
+ status = _font_options_load_from_dictionary (ctx, dict, options);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_set_font_options (cr, options);
+ cairo_font_options_destroy (options);
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_set_font_matrix (csi_t *ctx)
+{
+ csi_status_t status;
+ cairo_t *cr;
+ cairo_matrix_t m;
+
+ check (2);
+
+ status = _csi_ostack_get_matrix (ctx, 0, &m);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 1, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_set_font_matrix (cr, &m);
+ pop(1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_set_font_size (csi_t *ctx)
+{
+ csi_status_t status;
+ cairo_t *cr;
+ double size;
+
+ check (2);
+
+ status = _csi_ostack_get_number (ctx, 0, &size);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 1, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_set_font_size (cr, size);
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_set_line_cap (csi_t *ctx)
+{
+ csi_status_t status;
+ cairo_t *cr;
+ long line_cap;
+
+ check (2);
+
+ status = _csi_ostack_get_integer (ctx, 0, &line_cap);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 1, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_set_line_cap (cr, line_cap);
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_set_line_join (csi_t *ctx)
+{
+ csi_status_t status;
+ cairo_t *cr;
+ long line_join;
+
+ status = _csi_ostack_get_integer (ctx, 0, &line_join);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 1, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_set_line_join (cr, line_join);
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_set_line_width (csi_t *ctx)
+{
+ csi_status_t status;
+ cairo_t *cr;
+ double line_width;
+
+ check (2);
+
+ status = _csi_ostack_get_number (ctx, 0, &line_width);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 1, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_set_line_width (cr, line_width);
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_set_matrix (csi_t *ctx)
+{
+ csi_object_t *obj;
+ csi_status_t status;
+ cairo_matrix_t m;
+
+ check (2);
+
+ status = _csi_ostack_get_matrix (ctx, 0, &m);
+ if (_csi_unlikely (status))
+ return status;
+
+ obj = _csi_peek_ostack (ctx, 1);
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_CONTEXT:
+ cairo_set_matrix (obj->datum.cr, &m);
+ break;
+ case CSI_OBJECT_TYPE_PATTERN:
+ cairo_pattern_set_matrix (obj->datum.pattern, &m);
+ break;
+ case CSI_OBJECT_TYPE_MATRIX:
+ obj->datum.matrix->matrix = m;
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+struct _mime_tag {
+ csi_t *ctx;
+ csi_string_t *source;
+};
+static void
+_mime_tag_destroy (void *closure)
+{
+ struct _mime_tag *tag = closure;
+
+ if (--tag->source->base.ref)
+ csi_string_free (tag->ctx, tag->source);
+
+ _csi_slab_free (tag->ctx, tag, sizeof (struct _mime_tag));
+}
+
+static csi_status_t
+_set_mime_data (csi_t *ctx)
+{
+ csi_status_t status;
+ csi_object_t *obj;
+ const char *mime;
+ csi_object_t source;
+ cairo_surface_t *surface;
+ struct _mime_tag *tag;
+
+ check (3);
+
+ obj = _csi_peek_ostack (ctx, 0);
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_FILE:
+ status = _csi_file_as_string (ctx, obj->datum.file, &source);
+ if (_csi_unlikely (status))
+ return status;
+
+ break;
+
+ case CSI_OBJECT_TYPE_STRING:
+ source = *csi_object_reference (obj);
+ break;
+
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ status = _csi_ostack_get_string_constant (ctx, 1, &mime);
+ if (_csi_unlikely (status))
+ return status;
+
+ status = _csi_ostack_get_surface (ctx, 2, &surface);
+ if (_csi_unlikely (status))
+ return status;
+
+
+ /* XXX free source */
+ tag = _csi_slab_alloc (ctx, sizeof (struct _mime_tag));
+ if (_csi_unlikely (tag == NULL))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ tag->ctx = cairo_script_interpreter_reference (ctx);
+ tag->source = source.datum.string;
+ tag->source->base.ref++;
+
+ status = cairo_surface_set_mime_data (surface,
+ mime,
+ (uint8_t *)
+ source.datum.string->string,
+ source.datum.string->len,
+ _mime_tag_destroy, tag);
+ if (_csi_unlikely (status)) {
+ _mime_tag_destroy (tag);
+ return status;
+ }
+
+ pop (2);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_set_miter_limit (csi_t *ctx)
+{
+ csi_status_t status;
+ cairo_t *cr;
+ double miter_limit;
+
+ check (2);
+
+ status = _csi_ostack_get_number (ctx, 0, &miter_limit);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 1, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_set_miter_limit (cr, miter_limit);
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_set_operator (csi_t *ctx)
+{
+ cairo_t *cr;
+ long val;
+ csi_status_t status;
+
+ check (2);
+
+ status = _csi_ostack_get_integer (ctx, 0, &val);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 1, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_set_operator (cr, val);
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_set_scaled_font (csi_t *ctx)
+{
+ csi_status_t status;
+ cairo_scaled_font_t *font;
+ cairo_t *cr;
+
+ check (2);
+
+ status = _csi_ostack_get_scaled_font (ctx, 0, &font);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 1, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_set_scaled_font (cr, font);
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_set_source (csi_t *ctx)
+{
+ cairo_t *cr;
+ cairo_pattern_t *pattern;
+ csi_status_t status;
+
+ check (2);
+
+ status = _csi_ostack_get_pattern (ctx, 0, &pattern);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 1, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_set_source (cr, pattern);
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_set_source_image (csi_t *ctx)
+{
+ csi_status_t status;
+ cairo_surface_t *surface;
+ cairo_surface_t *source;
+ cairo_t *cr;
+
+ check (2);
+
+ status = _csi_ostack_get_surface (ctx, 0, &source);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_surface (ctx, 1, &surface);
+ if (_csi_unlikely (status))
+ return status;
+
+ cr = cairo_create (surface);
+ cairo_set_source_surface (cr, source, 0, 0);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_set_tolerance (csi_t *ctx)
+{
+ csi_status_t status;
+ cairo_t *cr;
+ double tolerance;
+
+ check (2);
+
+ status = _csi_ostack_get_number (ctx, 0, &tolerance);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 1, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_set_tolerance (cr, tolerance);
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_transform (csi_t *ctx)
+{
+ csi_object_t *obj;
+ csi_status_t status;
+ cairo_matrix_t m;
+
+ check (2);
+
+ status = _csi_ostack_get_matrix (ctx, 0, &m);
+ if (_csi_unlikely (status))
+ return status;
+
+ obj = _csi_peek_ostack (ctx, 1);
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_CONTEXT:
+ cairo_transform (obj->datum.cr, &m);
+ break;
+ case CSI_OBJECT_TYPE_PATTERN:
+ {
+ cairo_matrix_t ctm;
+ cairo_pattern_get_matrix (obj->datum.pattern, &ctm);
+ cairo_matrix_multiply (&ctm, &m, &ctm);
+ cairo_pattern_set_matrix (obj->datum.pattern, &ctm);
+ }
+ break;
+ case CSI_OBJECT_TYPE_MATRIX:
+ cairo_matrix_multiply (&obj->datum.matrix->matrix,
+ &m,
+ &obj->datum.matrix->matrix);
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_translate (csi_t *ctx)
+{
+ csi_object_t *obj;
+ csi_status_t status;
+ double x, y;
+
+ check (3);
+
+ status = _csi_ostack_get_number (ctx, 0, &y);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 1, &x);
+ if (_csi_unlikely (status))
+ return status;
+
+ obj = _csi_peek_ostack (ctx, 2);
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_CONTEXT:
+ cairo_translate (obj->datum.cr, x, y);
+ break;
+
+ case CSI_OBJECT_TYPE_PATTERN:
+ {
+ cairo_matrix_t ctm;
+ cairo_pattern_get_matrix (obj->datum.pattern, &ctm);
+ cairo_matrix_translate (&ctm, x, y);
+ cairo_pattern_set_matrix (obj->datum.pattern, &ctm);
+ }
+ break;
+
+
+ case CSI_OBJECT_TYPE_MATRIX:
+ cairo_matrix_translate (&obj->datum.matrix->matrix, x, y);
+ break;
+
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ pop (2);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_true (csi_t *ctx)
+{
+ return _csi_push_ostack_boolean (ctx, TRUE);
+}
+
+static csi_status_t
+_show_page (csi_t *ctx)
+{
+ csi_object_t *obj;
+
+ check (1);
+
+ obj = _csi_peek_ostack (ctx, 0);
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_CONTEXT:
+ cairo_show_page (obj->datum.cr);
+ if (ctx->hooks.copy_page != NULL)
+ ctx->hooks.copy_page (ctx->hooks.closure, obj->datum.cr);
+ break;
+ case CSI_OBJECT_TYPE_SURFACE:
+ cairo_surface_show_page (obj->datum.surface);
+ /* XXX hook? */
+ break;
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_similar (csi_t *ctx)
+{
+ csi_object_t obj;
+ long content;
+ double width, height;
+ cairo_surface_t *other;
+ csi_status_t status;
+
+ check (4);
+
+ status = _csi_ostack_get_integer (ctx, 0, &content);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 1, &height);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_number (ctx, 2, &width);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_surface (ctx, 3, &other);
+ if (_csi_unlikely (status))
+ return status;
+
+ /* silently fix-up a common bug when writing CS */
+ if ((content & CAIRO_CONTENT_COLOR_ALPHA) == 0) {
+ if (_csi_unlikely (content & ~CAIRO_CONTENT_COLOR_ALPHA))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ switch ((int) content) {
+ default:
+ case CAIRO_FORMAT_ARGB32:
+ content = CAIRO_CONTENT_COLOR_ALPHA;
+ break;
+ case CAIRO_FORMAT_RGB24:
+ content = CAIRO_CONTENT_COLOR;
+ break;
+ case CAIRO_FORMAT_A8:
+ case CAIRO_FORMAT_A1:
+ content = CAIRO_CONTENT_ALPHA;
+ break;
+ }
+ }
+
+ obj.type = CSI_OBJECT_TYPE_SURFACE;
+ obj.datum.surface = cairo_surface_create_similar (other,
+ content, width, height);
+ pop (4);
+ return push (&obj);
+}
+
+static csi_status_t
+_show_text (csi_t *ctx)
+{
+ csi_status_t status;
+ csi_string_t *text;
+ cairo_t *cr;
+
+ check (2);
+
+ status = _csi_ostack_get_string (ctx, 0, &text);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 1, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_show_text (cr, text->string);
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_show_glyphs (csi_t *ctx)
+{
+ csi_object_t *obj;
+ csi_array_t *array;
+ csi_array_t *glyph_array;
+ csi_string_t *glyph_string;
+ csi_status_t status;
+ cairo_t *cr;
+ cairo_scaled_font_t *scaled_font;
+ cairo_glyph_t stack_glyphs[256], *glyphs;
+ double x,y;
+ csi_integer_t nglyphs, i, j;
+ double glyph_advance[256][2];
+ int have_glyph_advance[256];
+
+ check (2);
+
+ status = _csi_ostack_get_array (ctx, 0, &array);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 1, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ /* count glyphs */
+ nglyphs = 0;
+ for (i = 0; i < array->stack.len; i++) {
+ obj = &array->stack.objects[i];
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_ARRAY:
+ nglyphs += obj->datum.array->stack.len;
+ break;
+ case CSI_OBJECT_TYPE_STRING:
+ nglyphs += obj->datum.string->len;
+ break;
+ }
+ }
+ if (nglyphs == 0) {
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+ }
+
+ if (nglyphs > ARRAY_LENGTH (stack_glyphs)) {
+ if (_csi_unlikely ((unsigned) nglyphs >= INT32_MAX / sizeof (cairo_glyph_t)))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs);
+ if (_csi_unlikely (glyphs == NULL))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ } else
+ glyphs = stack_glyphs;
+
+ scaled_font = cairo_get_scaled_font (cr);
+
+ nglyphs = 0;
+ memset (have_glyph_advance, 0, sizeof (have_glyph_advance));
+ x = y = 0;
+ for (i = 0; i < array->stack.len; i++) {
+ obj = &array->stack.objects[i];
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_ARRAY: /* glyphs */
+ glyph_array = obj->datum.array;
+ for (j = 0; j < glyph_array->stack.len; j++) {
+ unsigned long g;
+ cairo_bool_t have_advance;
+
+ obj = &glyph_array->stack.objects[j];
+ if (csi_object_get_type (obj) != CSI_OBJECT_TYPE_INTEGER)
+ break;
+ g = obj->datum.integer;
+
+ glyphs[nglyphs].index = g;
+ glyphs[nglyphs].x = x;
+ glyphs[nglyphs].y = y;
+
+ if (g < ARRAY_LENGTH (have_glyph_advance)) {
+ if (! have_glyph_advance[g]) {
+ cairo_text_extents_t extents;
+
+ cairo_scaled_font_glyph_extents (scaled_font,
+ &glyphs[nglyphs], 1,
+ &extents);
+
+ glyph_advance[g][0] = extents.x_advance;
+ glyph_advance[g][1] = extents.y_advance;
+ have_glyph_advance[g] = TRUE;
+
+ }
+
+ have_advance = glyph_advance[g][0] != 0.0;
+ x += glyph_advance[g][0];
+ y += glyph_advance[g][1];
+ } else {
+ cairo_text_extents_t extents;
+
+ cairo_scaled_font_glyph_extents (scaled_font,
+ &glyphs[nglyphs], 1,
+ &extents);
+
+ have_advance = extents.x_advance != 0.0;
+ x += extents.x_advance;
+ y += extents.y_advance;
+ }
+
+ nglyphs += have_advance;
+ }
+ break;
+
+ case CSI_OBJECT_TYPE_STRING: /* glyphs */
+ glyph_string = obj->datum.string;
+ for (j = 0; j < glyph_string->len; j++) {
+ uint8_t g;
+ cairo_bool_t have_advance;
+
+ g = glyph_string->string[j];
+ glyphs[nglyphs].index = g;
+ glyphs[nglyphs].x = x;
+ glyphs[nglyphs].y = y;
+
+ if (! have_glyph_advance[g]) {
+ cairo_text_extents_t extents;
+
+ cairo_scaled_font_glyph_extents (scaled_font,
+ &glyphs[nglyphs], 1,
+ &extents);
+
+ glyph_advance[g][0] = extents.x_advance;
+ glyph_advance[g][1] = extents.y_advance;
+ have_glyph_advance[g] = TRUE;
+ }
+
+ have_advance = glyph_advance[g][0] != 0.0;
+ x += glyph_advance[g][0];
+ y += glyph_advance[g][1];
+
+ nglyphs += have_advance;
+ }
+ break;
+
+ case CSI_OBJECT_TYPE_INTEGER:
+ case CSI_OBJECT_TYPE_REAL: /* dx */
+ x = csi_number_get_value (obj);
+ if (++i == array->stack.len)
+ break;
+ y = csi_number_get_value (&array->stack.objects[i]);
+ break;
+ }
+ }
+
+ cairo_show_glyphs (cr, glyphs, nglyphs);
+ cairo_move_to (cr, x, y);
+
+ if (glyphs != stack_glyphs)
+ _csi_free (ctx, glyphs);
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_show_text_glyphs (csi_t *ctx)
+{
+ csi_object_t *obj;
+ csi_array_t *array;
+ csi_string_t *string;
+ csi_string_t *utf8_string;
+ csi_string_t *glyph_string;
+ csi_array_t *glyph_array;
+ csi_status_t status;
+ cairo_t *cr;
+ cairo_scaled_font_t *scaled_font;
+ cairo_text_cluster_t stack_clusters[256], *clusters;
+ cairo_glyph_t stack_glyphs[256], *glyphs;
+ double x,y;
+ csi_integer_t nglyphs, nclusters, i, j;
+ double glyph_advance[256][2];
+ int have_glyph_advance[256];
+ long direction;
+
+ check (5);
+
+ status = _csi_ostack_get_integer (ctx, 0, &direction);
+ if (_csi_unlikely (status))
+ return status;
+
+ obj = _csi_peek_ostack (ctx, 1);
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_ARRAY:
+ array = obj->datum.array;
+ nclusters = array->stack.len / 2;
+ if (nclusters > ARRAY_LENGTH (stack_clusters)) {
+ if (_csi_unlikely ((unsigned) nclusters >= INT32_MAX / sizeof (cairo_text_cluster_t)))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ clusters = _csi_alloc (ctx, sizeof (cairo_text_cluster_t) * nclusters);
+ if (_csi_unlikely (clusters == NULL))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ } else
+ clusters = stack_clusters;
+
+ for (i = 0; i < nclusters; i++) {
+ clusters[i].num_bytes = csi_number_get_value (&array->stack.objects[2*i+0]);
+ clusters[i].num_glyphs = csi_number_get_value (&array->stack.objects[2*i+1]);
+ }
+ break;
+
+ case CSI_OBJECT_TYPE_STRING:
+ string = obj->datum.string;
+ nclusters = string->len / 2;
+ if (nclusters > ARRAY_LENGTH (stack_clusters)) {
+ if (_csi_unlikely ((unsigned) nclusters >= INT32_MAX / sizeof (cairo_text_cluster_t)))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ clusters = _csi_alloc (ctx, sizeof (cairo_text_cluster_t) * nclusters);
+ if (_csi_unlikely (clusters == NULL))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ } else
+ clusters = stack_clusters;
+
+ for (i = 0; i < nclusters; i++) {
+ clusters[i].num_bytes = string->string[2*i+0];
+ clusters[i].num_glyphs = string->string[2*i+1];
+ }
+ break;
+
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ status = _csi_ostack_get_array (ctx, 2, &array);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_string (ctx, 3, &utf8_string);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 4, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ /* count glyphs */
+ nglyphs = 0;
+ for (i = 0; i < array->stack.len; i++) {
+ obj = &array->stack.objects[i];
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_ARRAY:
+ nglyphs += obj->datum.array->stack.len;
+ break;
+ case CSI_OBJECT_TYPE_STRING:
+ nglyphs += obj->datum.string->len;
+ break;
+ }
+ }
+ if (nglyphs == 0)
+ return CSI_STATUS_SUCCESS;
+
+ if (nglyphs > ARRAY_LENGTH (stack_glyphs)) {
+ if (_csi_unlikely ((unsigned) nglyphs >= INT32_MAX / sizeof (cairo_glyph_t)))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs);
+ if (_csi_unlikely (glyphs == NULL)) {
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ }
+ } else
+ glyphs = stack_glyphs;
+
+ /* amalgamate glyph strings */
+ scaled_font = cairo_get_scaled_font (cr);
+
+ nglyphs = 0;
+ memset (have_glyph_advance, 0, sizeof (have_glyph_advance));
+ x = y = 0;
+ for (i = 0; i < array->stack.len; i++) {
+ obj = &array->stack.objects[i];
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_ARRAY: /* glyphs */
+ glyph_array = obj->datum.array;
+ for (j = 0; j < glyph_array->stack.len; j++) {
+ unsigned long g;
+ cairo_bool_t have_advance;
+
+ obj = &glyph_array->stack.objects[j];
+ if (csi_object_get_type (obj) != CSI_OBJECT_TYPE_INTEGER)
+ break;
+ g = obj->datum.integer;
+
+ glyphs[nglyphs].index = g;
+ glyphs[nglyphs].x = x;
+ glyphs[nglyphs].y = y;
+
+ if (g < ARRAY_LENGTH (have_glyph_advance)) {
+ if (! have_glyph_advance[g]) {
+ cairo_text_extents_t extents;
+
+ cairo_scaled_font_glyph_extents (scaled_font,
+ &glyphs[nglyphs], 1,
+ &extents);
+
+ glyph_advance[g][0] = extents.x_advance;
+ glyph_advance[g][1] = extents.y_advance;
+ have_glyph_advance[g] = TRUE;
+
+ }
+
+ have_advance = glyph_advance[g][0] != 0.0;
+ x += glyph_advance[g][0];
+ y += glyph_advance[g][1];
+ } else {
+ cairo_text_extents_t extents;
+
+ cairo_scaled_font_glyph_extents (scaled_font,
+ &glyphs[nglyphs], 1,
+ &extents);
+
+ have_advance = extents.x_advance != 0.0;
+ x += extents.x_advance;
+ y += extents.y_advance;
+ }
+
+ nglyphs += have_advance;
+ }
+ break;
+
+ case CSI_OBJECT_TYPE_STRING: /* glyphs */
+ glyph_string = obj->datum.string;
+ for (j = 0; j < glyph_string->len; j++) {
+ uint8_t g;
+ cairo_bool_t have_advance;
+
+ g = glyph_string->string[j];
+ glyphs[nglyphs].index = g;
+ glyphs[nglyphs].x = x;
+ glyphs[nglyphs].y = y;
+
+ if (! have_glyph_advance[g]) {
+ cairo_text_extents_t extents;
+
+ cairo_scaled_font_glyph_extents (scaled_font,
+ &glyphs[nglyphs], 1,
+ &extents);
+
+ glyph_advance[g][0] = extents.x_advance;
+ glyph_advance[g][1] = extents.y_advance;
+ have_glyph_advance[g] = TRUE;
+ }
+
+ have_advance = glyph_advance[g][0] != 0.0;
+ x += glyph_advance[g][0];
+ y += glyph_advance[g][1];
+
+ nglyphs += have_advance;
+ }
+ break;
+
+ case CSI_OBJECT_TYPE_INTEGER:
+ case CSI_OBJECT_TYPE_REAL: /* dx */
+ x = csi_number_get_value (obj);
+ if (++i == array->stack.len)
+ break;
+ y = csi_number_get_value (&array->stack.objects[i]);
+ break;
+ }
+ }
+
+ cairo_show_text_glyphs (cr,
+ utf8_string->string, utf8_string->len,
+ glyphs, nglyphs,
+ clusters, nclusters,
+ direction);
+ cairo_move_to (cr, x, y);
+
+ if (clusters != stack_clusters)
+ _csi_free (ctx, clusters);
+ if (glyphs != stack_glyphs)
+ _csi_free (ctx, glyphs);
+
+ pop (4);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_stroke (csi_t *ctx)
+{
+ return _do_cairo_op (ctx, cairo_stroke);
+}
+
+static csi_status_t
+_stroke_preserve (csi_t *ctx)
+{
+ return _do_cairo_op (ctx, cairo_stroke_preserve);
+}
+
+static csi_status_t
+_sub (csi_t *ctx)
+{
+ csi_object_t *A;
+ csi_object_t *B;
+ csi_object_type_t type_a, type_b;
+
+ check (2);
+
+ B = _csi_peek_ostack (ctx, 0);
+ A = _csi_peek_ostack (ctx, 1);
+
+ type_a = csi_object_get_type (A);
+ if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER ||
+ type_a == CSI_OBJECT_TYPE_REAL)))
+ {
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ type_b = csi_object_get_type (B);
+ if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER ||
+ type_b == CSI_OBJECT_TYPE_REAL)))
+ {
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ pop (2);
+
+ if (type_a == CSI_OBJECT_TYPE_REAL &&
+ type_b == CSI_OBJECT_TYPE_REAL)
+ {
+ return _csi_push_ostack_real (ctx, A->datum.real - B->datum.real);
+
+ }
+ else if (type_a == CSI_OBJECT_TYPE_INTEGER &&
+ type_b == CSI_OBJECT_TYPE_INTEGER)
+ {
+ return _csi_push_ostack_integer (ctx,
+ A->datum.integer - B->datum.integer);
+ }
+ else
+ {
+ double v;
+
+ if (type_a == CSI_OBJECT_TYPE_REAL)
+ v = A->datum.real;
+ else
+ v = A->datum.integer;
+
+ if (type_b == CSI_OBJECT_TYPE_REAL)
+ v -= B->datum.real;
+ else
+ v -= B->datum.integer;
+
+ return _csi_push_ostack_real (ctx, v);
+ }
+}
+
+static csi_status_t
+_surface (csi_t *ctx)
+{
+ csi_object_t obj;
+ csi_dictionary_t *dict;
+ csi_proxy_t *proxy;
+ csi_object_t key;
+ double width, height;
+ csi_surface_create_func_t hook;
+ cairo_surface_t *surface;
+ csi_status_t status;
+
+ check (1);
+
+ status = _csi_ostack_get_dictionary (ctx, 0, &dict);
+ if (_csi_unlikely (status))
+ return status;
+
+ status = _csi_dictionary_get_number (ctx, dict, "width", FALSE, &width);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_dictionary_get_number (ctx, dict, "height", FALSE, &height);
+ if (_csi_unlikely (status))
+ return status;
+
+ hook = ctx->hooks.surface_create;
+ assert (hook != NULL);
+
+ surface = hook (ctx->hooks.closure, width, height);
+ if (_csi_unlikely (surface == NULL)) {
+ return _csi_error (CSI_STATUS_NULL_POINTER);
+ }
+
+ proxy = _csi_proxy_create (ctx, surface, dict,
+ ctx->hooks.surface_destroy,
+ ctx->hooks.closure);
+ if (_csi_unlikely (proxy == NULL)) {
+ cairo_surface_destroy (surface);
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ }
+
+ status = cairo_surface_set_user_data (surface,
+ &_csi_proxy_key,
+ proxy, _csi_proxy_destroy);
+ if (_csi_unlikely (status)) {
+ _csi_proxy_destroy (proxy);
+ cairo_surface_destroy (surface);
+ return status;
+ }
+
+ status = csi_name_new_static (ctx, &key, "fallback-resolution");
+ if (_csi_unlikely (status)) {
+ cairo_surface_destroy (surface);
+ return status;
+ }
+ if (csi_dictionary_has (dict, key.datum.name)) {
+ status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
+ if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_ARRAY) {
+ csi_array_t *array = obj.datum.array;
+ if (array->stack.len == 2) {
+ cairo_surface_set_fallback_resolution (surface,
+ csi_number_get_value
+ (&array->stack.objects[0]),
+ csi_number_get_value
+ (&array->stack.objects[1]));
+ }
+ }
+ }
+ /* initialise surface to source */
+ status = csi_name_new_static (ctx, &key, "source");
+ if (_csi_unlikely (status)) {
+ cairo_surface_destroy (surface);
+ return status;
+ }
+ if (csi_dictionary_has (dict, key.datum.name)) {
+ cairo_surface_t *image;
+ cairo_t *cr;
+
+ status = _image_load_from_dictionary (ctx, dict, &image);
+ if (_csi_unlikely (status)) {
+ cairo_surface_destroy (surface);
+ return status;
+ }
+
+ cr = cairo_create (surface);
+ cairo_set_source_surface (cr, image, 0, 0);
+ cairo_surface_destroy (image);
+ cairo_paint (cr);
+ status = cairo_status (cr);
+ cairo_destroy (cr);
+
+ if (_csi_unlikely (status))
+ return status;
+ }
+
+ status = csi_name_new_static (ctx, &key, "device-offset");
+ if (_csi_unlikely (status)) {
+ cairo_surface_destroy (surface);
+ return status;
+ }
+ if (csi_dictionary_has (dict, key.datum.name)) {
+ status = csi_dictionary_get (ctx, dict, key.datum.name, &obj);
+ if (_csi_unlikely (status))
+ return status;
+
+ if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_ARRAY) {
+ csi_array_t *array = obj.datum.array;
+
+ if (array->stack.len == 2) {
+ cairo_surface_set_device_offset (surface,
+ csi_number_get_value
+ (&array->stack.objects[0]),
+ csi_number_get_value
+ (&array->stack.objects[1]));
+ }
+ }
+ }
+
+ obj.type = CSI_OBJECT_TYPE_SURFACE;
+ obj.datum.surface = surface;
+ pop (1);
+ return push (&obj);
+}
+
+static csi_status_t
+_text_path (csi_t *ctx)
+{
+ csi_status_t status;
+ csi_string_t *text;
+ cairo_t *cr;
+
+ check (2);
+
+ status = _csi_ostack_get_string (ctx, 0, &text);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_context (ctx, 1, &cr);
+ if (_csi_unlikely (status))
+ return status;
+
+ cairo_text_path (cr, text->string);
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_undef (csi_t *ctx)
+{
+ csi_name_t name;
+ csi_status_t status;
+
+ check (1);
+
+ status = _csi_ostack_get_name (ctx, 0, &name);
+ if (_csi_unlikely (status))
+ return status;
+
+ status = _csi_name_undefine (ctx, name);
+ if (_csi_unlikely (status))
+ return status;
+
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_unset (csi_t *ctx)
+{
+ csi_object_t *dst;
+ csi_name_t name;
+ csi_status_t status;
+
+ check (2);
+
+ status = _csi_ostack_get_name (ctx, 0, &name);
+ if (_csi_unlikely (status))
+ return status;
+
+ dst = _csi_peek_ostack (ctx, 1);
+ switch ((int) csi_object_get_type (dst)) {
+ case CSI_OBJECT_TYPE_DICTIONARY:
+ csi_dictionary_remove (ctx, dst->datum.dictionary, name);
+ break;
+ case CSI_OBJECT_TYPE_STRING:
+ case CSI_OBJECT_TYPE_ARRAY:
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_write_to_png (csi_t *ctx)
+{
+ csi_status_t status;
+ csi_string_t *filename;
+ cairo_surface_t *surface;
+
+ check (2);
+
+ status = _csi_ostack_get_string (ctx, 0, &filename);
+ if (_csi_unlikely (status))
+ return status;
+ status = _csi_ostack_get_surface (ctx, 1, &surface);
+ if (_csi_unlikely (status))
+ return status;
+
+ status = cairo_surface_write_to_png (surface, filename->string);
+ if (_csi_unlikely (status))
+ return status;
+
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_xor (csi_t *ctx)
+{
+ csi_object_t *a, *b;
+
+ check (2);
+
+ a = _csi_peek_ostack (ctx, 0);
+ b = _csi_peek_ostack (ctx, 1);
+ if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b)))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ pop (2);
+ switch ((int) csi_object_get_type (a)) {
+ case CSI_OBJECT_TYPE_INTEGER:
+ return _csi_push_ostack_integer (ctx,
+ a->datum.integer ^ b->datum.integer);
+ case CSI_OBJECT_TYPE_BOOLEAN:
+ return _csi_push_ostack_boolean (ctx,
+ a->datum.boolean ^ b->datum.boolean);
+ default:
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ }
+}
+
+static csi_status_t
+_debug_print (csi_t *ctx)
+{
+ csi_object_t *obj;
+
+ check (1);
+ obj = _csi_peek_ostack (ctx, 0);
+ switch (csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_NULL:
+ fprintf (stderr, "NULL\n");
+ break;
+
+ /* atomics */
+ case CSI_OBJECT_TYPE_BOOLEAN:
+ fprintf (stderr, "boolean: %s\n",
+ obj->datum.boolean ? "true" : "false");
+ break;
+ case CSI_OBJECT_TYPE_INTEGER:
+ fprintf (stderr, "integer: %ld\n", obj->datum.integer);
+ break;
+ case CSI_OBJECT_TYPE_MARK:
+ fprintf (stderr, "mark\n");
+ break;
+ case CSI_OBJECT_TYPE_NAME:
+ fprintf (stderr, "name: %s\n", (char *) obj->datum.name);
+ break;
+ case CSI_OBJECT_TYPE_OPERATOR:
+ fprintf (stderr, "operator: %p\n", obj->datum.op);
+ break;
+ case CSI_OBJECT_TYPE_REAL:
+ fprintf (stderr, "real: %g\n", obj->datum.real);
+ break;
+
+ /* compound */
+ case CSI_OBJECT_TYPE_ARRAY:
+ fprintf (stderr, "array\n");
+ break;
+ case CSI_OBJECT_TYPE_DICTIONARY:
+ fprintf (stderr, "dictionary\n");
+ break;
+ case CSI_OBJECT_TYPE_FILE:
+ fprintf (stderr, "file\n");
+ break;
+ case CSI_OBJECT_TYPE_MATRIX:
+ fprintf (stderr, "matrix: [%g %g %g %g %g %g]\n",
+ obj->datum.matrix->matrix.xx,
+ obj->datum.matrix->matrix.yx,
+ obj->datum.matrix->matrix.xy,
+ obj->datum.matrix->matrix.yy,
+ obj->datum.matrix->matrix.x0,
+ obj->datum.matrix->matrix.y0);
+ break;
+ case CSI_OBJECT_TYPE_STRING:
+ fprintf (stderr, "string: %s\n", obj->datum.string->string);
+ break;
+
+ /* cairo */
+ case CSI_OBJECT_TYPE_CONTEXT:
+ fprintf (stderr, "context\n");
+ break;
+ case CSI_OBJECT_TYPE_FONT:
+ fprintf (stderr, "font\n");
+ break;
+ case CSI_OBJECT_TYPE_PATTERN:
+ fprintf (stderr, "pattern\n");
+ break;
+ case CSI_OBJECT_TYPE_SCALED_FONT:
+ fprintf (stderr, "scaled_font\n");
+ break;
+ case CSI_OBJECT_TYPE_SURFACE:
+ fprintf (stderr, "surface\n");
+ break;
+ }
+ pop (1);
+ return CSI_STATUS_SUCCESS;
+}
+
+static const csi_operator_def_t
+_defs[] = {
+ { "<<", _mark },
+ { ">>", end_dict_construction },
+ { "[", _mark },
+ { "]", end_array_construction },
+ { "a", _alpha },
+ { "abs", NULL },
+ { "add", _add },
+ { "add_color_stop", _add_color_stop },
+ { "and", _and },
+ { "arc", _arc },
+ { "arc_negative", _arc_negative },
+ { "arc-", _arc_negative },
+ //{ "arc_to", NULL },
+ { "array", _array },
+ { "astore", NULL },
+ { "atan", NULL },
+ { "bind", _bind },
+ { "bitshift", _bitshift },
+ { "c", _curve_to },
+ { "C", _rel_curve_to },
+ { "ceiling", NULL },
+ { "clear", NULL },
+ { "clear_to_mark", NULL },
+ { "clip", _clip },
+ { "clip_extents", NULL },
+ { "clip_preserve", _clip_preserve },
+ { "clip+", _clip_preserve },
+ { "close_path", _close_path },
+ { "context", _context },
+ { "copy", _copy },
+ { "copy_page", _copy_page },
+ { "cos", NULL },
+ { "count", NULL },
+ { "count_to_mark", NULL },
+ { "curve_to", _curve_to },
+ { "def", _def },
+ { "device_to_user", NULL },
+ { "device_to_user_distance", NULL },
+ { "dict", _dict },
+ { "div", _div },
+ { "dup", _dup },
+ { "eq", _eq },
+ { "exch", _exch },
+ { "exec", NULL },
+ { "exp", NULL },
+ { "false", _false },
+ { "fill", _fill },
+ { "fill_extents", NULL },
+ { "fill_preserve", _fill_preserve },
+ { "fill+", _fill_preserve },
+ { "filter", _filter },
+ { "floor", NULL },
+ { "font", _font },
+ { "for", _for },
+ { "forall", NULL },
+ { "g", _gray },
+ { "ge", _ge },
+ { "get", _get },
+ { "glyph_path", _glyph_path },
+ { "gt", _gt },
+ { "h", _close_path },
+ { "identity", _identity },
+ { "if", _if },
+ { "ifelse", _ifelse },
+ { "image", _image },
+ { "index", _index },
+ { "invert", NULL },
+ { "in_stroke", NULL },
+ { "in_fill", NULL },
+ { "known", NULL },
+ { "l", _line_to },
+ { "L", _rel_line_to },
+ { "languagelevel", NULL },
+ { "le", _le },
+ { "length", NULL },
+ { "linear", _linear },
+ { "line_to", _line_to },
+ { "ln", NULL },
+ { "load", NULL },
+ { "log", NULL },
+ { "loop", NULL },
+ { "lt", _lt },
+ { "m", _move_to },
+ { "M", _rel_move_to },
+ { "mark", _mark },
+ { "mask", _mask },
+ { "matrix", _matrix },
+ { "mod", NULL },
+ { "move_to", _move_to },
+ { "mul", _mul },
+ { "multiply", NULL },
+ { "n", _new_path },
+ { "N", _new_sub_path },
+ { "ne", NULL },
+ { "neg", _neg },
+ { "new_path", _new_path },
+ { "new_sub_path", _new_sub_path },
+ { "not", _not },
+ { "null", NULL },
+ { "or", _or },
+ { "paint", _paint },
+ { "paint_with_alpha", _paint_with_alpha },
+ { "pattern", _pattern },
+ { "pop", _pop },
+ { "pop_group", _pop_group },
+ { "push_group", _push_group },
+ { "radial", _radial },
+ { "rand", NULL },
+ { "rectangle", _rectangle },
+ { "repeat", NULL },
+ { "restore", _restore },
+ { "rel_curve_to", _rel_curve_to },
+ { "rel_line_to", _rel_line_to },
+ { "rel_move_to", _rel_move_to },
+ { "reset_clip", _reset_clip },
+ { "rgb", _rgb },
+ { "rgba", _rgba },
+ { "roll", _roll },
+ { "rotate", _rotate },
+ { "round", NULL },
+ { "run", NULL },
+ { "save", _save },
+ { "scale", _scale },
+ { "scaled_font", _scaled_font },
+ { "select_font_face", _select_font_face },
+ { "set", _set },
+ { "set_antialias", _set_antialias },
+ { "set_dash", _set_dash },
+ { "set_device_offset", _set_device_offset },
+ { "set_extend", _set_extend },
+ { "set_fallback_resolution", _set_fallback_resolution },
+ { "set_fill_rule", _set_fill_rule },
+ { "set_filter", _set_filter },
+ { "set_font_face", _set_font_face },
+ { "set_font_options", _set_font_options },
+ { "set_font_matrix", _set_font_matrix },
+ { "set_font_size", _set_font_size },
+ { "set_line_cap", _set_line_cap },
+ { "set_line_join", _set_line_join },
+ { "set_line_width", _set_line_width },
+ { "set_matrix", _set_matrix },
+ { "set_miter_limit", _set_miter_limit },
+ { "set_mime_data", _set_mime_data },
+ { "set_operator", _set_operator },
+ { "set_scaled_font", _set_scaled_font },
+ { "set_source", _set_source },
+ { "set_source_image", _set_source_image },
+ { "set_tolerance", _set_tolerance },
+ { "show_glyphs", _show_glyphs },
+ { "show_text", _show_text },
+ { "show_text_glyphs", _show_text_glyphs },
+ { "show_page", _show_page },
+ { "similar", _similar },
+ { "sin", NULL },
+ { "sqrt", NULL },
+ { "sub", _sub },
+ { "surface", _surface },
+ { "string", NULL },
+ { "stroke", _stroke },
+ { "stroke_extents", NULL },
+ { "stroke_preserve", _stroke_preserve },
+ { "stroke+", _stroke_preserve },
+ { "text_path", _text_path },
+ { "transform", _transform },
+ { "transform_distance", NULL },
+ { "transform_point", NULL },
+ { "translate", _translate },
+ { "true", _true },
+ { "type", NULL },
+ { "undef", _undef },
+ { "unset", _unset },
+ { "user_to_device", NULL },
+ { "user_to_device_distance", NULL },
+ { "where", NULL },
+ { "write_to_png", _write_to_png },
+ { "xor", _xor },
+
+ { "=", _debug_print },
+
+ { NULL, NULL },
+};
+
+const csi_operator_def_t *
+_csi_operators (void)
+{
+ return _defs;
+}
+
+static const csi_integer_constant_def_t
+_integer_constants[] = {
+ { "CLEAR", CAIRO_OPERATOR_CLEAR },
+ { "SOURCE", CAIRO_OPERATOR_SOURCE },
+ { "OVER", CAIRO_OPERATOR_OVER },
+ { "IN", CAIRO_OPERATOR_IN },
+ { "OUT", CAIRO_OPERATOR_OUT },
+ { "ATOP", CAIRO_OPERATOR_ATOP },
+ { "DEST", CAIRO_OPERATOR_DEST },
+ { "DEST_OVER", CAIRO_OPERATOR_DEST_OVER },
+ { "DEST_IN", CAIRO_OPERATOR_DEST_IN },
+ { "DEST_OUT", CAIRO_OPERATOR_DEST_OUT },
+ { "DEST_ATOP", CAIRO_OPERATOR_DEST_ATOP },
+ { "XOR", CAIRO_OPERATOR_XOR },
+ { "ADD", CAIRO_OPERATOR_ADD },
+ { "SATURATE", CAIRO_OPERATOR_SATURATE },
+
+ { "WINDING", CAIRO_FILL_RULE_WINDING },
+ { "EVEN_ODD", CAIRO_FILL_RULE_EVEN_ODD },
+
+ { "ANTIALIAS_DEFAULT", CAIRO_ANTIALIAS_DEFAULT },
+ { "ANTIALIAS_NONE", CAIRO_ANTIALIAS_NONE },
+ { "ANTIALIAS_GRAY", CAIRO_ANTIALIAS_GRAY },
+ { "ANTIALIAS_SUBPIXEL", CAIRO_ANTIALIAS_SUBPIXEL },
+
+ { "LINE_CAP_BUTT", CAIRO_LINE_CAP_BUTT },
+ { "LINE_CAP_ROUND", CAIRO_LINE_CAP_ROUND },
+ { "LINE_CAP_SQUARE", CAIRO_LINE_CAP_SQUARE },
+
+ { "LINE_JOIN_MITER", CAIRO_LINE_JOIN_MITER },
+ { "LINE_JOIN_ROUND", CAIRO_LINE_JOIN_ROUND },
+ { "LINE_JOIN_BEVEL", CAIRO_LINE_JOIN_BEVEL },
+
+ { "EXTEND_NONE", CAIRO_EXTEND_NONE },
+ { "EXTEND_REPEAT", CAIRO_EXTEND_REPEAT },
+ { "EXTEND_REFLECT", CAIRO_EXTEND_REFLECT },
+ { "EXTEND_PAD", CAIRO_EXTEND_PAD },
+
+ { "FILTER_FAST", CAIRO_FILTER_FAST },
+ { "FILTER_GOOD", CAIRO_FILTER_GOOD },
+ { "FILTER_BEST", CAIRO_FILTER_BEST },
+ { "FILTER_BILINEAR", CAIRO_FILTER_BILINEAR },
+ { "FILTER_NEAREST", CAIRO_FILTER_NEAREST },
+ { "FILTER_GAUSSIAN", CAIRO_FILTER_GAUSSIAN },
+
+ { "SLANT_NORMAL", CAIRO_FONT_SLANT_NORMAL },
+ { "SLANT_ITALIC", CAIRO_FONT_SLANT_ITALIC },
+ { "SLANT_OBLIQUE", CAIRO_FONT_SLANT_OBLIQUE },
+
+ { "WEIGHT_NORMAL", CAIRO_FONT_WEIGHT_NORMAL },
+ { "WEIGHT_BOLD", CAIRO_FONT_WEIGHT_BOLD },
+
+ { "SUBPIXEL_ORDER_DEFAULT", CAIRO_SUBPIXEL_ORDER_DEFAULT },
+ { "SUBPIXEL_ORDER_RGB", CAIRO_SUBPIXEL_ORDER_RGB },
+ { "SUBPIXEL_ORDER_BGR", CAIRO_SUBPIXEL_ORDER_BGR },
+ { "SUBPIXEL_ORDER_VRGB", CAIRO_SUBPIXEL_ORDER_VRGB },
+ { "SUBPIXEL_ORDER_VBGR", CAIRO_SUBPIXEL_ORDER_VBGR },
+
+ { "HINT_STYLE_DEFAULT", CAIRO_HINT_STYLE_DEFAULT },
+ { "HINT_STYLE_NONE", CAIRO_HINT_STYLE_NONE },
+ { "HINT_STYLE_SLIGHT", CAIRO_HINT_STYLE_SLIGHT },
+ { "HINT_STYLE_MEDIUM", CAIRO_HINT_STYLE_MEDIUM },
+ { "HINT_STYLE_FULL", CAIRO_HINT_STYLE_FULL },
+
+ { "HINT_METRICS_DEFAULT", CAIRO_HINT_METRICS_DEFAULT },
+ { "HINT_METRICS_OFF", CAIRO_HINT_METRICS_OFF },
+ { "HINT_METRICS_ON", CAIRO_HINT_METRICS_ON },
+
+ { "FORWARD", 0 },
+ { "BACKWARD", 1 },
+
+ { "COLOR", CAIRO_CONTENT_COLOR },
+ { "ALPHA", CAIRO_CONTENT_ALPHA },
+ { "COLOR_ALPHA", CAIRO_CONTENT_COLOR_ALPHA },
+
+ { "A1", CAIRO_FORMAT_A1 },
+ { "A8", CAIRO_FORMAT_A8 },
+ { "RGB24", CAIRO_FORMAT_RGB24 },
+ { "ARGB32", CAIRO_FORMAT_ARGB32 },
+
+ { NULL, 0 }
+};
+
+const csi_integer_constant_def_t *
+_csi_integer_constants (void)
+{
+ return _integer_constants;
+}
diff --git a/util/cairo-script/cairo-script-private.h b/util/cairo-script/cairo-script-private.h
new file mode 100644
index 00000000..8ab1f63a
--- /dev/null
+++ b/util/cairo-script/cairo-script-private.h
@@ -0,0 +1,870 @@
+/*
+ * Copyright © 2008 Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Chris Wilson.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_SCRIPT_PRIVATE_H
+#define CAIRO_SCRIPT_PRIVATE_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cairo-script-interpreter.h"
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+#ifndef NULL
+#define NULL (void *) 0
+#endif
+
+#if HAVE_STDINT_H
+# include <stdint.h>
+#elif HAVE_INTTYPES_H
+# include <inttypes.h>
+#elif HAVE_SYS_INT_TYPES_H
+# include <sys/int_types.h>
+#elif defined(_MSC_VER)
+ typedef __int8 int8_t;
+ typedef unsigned __int8 uint8_t;
+ typedef __int16 int16_t;
+ typedef unsigned __int16 uint16_t;
+ typedef __int32 int32_t;
+ typedef unsigned __int32 uint32_t;
+ typedef __int64 int64_t;
+ typedef unsigned __int64 uint64_t;
+# ifndef HAVE_UINT64_T
+# define HAVE_UINT64_T 1
+# endif
+#else
+#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.)
+#endif
+
+#if HAVE_BYTESWAP_H
+# include <byteswap.h>
+#endif
+#ifndef bswap_16
+# define bswap_16(p) \
+ (((((uint16_t)(p)) & 0x00ff) << 8) | \
+ (((uint16_t)(p)) >> 8));
+#endif
+#ifndef bswap_32
+# define bswap_32(p) \
+ (((((uint32_t)(p)) & 0x000000ff) << 24) | \
+ ((((uint32_t)(p)) & 0x0000ff00) << 8) | \
+ ((((uint32_t)(p)) & 0x00ff0000) >> 8) | \
+ ((((uint32_t)(p))) >> 24));
+#endif
+
+
+#if __GNUC__ >= 3 && defined(__ELF__) && !defined(__sun)
+# define slim_hidden_proto(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) csi_private
+# define slim_hidden_proto_no_warn(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) csi_private_no_warn
+# define slim_hidden_def(name) slim_hidden_def1(name, slim_hidden_int_name(name))
+# define slim_hidden_int_name(name) INT_##name
+# define slim_hidden_proto1(name, internal) \
+ extern __typeof (name) name \
+ __asm__ (slim_hidden_asmname (internal))
+# define slim_hidden_def1(name, internal) \
+ extern __typeof (name) EXT_##name __asm__(slim_hidden_asmname(name)) \
+ __attribute__((__alias__(slim_hidden_asmname(internal))))
+# define slim_hidden_ulp slim_hidden_ulp1(__USER_LABEL_PREFIX__)
+# define slim_hidden_ulp1(x) slim_hidden_ulp2(x)
+# define slim_hidden_ulp2(x) #x
+# define slim_hidden_asmname(name) slim_hidden_asmname1(name)
+# define slim_hidden_asmname1(name) slim_hidden_ulp #name
+#else
+# define slim_hidden_proto(name) int _csi_dummy_prototype(void)
+# define slim_hidden_proto_no_warn(name) int _csi_dummy_prototype(void)
+# define slim_hidden_def(name) int _csi_dummy_prototype(void)
+#endif
+
+#if __GNUC__ >= 3
+#define csi_pure __attribute__((pure))
+#define csi_const __attribute__((const))
+#else
+#define csi_pure
+#define csi_const
+#endif
+
+#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
+#define _CSI_BOOLEAN_EXPR(expr) \
+ __extension__ ({ \
+ int _csi_boolean_var_; \
+ if (expr) \
+ _csi_boolean_var_ = 1; \
+ else \
+ _csi_boolean_var_ = 0; \
+ _csi_boolean_var_; \
+})
+#define _csi_likely(expr) (__builtin_expect (_CSI_BOOLEAN_EXPR(expr), 1))
+#define _csi_unlikely(expr) (__builtin_expect (_CSI_BOOLEAN_EXPR(expr), 0))
+#else
+#define _csi_likely(expr) (expr)
+#define _csi_unlikely(expr) (expr)
+#endif
+
+#ifdef __GNUC__
+#ifndef offsetof
+#define offsetof(type, member) \
+ ((char *) &((type *) 0)->member - (char *) 0)
+#endif
+#define csi_container_of(ptr, type, member) ({ \
+ const typeof(((type *) 0)->member) *mptr__ = (ptr); \
+ (type *) ((char *) mptr__ - offsetof (type, member)); \
+})
+#else
+#define csi_container_of(ptr, type, member) \
+ (type *)((char *) (ptr) - (char *) &((type *)0)->member)
+#endif
+
+/* slim_internal.h */
+#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun)
+#define csi_private_no_warn __attribute__((__visibility__("hidden")))
+#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+#define csi_private_no_warn __hidden
+#else /* not gcc >= 3.3 and not Sun Studio >= 8 */
+#define csi_private_no_warn
+#endif
+
+#undef ARRAY_LENGTH
+#define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0])))
+
+#ifndef WARN_UNUSED_RESULT
+#define WARN_UNUSED_RESULT
+#endif
+/* Add attribute(warn_unused_result) if supported */
+#define csi_warn WARN_UNUSED_RESULT
+#define csi_private csi_private_no_warn csi_warn
+
+#define CSI_BITSWAP8(c) ((((c) * 0x0802LU & 0x22110LU) | ((c) * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16)
+#ifdef WORDS_BIGENDIAN
+#define CSI_BITSWAP8_IF_LITTLE_ENDIAN(c) (c)
+#else
+#define CSI_BITSWAP8_IF_LITTLE_ENDIAN(c) CSI_BITSWAP8(c)
+#endif
+
+typedef enum _csi_status {
+ CSI_STATUS_SUCCESS = CAIRO_STATUS_SUCCESS,
+ CSI_STATUS_NO_MEMORY = CAIRO_STATUS_NO_MEMORY,
+ CSI_STATUS_INVALID_RESTORE = CAIRO_STATUS_INVALID_RESTORE,
+ CSI_STATUS_INVALID_POP_GROUP = CAIRO_STATUS_INVALID_POP_GROUP,
+ CSI_STATUS_NO_CURRENT_POINT = CAIRO_STATUS_NO_CURRENT_POINT,
+ CSI_STATUS_INVALID_MATRIX = CAIRO_STATUS_INVALID_MATRIX,
+ CSI_STATUS_INVALID_STATUS = CAIRO_STATUS_INVALID_STATUS,
+ CSI_STATUS_NULL_POINTER = CAIRO_STATUS_NULL_POINTER,
+ CSI_STATUS_INVALID_STRING = CAIRO_STATUS_INVALID_STRING,
+ CSI_STATUS_INVALID_PATH_DATA = CAIRO_STATUS_INVALID_PATH_DATA,
+ CSI_STATUS_READ_ERROR = CAIRO_STATUS_READ_ERROR,
+ CSI_STATUS_WRITE_ERROR = CAIRO_STATUS_WRITE_ERROR,
+ CSI_STATUS_SURFACE_FINISHED = CAIRO_STATUS_SURFACE_FINISHED,
+ CSI_STATUS_SURFACE_TYPE_MISMATCH = CAIRO_STATUS_SURFACE_TYPE_MISMATCH,
+ CSI_STATUS_PATTERN_TYPE_MISMATCH = CAIRO_STATUS_PATTERN_TYPE_MISMATCH,
+ CSI_STATUS_INVALID_CONTENT = CAIRO_STATUS_INVALID_CONTENT,
+ CSI_STATUS_INVALID_FORMAT = CAIRO_STATUS_INVALID_FORMAT,
+ CSI_STATUS_INVALID_VISUAL = CAIRO_STATUS_INVALID_VISUAL,
+ CSI_STATUS_FILE_NOT_FOUND = CAIRO_STATUS_FILE_NOT_FOUND,
+ CSI_STATUS_INVALID_DASH = CAIRO_STATUS_INVALID_DASH,
+ CSI_STATUS_INVALID_DSC_COMMENT = CAIRO_STATUS_INVALID_DSC_COMMENT,
+ CSI_STATUS_INVALID_INDEX = CAIRO_STATUS_INVALID_INDEX,
+ CSI_STATUS_CLIP_NOT_REPRESENTABLE = CAIRO_STATUS_CLIP_NOT_REPRESENTABLE,
+ CSI_STATUS_TEMP_FILE_ERROR = CAIRO_STATUS_TEMP_FILE_ERROR,
+ CSI_STATUS_INVALID_STRIDE = CAIRO_STATUS_INVALID_STRIDE,
+ CSI_STATUS_FONT_TYPE_MISMATCH = CAIRO_STATUS_FONT_TYPE_MISMATCH,
+ CSI_STATUS_USER_FONT_IMMUTABLE = CAIRO_STATUS_USER_FONT_IMMUTABLE,
+ CSI_STATUS_USER_FONT_ERROR = CAIRO_STATUS_USER_FONT_ERROR,
+ CSI_STATUS_NEGATIVE_COUNT = CAIRO_STATUS_NEGATIVE_COUNT,
+ CSI_STATUS_INVALID_CLUSTERS = CAIRO_STATUS_INVALID_CLUSTERS,
+ CSI_STATUS_INVALID_SLANT = CAIRO_STATUS_INVALID_SLANT,
+ CSI_STATUS_INVALID_WEIGHT = CAIRO_STATUS_INVALID_WEIGHT,
+
+ /* cairo-script-interpreter specific errors */
+
+ CSI_STATUS_INVALID_SCRIPT,
+ CSI_STATUS_SCRIPT_INVALID_TYPE,
+ CSI_STATUS_SCRIPT_INVALID_INDEX,
+ CSI_STATUS_SCRIPT_UNDEFINED_NAME,
+
+ _CSI_STATUS_SCRIPT_LAST_ERROR,
+ CSI_INT_STATUS_UNSUPPORTED
+} csi_status_t;
+
+typedef enum {
+ CSI_OBJECT_TYPE_NULL = 0,
+
+ /* atomics */
+ CSI_OBJECT_TYPE_BOOLEAN,
+ CSI_OBJECT_TYPE_INTEGER,
+ CSI_OBJECT_TYPE_MARK,
+ CSI_OBJECT_TYPE_NAME,
+ CSI_OBJECT_TYPE_OPERATOR,
+ CSI_OBJECT_TYPE_REAL,
+
+ /* compound */
+ CSI_OBJECT_TYPE_ARRAY = 0x8,
+ CSI_OBJECT_TYPE_DICTIONARY,
+ CSI_OBJECT_TYPE_FILE,
+ CSI_OBJECT_TYPE_MATRIX,
+ CSI_OBJECT_TYPE_STRING,
+
+ /* cairo */
+ CSI_OBJECT_TYPE_CONTEXT = 0x10,
+ CSI_OBJECT_TYPE_FONT,
+ CSI_OBJECT_TYPE_PATTERN,
+ CSI_OBJECT_TYPE_SCALED_FONT,
+ CSI_OBJECT_TYPE_SURFACE,
+} csi_object_type_t;
+
+#define CSI_OBJECT_IS_ATOM(OBJ) (((OBJ)->type & CSI_OBJECT_TYPE_MASK) < 0x08)
+#define CSI_OBJECT_IS_COMPOUND(OBJ) ((OBJ)->type & 0x08)
+#define CSI_OBJECT_IS_CAIRO(OBJ) ((OBJ)->type & 0x10)
+
+enum { /* attributes */
+ CSI_OBJECT_ATTR_EXECUTABLE = 1 << 6,
+ CSI_OBJECT_ATTR_WRITABLE = 1 << 7,
+};
+#define CSI_OBJECT_ATTR_MASK (CSI_OBJECT_ATTR_EXECUTABLE | \
+ CSI_OBJECT_ATTR_WRITABLE)
+#define CSI_OBJECT_TYPE_MASK (~CSI_OBJECT_ATTR_MASK)
+
+typedef struct _cairo_script_interpreter csi_t;
+
+typedef cairo_bool_t csi_boolean_t;
+typedef csi_status_t (*csi_operator_t) (csi_t *);
+typedef float csi_real_t;
+typedef long csi_integer_t;
+typedef long csi_name_t;
+typedef struct _csi_array csi_array_t;
+typedef struct _csi_buffer csi_buffer_t;
+typedef struct _csi_compound_object csi_compound_object_t;
+typedef struct _csi_dictionary csi_dictionary_t;
+typedef struct _csi_file csi_file_t;
+typedef struct _csi_hash_entry csi_hash_entry_t;
+typedef struct _csi_hash_table csi_hash_table_t;
+typedef struct _csi_hash_table_arrangement csi_hash_table_arrangement_t;
+typedef struct _csi_list csi_list_t;
+typedef struct _csi_matrix csi_matrix_t;
+typedef struct _csi_object csi_object_t;
+typedef struct _csi_scanner csi_scanner_t;
+typedef struct _csi_stack csi_stack_t;
+typedef struct _csi_string csi_string_t;
+
+typedef cairo_bool_t
+(*csi_hash_predicate_func_t) (void *entry);
+
+typedef void
+(*csi_hash_callback_func_t) (void *entry,
+ void *closure);
+
+typedef cairo_bool_t
+(*csi_hash_keys_equal_func_t) (const void *key_a, const void *key_b);
+
+struct _csi_object {
+ csi_object_type_t type;
+ union {
+ cairo_t *cr;
+ cairo_font_face_t *font_face;
+ cairo_pattern_t *pattern;
+ cairo_scaled_font_t *scaled_font;
+ cairo_surface_t *surface;
+ csi_array_t *array;
+ csi_boolean_t boolean;
+ csi_compound_object_t *object;
+ csi_dictionary_t *dictionary;
+ csi_file_t *file;
+ csi_integer_t integer;
+ csi_matrix_t *matrix;
+ csi_operator_t op;
+ csi_name_t name;
+ csi_real_t real;
+ csi_string_t *string;
+ void *ptr;
+ } datum;
+};
+
+struct _csi_compound_object {
+ csi_object_type_t type;
+ unsigned int ref;
+};
+
+struct _csi_hash_entry {
+ unsigned long hash;
+};
+
+struct _csi_hash_table_arrangement {
+ unsigned long high_water_mark;
+ unsigned long size;
+ unsigned long rehash;
+};
+
+struct _csi_hash_table {
+ csi_hash_keys_equal_func_t keys_equal;
+
+ const csi_hash_table_arrangement_t *arrangement;
+ csi_hash_entry_t **entries;
+
+ unsigned long live_entries;
+ unsigned long iterating; /* Iterating, no insert, no resize */
+};
+
+
+/* simple, embedded doubly-linked links */
+struct _csi_list {
+ struct _csi_list *next, *prev;
+};
+
+struct _csi_buffer {
+ csi_status_t status;
+
+ char *base, *ptr, *end;
+ unsigned int size;
+};
+
+struct _csi_stack {
+ csi_object_t *objects;
+ csi_integer_t len;
+ csi_integer_t size;
+};
+
+struct _csi_array {
+ csi_compound_object_t base;
+ csi_stack_t stack;
+};
+
+typedef struct _csi_dictionary_entry {
+ csi_hash_entry_t hash_entry;
+ csi_object_t value;
+} csi_dictionary_entry_t;
+
+struct _csi_dictionary {
+ csi_compound_object_t base;
+ csi_hash_table_t hash_table;
+};
+
+struct _csi_matrix {
+ csi_compound_object_t base;
+ cairo_matrix_t matrix;
+};
+
+struct _csi_string {
+ csi_compound_object_t base;
+ csi_integer_t len;
+ char *string;
+};
+
+typedef struct _csi_filter_funcs {
+ int (*filter_getc) (csi_file_t *);
+ void (*filter_putc) (csi_file_t *, int);
+ int (*filter_read) (csi_file_t *, uint8_t *, int);
+ void (*filter_destroy) (csi_t *, void *);
+} csi_filter_funcs_t;
+
+struct _csi_file {
+ csi_compound_object_t base;
+ enum {
+ STDIO,
+ BYTES,
+ PROCEDURE,
+ FILTER,
+ } type;
+ void *src;
+ void *data;
+ uint8_t *bp;
+ int rem;
+ const csi_filter_funcs_t *filter;
+};
+
+struct _csi_scanner {
+ csi_status_t status;
+
+ enum {
+ NONE,
+ TOKEN,
+ COMMENT,
+ STRING,
+ HEX,
+ BASE85,
+ } state;
+
+ csi_buffer_t buffer;
+ csi_stack_t procedure_stack;
+ csi_object_t build_procedure;
+
+ int string_p;
+ unsigned int accumulator;
+ unsigned int accumulator_count;
+};
+
+typedef cairo_script_interpreter_hooks_t csi_hooks_t;
+
+struct _cairo_script_interpreter {
+ int ref_count;
+ csi_status_t status;
+
+ csi_hooks_t hooks;
+
+ csi_hash_table_t strings;
+
+ csi_stack_t ostack;
+ csi_stack_t dstack;
+
+ csi_scanner_t scanner;
+
+ /* caches of live data */
+ csi_list_t *_images;
+ csi_list_t *_faces;
+};
+
+typedef struct _csi_operator_def {
+ const char *name;
+ csi_operator_t op;
+} csi_operator_def_t;
+
+typedef struct _csi_integer_constant_def {
+ const char *name;
+ csi_integer_t value;
+} csi_integer_constant_def_t;
+
+/* cairo-script-file.c */
+
+csi_private csi_status_t
+csi_file_new (csi_t *ctx,
+ csi_object_t *obj,
+ const char *path, const char *mode);
+
+csi_private csi_status_t
+csi_file_new_for_bytes (csi_t *ctx,
+ csi_object_t *obj,
+ const char *bytes,
+ unsigned int length);
+
+csi_private csi_status_t
+csi_file_new_from_string (csi_t *ctx,
+ csi_object_t *obj,
+ csi_string_t *src);
+
+csi_private csi_status_t
+csi_file_new_ascii85_decode (csi_t *ctx,
+ csi_object_t *obj,
+ csi_dictionary_t *dict,
+ csi_object_t *src);
+
+csi_private csi_status_t
+csi_file_new_deflate_decode (csi_t *ctx,
+ csi_object_t *obj,
+ csi_dictionary_t *dict,
+ csi_object_t *src);
+
+csi_private csi_status_t
+_csi_file_execute (csi_t *ctx, csi_file_t *obj);
+
+csi_private int
+csi_file_getc (csi_file_t *obj);
+
+csi_private int
+csi_file_read (csi_file_t *obj, void *buf, int len);
+
+csi_private void
+csi_file_putc (csi_file_t *obj, int c);
+
+csi_private void
+csi_file_flush (csi_file_t *obj);
+
+csi_private void
+csi_file_close (csi_t *ctx, csi_file_t *obj);
+
+csi_private void
+_csi_file_free (csi_t *ctx, csi_file_t *obj);
+
+csi_private csi_status_t
+_csi_file_as_string (csi_t *ctx,
+ csi_file_t *file,
+ csi_object_t *obj);
+
+/* cairo-script-hash.c */
+
+csi_private csi_status_t
+_csi_hash_table_init (csi_hash_table_t *hash_table,
+ csi_hash_keys_equal_func_t keys_equal);
+
+csi_private void
+_csi_hash_table_fini (csi_hash_table_t *hash_table);
+
+csi_private void *
+_csi_hash_table_lookup (csi_hash_table_t *hash_table,
+ csi_hash_entry_t *key);
+
+csi_private csi_status_t
+_csi_hash_table_insert (csi_hash_table_t *hash_table,
+ csi_hash_entry_t *entry);
+
+csi_private void
+_csi_hash_table_remove (csi_hash_table_t *hash_table,
+ csi_hash_entry_t *key);
+
+csi_private void
+_csi_hash_table_foreach (csi_hash_table_t *hash_table,
+ csi_hash_callback_func_t hash_callback,
+ void *closure);
+
+/* cairo-script-interpreter.c */
+
+csi_private void *
+_csi_alloc (csi_t *ctx, int size);
+
+csi_private void *
+_csi_alloc0 (csi_t *ctx, int size);
+
+csi_private void *
+_csi_realloc (csi_t *ctx, void *ptr, int size);
+
+csi_private void
+_csi_free (csi_t *ctx, void *ptr);
+
+csi_private void *
+_csi_slab_alloc (csi_t *ctx, int size);
+
+csi_private void
+_csi_slab_free (csi_t *ctx, void *ptr, int size);
+
+csi_private csi_status_t
+csi_push_ostack (csi_t *ctx, csi_object_t *obj);
+
+csi_private csi_status_t
+_csi_name_define (csi_t *ctx, csi_name_t name, csi_object_t *obj);
+
+csi_private csi_status_t
+_csi_name_lookup (csi_t *ctx, csi_name_t name, csi_object_t *obj);
+
+csi_private csi_status_t
+_csi_name_undefine (csi_t *ctx, csi_name_t name);
+
+csi_private csi_status_t
+_csi_intern_string (csi_t *ctx, const char **str_inout, int len);
+
+csi_private csi_status_t
+_csi_error (csi_status_t status);
+
+/* cairo-script-objects.c */
+
+csi_private csi_status_t
+csi_array_new (csi_t *ctx,
+ csi_object_t *obj);
+
+csi_private csi_status_t
+_csi_array_execute (csi_t *ctx, csi_array_t *array);
+
+csi_private csi_status_t
+csi_array_get (csi_t *ctx,
+ csi_array_t *array,
+ long elem,
+ csi_object_t *value);
+
+csi_private csi_status_t
+csi_array_put (csi_t *ctx,
+ csi_array_t *array,
+ csi_integer_t elem,
+ csi_object_t *value);
+
+csi_private csi_status_t
+csi_array_append (csi_t *ctx,
+ csi_array_t *array,
+ csi_object_t *obj);
+
+csi_private void
+csi_array_free (csi_t *ctx, csi_array_t *array);
+
+csi_private csi_status_t
+csi_boolean_new (csi_t *ctx,
+ csi_object_t *obj,
+ csi_boolean_t v);
+
+csi_private csi_status_t
+csi_dictionary_new (csi_t *ctx,
+ csi_object_t *obj);
+
+csi_private csi_status_t
+csi_dictionary_put (csi_t *ctx,
+ csi_dictionary_t *dict,
+ csi_name_t name,
+ csi_object_t *value);
+
+csi_private csi_status_t
+csi_dictionary_get (csi_t *ctx,
+ csi_dictionary_t *dict,
+ csi_name_t name,
+ csi_object_t *value);
+
+csi_private csi_boolean_t
+csi_dictionary_has (csi_dictionary_t *dict,
+ csi_name_t name);
+
+csi_private void
+csi_dictionary_remove (csi_t *ctx,
+ csi_dictionary_t *dict,
+ csi_name_t name);
+
+csi_private void
+csi_dictionary_free (csi_t *ctx,
+ csi_dictionary_t *dict);
+
+csi_private csi_status_t
+csi_integer_new (csi_t *ctx,
+ csi_object_t *obj,
+ csi_integer_t v);
+
+csi_private csi_status_t
+csi_matrix_new (csi_t *ctx,
+ csi_object_t *obj);
+
+csi_private csi_status_t
+csi_matrix_new_from_array (csi_t *ctx,
+ csi_object_t *obj,
+ csi_array_t *array);
+
+csi_private csi_status_t
+csi_matrix_new_from_matrix (csi_t *ctx,
+ csi_object_t *obj,
+ const cairo_matrix_t *m);
+
+csi_private csi_status_t
+csi_matrix_new_from_values (csi_t *ctx,
+ csi_object_t *obj,
+ double v[6]);
+
+csi_private void
+csi_matrix_free (csi_t *ctx,
+ csi_matrix_t *obj);
+
+csi_private csi_status_t
+csi_name_new (csi_t *ctx,
+ csi_object_t *obj,
+ const char *str,
+ int len);
+
+csi_private csi_status_t
+csi_name_new_static (csi_t *ctx,
+ csi_object_t *obj,
+ const char *str);
+
+csi_private csi_status_t
+csi_operator_new (csi_t *ctx,
+ csi_object_t *obj,
+ csi_operator_t op);
+
+csi_private csi_status_t
+csi_real_new (csi_t *ctx,
+ csi_object_t *obj,
+ csi_real_t v);
+
+csi_private csi_status_t
+csi_string_new (csi_t *ctx,
+ csi_object_t *obj,
+ const char *str,
+ int len);
+
+csi_private void
+csi_string_free (csi_t *ctx, csi_string_t *string);
+
+csi_private csi_status_t
+csi_object_execute (csi_t *ctx, csi_object_t *obj);
+
+csi_private csi_object_t *
+csi_object_reference (csi_object_t *obj);
+
+csi_private void
+csi_object_free (csi_t *ctx,
+ csi_object_t *obj);
+
+csi_private csi_status_t
+csi_object_as_file (csi_t *ctx,
+ csi_object_t *src,
+ csi_object_t *file);
+
+/* cairo-script-operators.c */
+
+csi_private const csi_operator_def_t *
+_csi_operators (void);
+
+csi_private const csi_integer_constant_def_t *
+_csi_integer_constants (void);
+
+/* cairo-script-scanner.c */
+
+csi_private csi_status_t
+_csi_scanner_init (csi_t *ctx, csi_scanner_t *scanner);
+
+csi_private csi_status_t
+_csi_scan_file (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src);
+
+csi_private void
+_csi_scanner_fini (csi_t *ctx, csi_scanner_t *scanner);
+
+/* cairo-script-stack.c */
+
+csi_private csi_status_t
+_csi_stack_init (csi_t *ctx, csi_stack_t *stack, csi_integer_t size);
+
+csi_private void
+_csi_stack_fini (csi_t *ctx, csi_stack_t *stack);
+
+csi_private csi_status_t
+_csi_stack_roll (csi_t *ctx,
+ csi_stack_t *stack,
+ csi_integer_t mod,
+ csi_integer_t n);
+
+csi_private csi_status_t
+_csi_stack_grow (csi_t *ctx, csi_stack_t *stack, csi_integer_t cnt);
+
+csi_private csi_status_t
+_csi_stack_push (csi_t *ctx, csi_stack_t *stack, const csi_object_t *obj);
+
+csi_private csi_object_t *
+_csi_stack_peek (csi_stack_t *stack, csi_integer_t i);
+
+csi_private void
+_csi_stack_pop (csi_t *ctx, csi_stack_t *stack, csi_integer_t count);
+
+csi_private csi_status_t
+_csi_stack_exch (csi_stack_t *stack);
+
+static inline csi_object_type_t
+csi_object_get_type (const csi_object_t *obj)
+{
+ return obj->type & CSI_OBJECT_TYPE_MASK;
+}
+
+static inline csi_boolean_t
+csi_object_is_procedure (const csi_object_t *obj)
+{
+ return obj->type == (CSI_OBJECT_TYPE_ARRAY | CSI_OBJECT_ATTR_EXECUTABLE);
+}
+
+static inline csi_boolean_t
+csi_object_is_number (const csi_object_t *obj)
+{
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_BOOLEAN:
+ case CSI_OBJECT_TYPE_INTEGER:
+ case CSI_OBJECT_TYPE_REAL:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static inline double
+csi_number_get_value (const csi_object_t *obj)
+{
+ switch ((int) csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_BOOLEAN: return obj->datum.boolean;
+ case CSI_OBJECT_TYPE_INTEGER: return obj->datum.integer;
+ case CSI_OBJECT_TYPE_REAL: return obj->datum.real;
+ default: return 0.;
+ }
+}
+
+static inline csi_boolean_t
+_csi_check_ostack (csi_t *ctx, csi_integer_t count)
+{
+ return ctx->ostack.len >= count;
+}
+
+static inline csi_object_t *
+_csi_peek_ostack (csi_t *ctx, csi_integer_t i)
+{
+ return &ctx->ostack.objects[ctx->ostack.len - i -1];
+}
+
+static inline void
+_csi_pop_ostack (csi_t *ctx, csi_integer_t count)
+{
+ do
+ csi_object_free (ctx, &ctx->ostack.objects[--ctx->ostack.len]);
+ while (--count);
+}
+
+static inline csi_status_t
+_csi_push_ostack_copy (csi_t *ctx, csi_object_t *obj)
+{
+ return _csi_stack_push (ctx, &ctx->ostack, csi_object_reference (obj));
+}
+
+static inline csi_status_t
+_csi_push_ostack (csi_t *ctx, csi_object_t *obj)
+{
+ return _csi_stack_push (ctx, &ctx->ostack, obj);
+}
+
+static inline csi_status_t
+_csi_push_ostack_boolean (csi_t *ctx, csi_boolean_t v)
+{
+ csi_object_t obj;
+ obj.type = CSI_OBJECT_TYPE_BOOLEAN;
+ obj.datum.boolean = v;
+ return _csi_stack_push (ctx, &ctx->ostack, &obj);
+}
+static inline csi_status_t
+_csi_push_ostack_integer (csi_t *ctx, csi_integer_t v)
+{
+ csi_object_t obj;
+ obj.type = CSI_OBJECT_TYPE_INTEGER;
+ obj.datum.integer = v;
+ return _csi_stack_push (ctx, &ctx->ostack, &obj);
+}
+static inline csi_status_t
+_csi_push_ostack_mark (csi_t *ctx)
+{
+ csi_object_t obj;
+ obj.type = CSI_OBJECT_TYPE_MARK;
+ return _csi_stack_push (ctx, &ctx->ostack, &obj);
+}
+static inline csi_status_t
+_csi_push_ostack_real (csi_t *ctx, csi_real_t v)
+{
+ csi_object_t obj;
+ obj.type = CSI_OBJECT_TYPE_REAL;
+ obj.datum.real = v;
+ return _csi_stack_push (ctx, &ctx->ostack, &obj);
+}
+
+slim_hidden_proto_no_warn (cairo_script_interpreter_destroy);
+slim_hidden_proto_no_warn (cairo_script_interpreter_reference);
+
+#endif /* CAIRO_SCRIPT_PRIVATE_H */
diff --git a/util/cairo-script/cairo-script-scanner.c b/util/cairo-script/cairo-script-scanner.c
new file mode 100644
index 00000000..484acd96
--- /dev/null
+++ b/util/cairo-script/cairo-script-scanner.c
@@ -0,0 +1,1179 @@
+/*
+ * Copyright © 2008 Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Chris Wilson.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairo-script-private.h"
+
+#include <stdio.h> /* EOF */
+#include <string.h> /* memset */
+#include <math.h> /* pow */
+
+/*
+ * whitespace:
+ * 0 - nul
+ * 9 - tab
+ * A - LF
+ * C - FF
+ * D - CR
+ *
+ * syntax delimiters
+ * ( = 28, ) = 29 - literal strings
+ * < = 3C, > = 3E - hex/base85 strings, dictionary name
+ * [ = 5B, ] = 5D - array
+ * { = 7B, } = 7C - procedure
+ * / = 5C - literal marker
+ * % = 25 - comment
+ */
+
+static cairo_status_t
+_csi_buffer_init (csi_t *ctx, csi_buffer_t *buffer)
+{
+ buffer->status = CSI_STATUS_SUCCESS;
+ buffer->size = 16384;
+ buffer->base = _csi_alloc (ctx, buffer->size);
+ if (_csi_unlikely (buffer->base == NULL)) {
+ buffer->status = _csi_error (CSI_STATUS_NO_MEMORY);
+ buffer->size = 0;
+ }
+
+ buffer->ptr = buffer->base;
+ buffer->end = buffer->base + buffer->size;
+
+ return buffer->status;
+}
+
+static void
+_csi_buffer_fini (csi_t *ctx, csi_buffer_t *buffer)
+{
+ _csi_free (ctx, buffer->base);
+}
+
+static cairo_status_t
+_csi_buffer_grow (csi_t *ctx, csi_buffer_t *buffer)
+{
+ int newsize;
+ int offset;
+ char *base;
+
+ if (_csi_unlikely (buffer->status))
+ return buffer->status;
+
+ if (_csi_unlikely (buffer->size > INT32_MAX / 2))
+ return buffer->status = _csi_error (CSI_STATUS_NO_MEMORY);
+
+ offset = buffer->ptr - buffer->base;
+ newsize = buffer->size * 2;
+ base = _csi_realloc (ctx, buffer->base, newsize);
+ if (_csi_unlikely (base == NULL))
+ return buffer->status = _csi_error (CSI_STATUS_NO_MEMORY);
+
+ buffer->base = base;
+ buffer->ptr = base + offset;
+ buffer->end = base + newsize;
+ buffer->size = newsize;
+
+ return CSI_STATUS_SUCCESS;
+}
+
+static inline csi_boolean_t
+_csi_buffer_check (csi_t *ctx, csi_buffer_t *buffer, int count)
+{
+ if (_csi_unlikely (buffer->ptr + count > buffer->end)) {
+ if (_csi_buffer_grow (ctx, buffer))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static inline void
+_csi_buffer_add (csi_buffer_t *buffer, int c)
+{
+ *buffer->ptr++ = c;
+}
+
+static inline void
+_csi_buffer_reset (csi_buffer_t *buffer)
+{
+ buffer->ptr = buffer->base;
+}
+
+static inline int
+scan_getc (csi_scanner_t *scan, csi_file_t *src)
+{
+ if (_csi_unlikely (scan->status))
+ return EOF;
+
+ return csi_file_getc (src);
+}
+
+static inline int
+scan_read (csi_scanner_t *scan, csi_file_t *src, void *buf, int len)
+{
+ return csi_file_read (src, buf, len);
+}
+
+static inline void
+scan_putc (csi_scanner_t *scan, csi_file_t *src, int c)
+{
+ csi_file_putc (src, c);
+}
+
+static inline void
+reset (csi_scanner_t *scan)
+{
+ scan->state = NONE;
+}
+
+static void
+token_start (csi_scanner_t *scan)
+{
+ scan->state = TOKEN;
+ _csi_buffer_reset (&scan->buffer);
+}
+
+static void
+token_add (csi_t *ctx, csi_scanner_t *scan, int c)
+{
+ if (_csi_likely (_csi_buffer_check (ctx, &scan->buffer, 1)))
+ _csi_buffer_add (&scan->buffer, c);
+}
+
+static void
+token_add_unchecked (csi_scanner_t *scan, int c)
+{
+ _csi_buffer_add (&scan->buffer, c);
+}
+
+static csi_boolean_t
+parse_number (csi_object_t *obj, const char *s, int len)
+{
+ int radix = 0;
+ long long mantissa = 0;
+ int exponent = 0;
+ int sign = 1;
+ int decimal = -1;
+ int exponent_sign = 0;
+ const char * const end = s + len;
+
+ switch (*s) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ mantissa = *s - '0';
+ case '+':
+ break;
+ case '-':
+ sign = -1;
+ break;
+ case '.':
+ decimal = 0;
+ break;
+ default:
+ return FALSE;
+ }
+
+ while (++s < end) {
+ if (*s < '0') {
+ if (*s == '.') {
+ if (radix)
+ return FALSE;
+ if (decimal != -1)
+ return FALSE;
+ if (exponent_sign)
+ return FALSE;
+
+ decimal = 0;
+ } else if (*s == '!') {
+ if (radix)
+ return FALSE;
+ if (decimal != -1)
+ return FALSE;
+ if (exponent_sign)
+ return FALSE;
+
+ radix = mantissa;
+ mantissa = 0;
+
+ if (radix < 2 || radix > 36)
+ return FALSE;
+ } else
+ return FALSE;
+ } else if (*s <= '9') {
+ int v = *s - '0';
+ if (radix && v >= radix)
+ return FALSE;
+
+ if (exponent_sign) {
+ exponent = 10 * exponent + v;
+ } else {
+ if (radix)
+ mantissa = radix * mantissa + v;
+ else
+ mantissa = 10 * mantissa + v;
+ if (decimal != -1)
+ decimal++;
+ }
+ } else if (*s == 'E' || * s== 'e') {
+ if (radix == 0) {
+ if (s + 1 == end)
+ return FALSE;
+
+ exponent_sign = 1;
+ if (s[1] == '-') {
+ exponent_sign = -1;
+ s++;
+ } else if (s[1] == '+')
+ s++;
+ } else {
+ int v = 0xe;
+
+ if (v >= radix)
+ return FALSE;
+
+ mantissa = radix * mantissa + v;
+ }
+ } else if (*s < 'A') {
+ return FALSE;
+ } else if (*s <= 'Z') {
+ int v = *s - 'A' + 0xA;
+
+ if (v >= radix)
+ return FALSE;
+
+ mantissa = radix * mantissa + v;
+ } else if (*s < 'a') {
+ return FALSE;
+ } else if (*s <= 'z') {
+ int v = *s - 'a' + 0xa;
+
+ if (v >= radix)
+ return FALSE;
+
+ mantissa = radix * mantissa + v;
+ } else
+ return FALSE;
+ }
+
+ if (exponent_sign || decimal != -1) {
+ if (mantissa == 0) {
+ obj->type = CSI_OBJECT_TYPE_REAL;
+ obj->datum.real = 0.;
+ return TRUE;
+ } else {
+ int e;
+ double v;
+
+ v = mantissa;
+ e = exponent * exponent_sign;
+ if (decimal != -1)
+ e -= decimal;
+ if (e != 0)
+ v *= pow (10, e); /* XXX */
+
+ obj->type = CSI_OBJECT_TYPE_REAL;
+ obj->datum.real = sign * v;
+ return TRUE;
+ }
+ } else {
+ obj->type = CSI_OBJECT_TYPE_INTEGER;
+ obj->datum.integer = sign * mantissa;
+ return TRUE;
+ }
+}
+
+static void
+token_end (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
+{
+ char *s;
+ csi_object_t obj;
+ int len;
+
+ /*
+ * Any token that consists entirely of regular characters and
+ * cannot be interpreted as a number is treated as a name object
+ * (more precisely, an executable name). All characters except
+ * delimiters and white-space characters can appear in names,
+ * including characters ordinarily considered to be punctuation.
+ */
+
+ if (_csi_unlikely (scan->buffer.ptr == scan->buffer.base))
+ return;
+
+ scan->status = scan->buffer.status;
+ if (_csi_unlikely (scan->status))
+ return;
+
+ s = scan->buffer.base;
+ len = scan->buffer.ptr - scan->buffer.base;
+
+ if (s[0] == '{') { /* special case procedures */
+ if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL)
+ scan->status = _csi_stack_push (ctx,
+ &scan->procedure_stack,
+ &scan->build_procedure);
+
+ scan->status = csi_array_new (ctx, &scan->build_procedure);
+ scan->build_procedure.type |= CSI_OBJECT_ATTR_EXECUTABLE;
+ reset (scan);
+ return;
+ } else if (s[0] == '}') {
+ csi_object_t *next;
+
+ if (_csi_unlikely
+ (scan->build_procedure.type == CSI_OBJECT_TYPE_NULL))
+ {
+ scan->status = _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ return;
+ }
+
+ if (scan->procedure_stack.len) {
+ next = _csi_stack_peek (&scan->procedure_stack, 0);
+ scan->status = csi_array_append (ctx, next->datum.array,
+ &scan->build_procedure);
+ scan->build_procedure = *next;
+ scan->procedure_stack.len--;
+ } else {
+ scan->status = _csi_push_ostack (ctx, &scan->build_procedure);
+ scan->build_procedure.type = CSI_OBJECT_TYPE_NULL;
+ }
+
+ reset (scan);
+ return;
+ }
+
+ if (s[0] == '/') {
+ if (len >= 2 && s[1] == '/') { /* substituted name */
+ scan->status = csi_name_new (ctx, &obj, s + 2, len - 2);
+ if (_csi_unlikely (scan->status))
+ return;
+
+ scan->status = _csi_name_lookup (ctx, obj.datum.name, &obj);
+ } else { /* literal name */
+ scan->status = csi_name_new (ctx, &obj, s + 1, len - 1);
+ }
+ } else {
+ if (! parse_number (&obj, s, len)) {
+ scan->status = csi_name_new (ctx, &obj, s, len);
+ obj.type |= CSI_OBJECT_ATTR_EXECUTABLE;
+ }
+ }
+ if (_csi_unlikely (scan->status))
+ return;
+
+ /* consume whitespace after token, before calling the interpreter */
+ reset (scan);
+
+ if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) {
+ scan->status = csi_array_append (ctx,
+ scan->build_procedure.datum.array,
+ &obj);
+ } else if (obj.type & CSI_OBJECT_ATTR_EXECUTABLE) {
+ scan->status = csi_object_execute (ctx, csi_object_reference (&obj));
+ csi_object_free (ctx, &obj);
+ } else
+ scan->status = _csi_push_ostack (ctx, &obj);
+}
+
+static void
+comment_start (csi_scanner_t *scan)
+{
+ /* XXX check for '!' interpreter mode?, '%' dsc setup? */
+ scan->state = COMMENT;
+}
+
+static void
+comment_end (csi_scanner_t *scan)
+{
+ reset (scan);
+}
+
+static void
+string_start (csi_scanner_t *scan)
+{
+ scan->state = STRING;
+ scan->string_p = 1;
+ _csi_buffer_reset (&scan->buffer);
+}
+
+static void
+string_inc_p (csi_scanner_t *scan)
+{
+ scan->string_p++;
+}
+
+static int
+string_dec_p (csi_scanner_t *scan)
+{
+ return --scan->string_p == 0;
+}
+
+static void
+string_add (csi_t *ctx, csi_scanner_t *scan, int c)
+{
+ if (_csi_likely (_csi_buffer_check (ctx, &scan->buffer, 1)))
+ _csi_buffer_add (&scan->buffer, c);
+}
+
+static void
+string_end (csi_t *ctx, csi_scanner_t *scan)
+{
+ csi_object_t obj;
+
+ scan->status = scan->buffer.status;
+ if (_csi_unlikely (scan->status))
+ return;
+
+ scan->status = csi_string_new (ctx,
+ &obj,
+ scan->buffer.base,
+ scan->buffer.ptr - scan->buffer.base);
+ if (_csi_unlikely (scan->status))
+ return;
+
+ if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL)
+ scan->status = csi_array_append (ctx,
+ scan->build_procedure.datum.array,
+ &obj);
+ else
+ scan->status = _csi_push_ostack (ctx, &obj);
+
+ reset (scan);
+}
+
+static void
+hex_start (csi_scanner_t *scan)
+{
+ scan->state = HEX;
+ scan->accumulator_count = 0;
+ scan->accumulator = 0;
+
+ _csi_buffer_reset (&scan->buffer);
+}
+
+static int
+hex_value (int c)
+{
+ if (c < '0')
+ return EOF;
+ if (c <= '9')
+ return c - '0';
+ c |= 32;
+ if (c < 'a')
+ return EOF;
+ if (c <= 'f')
+ return c - 'a' + 0xa;
+ return EOF;
+}
+
+static void
+hex_add (csi_t *ctx, csi_scanner_t *scan, int c)
+{
+ if (scan->accumulator_count == 0) {
+ scan->accumulator |= hex_value (c) << 4;
+ scan->accumulator_count = 1;
+ } else {
+ scan->accumulator |= hex_value (c) << 0;
+ if (_csi_likely (_csi_buffer_check (ctx, &scan->buffer, 1)))
+ _csi_buffer_add (&scan->buffer, scan->accumulator);
+ scan->accumulator = 0;
+ scan->accumulator_count = 0;
+ }
+}
+
+static void
+hex_end (csi_t *ctx, csi_scanner_t *scan)
+{
+ csi_object_t obj;
+
+ if (scan->accumulator_count)
+ hex_add (ctx, scan, '0');
+
+ scan->status = scan->buffer.status;
+ if (_csi_unlikely (scan->status))
+ return;
+
+ scan->status = csi_string_new (ctx,
+ &obj,
+ scan->buffer.base,
+ scan->buffer.ptr - scan->buffer.base);
+ if (_csi_unlikely (scan->status))
+ return;
+
+ if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL)
+ scan->status = csi_array_append (ctx,
+ scan->build_procedure.datum.array,
+ &obj);
+ else
+ scan->status = _csi_push_ostack (ctx, &obj);
+
+ reset (scan);
+}
+
+static void
+base85_start (csi_scanner_t *scan)
+{
+ scan->state = BASE85;
+ scan->accumulator = 0;
+ scan->accumulator_count = 0;
+
+ _csi_buffer_reset (&scan->buffer);
+}
+
+static void
+base85_add (csi_t *ctx, csi_scanner_t *scan, int c)
+{
+ if (c == 'z') {
+ if (_csi_unlikely (scan->accumulator_count != 0)) {
+ scan->status = _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ return;
+ }
+ if (_csi_likely (_csi_buffer_check (ctx, &scan->buffer, 4))) {
+ _csi_buffer_add (&scan->buffer, 0);
+ _csi_buffer_add (&scan->buffer, 0);
+ _csi_buffer_add (&scan->buffer, 0);
+ _csi_buffer_add (&scan->buffer, 0);
+ }
+ } else if (_csi_unlikely (c < '!' || c > 'u')) {
+ scan->status = _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ return;
+ } else {
+ scan->accumulator = scan->accumulator*85 + c - '!';
+ if (++scan->accumulator_count == 5) {
+ if (_csi_likely (_csi_buffer_check (ctx, &scan->buffer, 4))) {
+ _csi_buffer_add (&scan->buffer,
+ (scan->accumulator >> 24) & 0xff);
+ _csi_buffer_add (&scan->buffer,
+ (scan->accumulator >> 16) & 0xff);
+ _csi_buffer_add (&scan->buffer,
+ (scan->accumulator >> 8) & 0xff);
+ _csi_buffer_add (&scan->buffer,
+ (scan->accumulator >> 0) & 0xff);
+ }
+
+ scan->accumulator = 0;
+ scan->accumulator_count = 0;
+ }
+ }
+}
+
+static void
+base85_end (csi_t *ctx, csi_scanner_t *scan)
+{
+ csi_object_t obj;
+
+ if (_csi_unlikely (! _csi_buffer_check (ctx, &scan->buffer, 4))) {
+ scan->status = scan->buffer.status;
+ return;
+ }
+
+ switch (scan->accumulator_count) {
+ case 0:
+ break;
+ case 1:
+ scan->status = _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ break;
+
+ case 2:
+ scan->accumulator = scan->accumulator * (85*85*85) + 85*85*85 -1;
+ _csi_buffer_add (&scan->buffer, (scan->accumulator >> 24) & 0xff);
+ break;
+ case 3:
+ scan->accumulator = scan->accumulator * (85*85) + 85*85 -1;
+ _csi_buffer_add (&scan->buffer, (scan->accumulator >> 24) & 0xff);
+ _csi_buffer_add (&scan->buffer, (scan->accumulator >> 16) & 0xff);
+ break;
+ case 4:
+ scan->accumulator = scan->accumulator * 85 + 84;
+ _csi_buffer_add (&scan->buffer, (scan->accumulator >> 24) & 0xff);
+ _csi_buffer_add (&scan->buffer, (scan->accumulator >> 16) & 0xff);
+ _csi_buffer_add (&scan->buffer, (scan->accumulator >> 8) & 0xff);
+ break;
+ }
+
+ scan->status = csi_string_new (ctx,
+ &obj,
+ scan->buffer.base,
+ scan->buffer.ptr - scan->buffer.base);
+ if (_csi_unlikely (scan->status))
+ return;
+
+ if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL)
+ scan->status = csi_array_append (ctx,
+ scan->build_procedure.datum.array,
+ &obj);
+ else
+ scan->status = _csi_push_ostack (ctx, &obj);
+
+ reset (scan);
+}
+
+static int
+scan_none (csi_t *ctx,
+ csi_scanner_t *scan,
+ csi_file_t *src)
+{
+ int c, next;
+ union {
+ int i;
+ float f;
+ } u;
+
+ while ((c = scan_getc (scan, src)) != EOF) {
+ csi_object_t obj = { CSI_OBJECT_TYPE_NULL };
+
+ switch (c) {
+ case 0x0:
+ case 0x9:
+ case 0xa:
+ case 0xc:
+ case 0xd:
+ case 0x20: /* ignore whitespace */
+ break;
+
+ case '%':
+ comment_start (scan);
+ return 1;
+
+ case '(':
+ string_start (scan);
+ return 1;
+
+ case '[': /* needs special case */
+ case ']':
+ case '{':
+ case '}':
+ token_start (scan);
+ token_add_unchecked (scan, c);
+ token_end (ctx, scan, src);
+ return 1;
+
+ case '<':
+ next = scan_getc (scan, src);
+ switch (next) {
+ case EOF:
+ scan_putc (scan, src, '<');
+ return 0;
+ case '<':
+ /* dictionary name */
+ token_start (scan);
+ token_add_unchecked (scan, '<');
+ token_add_unchecked (scan, '<');
+ token_end (ctx, scan, src);
+ return 1;
+ case '~':
+ base85_start (scan);
+ return 1;
+ default:
+ scan_putc (scan, src, next);
+ hex_start (scan);
+ return 1;
+ }
+ break;
+
+ /* binary token */
+ case 128:
+ case 129:
+ case 130:
+ case 131:
+ /* binary object sequence */
+ break;
+ case 132: /* 32-bit integer, MSB */
+ break;
+ case 133: /* 32-bit integer, LSB */
+ break;
+ case 134: /* 16-bit integer, MSB */
+ break;
+ case 135: /* 16-bit integer, LSB */
+ break;
+ case 136: /* 8-bit integer */
+ break;
+ case 137: /* 16/32-bit fixed point */
+ break;
+ case 138: /* 32-bit real, MSB */
+ scan_read (scan, src, &u.i, 4);
+#if ! WORDS_BIGENDIAN
+ u.i = bswap_32 (u.i);
+#endif
+ scan->status = csi_real_new (ctx, &obj, u.f);
+ break;
+ case 139: /* 32-bit real, LSB */
+ scan_read (scan, src, &u.f, 4);
+#if WORDS_BIGENDIAN
+ u.i = bswap_32 (u.i);
+#endif
+ scan->status = csi_real_new (ctx, &obj, u.f);
+ break;
+ case 140: /* 32-bit real, native */
+ scan_read (scan, src, &u.f, 4);
+ scan->status = csi_real_new (ctx, &obj, u.f);
+ break;
+ case 141: /* boolean */
+ break;
+ case 142: /* string of length 1n */
+ break;
+ case 143: /* string of length 2n (MSB) */
+ break;
+ case 144: /* string of length 2n (LSB) */
+ break;
+ case 145: /* literal system name */
+ break;
+ case 146: /* executable system name */
+ break;
+ case 147: /* reserved */
+ break;
+ case 148: /* reserved */
+ break;
+ case 149: /* homogeneous array */
+ break;
+
+ /* unassigned */
+ case 150:
+ case 151:
+ case 152:
+ case 153:
+ case 154:
+ case 155:
+ case 156:
+ case 157:
+ case 158:
+ case 159:
+ scan->status = _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ return 0;
+
+ case '#': /* PDF 1.2 escape code */
+ {
+ int c_hi = scan_getc (scan, src);
+ int c_lo = scan_getc (scan, src);
+ c = (hex_value (c_hi) << 4) | hex_value (c_lo);
+ }
+ /* fall-through */
+ default:
+ token_start (scan);
+ token_add_unchecked (scan, c);
+ return 1;
+ }
+
+ if (obj.type != CSI_OBJECT_TYPE_NULL) {
+ if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL)
+ scan->status = csi_array_append (ctx,
+ scan->build_procedure.datum.array,
+ &obj);
+ else
+ scan->status = csi_object_execute (ctx, &obj);
+ }
+ }
+
+ return 0;
+}
+
+static int
+scan_token (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
+{
+ int c;
+
+ while ((c = scan_getc (scan, src)) != EOF) {
+ switch (c) {
+ case 0x0:
+ case 0x9:
+ case 0xa:
+ case 0xc:
+ case 0xd:
+ case 0x20:
+ token_end (ctx, scan, src);
+ return 1;
+
+ /* syntax delimiters */
+ case '%':
+ token_end (ctx, scan, src);
+ comment_start (scan);
+ return 1;
+ /* syntax error? */
+ case '(':
+ token_end (ctx, scan, src);
+ string_start (scan);
+ return 1;
+ /* XXX syntax error? */
+ case ')':
+ token_end (ctx, scan, src);
+ return 1;
+ case '/':
+ /* need to special case '^//?' */
+ if (scan->buffer.ptr > scan->buffer.base+1 ||
+ scan->buffer.base[0] != '/')
+ {
+ token_end (ctx, scan, src);
+ token_start (scan);
+ }
+ token_add_unchecked (scan, '/');
+ return 1;
+
+ case '{':
+ case '}':
+ case ']':
+ token_end (ctx, scan, src);
+ token_start (scan);
+ token_add_unchecked (scan, c);
+ token_end (ctx, scan, src);
+ return 1;
+
+ case '<':
+ scan_putc (scan, src, '<');
+ token_end (ctx, scan, src);
+ return 1;
+
+ case '#': /* PDF 1.2 escape code */
+ {
+ int c_hi = scan_getc (scan, src);
+ int c_lo = scan_getc (scan, src);
+ c = (hex_value (c_hi) << 4) | hex_value (c_lo);
+ }
+ /* fall-through */
+ default:
+ token_add (ctx, scan, c);
+ break;
+ }
+ }
+ token_end (ctx, scan, src);
+
+ return 0;
+}
+
+static int
+scan_hex (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
+{
+ int c;
+
+ while ((c = scan_getc (scan, src)) != EOF) {
+ switch (c) {
+ case 0x0:
+ case 0x9:
+ case 0xa:
+ case 0xc:
+ case 0xd:
+ case 0x20: /* ignore whitespace */
+ break;
+
+ case '>':
+ hex_end (ctx, scan); /* fixup odd digit with '0' */
+ return 1;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ hex_add (ctx, scan, c);
+ break;
+
+ default:
+ scan->status = _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ return 0;
+ }
+ }
+
+ scan->status = _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ return 0;
+}
+
+static int
+scan_base85 (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
+{
+ int c, next;
+
+ while ((c = scan_getc (scan, src)) != EOF) {
+ switch (c) {
+ case '~':
+ next = scan_getc (scan, src);
+ switch (next) {
+ case EOF:
+ return 0;
+
+ case '>':
+ base85_end (ctx, scan);
+ return 1;
+ }
+ scan_putc (scan, src, next);
+
+ /* fall-through */
+ default:
+ base85_add (ctx, scan, c);
+ break;
+ }
+ }
+
+ scan->status = _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ return 0;
+}
+
+static int
+scan_string (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
+{
+ int c, next;
+
+ while ((c = scan_getc (scan, src)) != EOF) {
+ switch (c) {
+ case '\\': /* escape */
+ next = scan_getc (scan, src);
+ switch (next) {
+ case EOF:
+ return 0;
+
+ case 'n':
+ string_add (ctx, scan, '\n');
+ break;
+ case 'r':
+ string_add (ctx, scan, '\r');
+ break;
+ case 't':
+ string_add (ctx, scan, '\r');
+ break;
+ case 'b':
+ string_add (ctx, scan, '\b');
+ break;
+ case 'f':
+ string_add (ctx, scan, '\f');
+ break;
+ case '\\':
+ string_add (ctx, scan, '\\');
+ break;
+ case '(':
+ string_add (ctx, scan, '(');
+ break;
+ case ')':
+ string_add (ctx, scan, ')');
+ break;
+
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ { /* octal code: \d{1,3} */
+ int i;
+
+ c = next - '0';
+
+ for (i = 0; i < 2; i++) {
+ next = scan_getc (scan, src);
+ switch (next) {
+ case EOF:
+ return 0;
+
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ c = 8*c + next-'0';
+ break;
+
+ default:
+ scan_putc (scan, src, next);
+ goto octal_code_done;
+ }
+ }
+ octal_code_done:
+ string_add (ctx, scan, c);
+ }
+ break;
+
+ case 0xa:
+ /* skip the newline */
+ next = scan_getc (scan, src); /* might be compound LFCR */
+ switch (next) {
+ case EOF:
+ return 0;
+ case 0xc:
+ break;
+ default:
+ scan_putc (scan, src, next);
+ break;
+ }
+ break;
+ case 0xc:
+ break;
+
+ default:
+ /* ignore the '\' */
+ break;
+ }
+ break;
+
+ case '(':
+ string_inc_p (scan);
+ string_add (ctx, scan, c);
+ break;
+
+ case ')':
+ if (string_dec_p (scan)) {
+ string_end (ctx, scan);
+ return 1;
+ } else
+ string_add (ctx, scan, c);
+ break;
+
+ default:
+ string_add (ctx, scan, c);
+ break;
+ }
+ }
+
+ scan->status = _csi_error (CSI_STATUS_INVALID_SCRIPT);
+ return 0;
+}
+
+static int
+scan_comment (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
+{
+ int c;
+
+ /* discard until newline */
+ while ((c = scan_getc (scan, src)) != EOF) {
+ switch (c) {
+ case 0xa:
+ case 0xc:
+ comment_end (scan);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+csi_status_t
+_csi_scan_file (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
+{
+ static int (* const func[]) (csi_t *, csi_scanner_t *, csi_file_t *) = {
+ scan_none,
+ scan_token,
+ scan_comment,
+ scan_string,
+ scan_hex,
+ scan_base85,
+ };
+
+ while (func[scan->state] (ctx, scan, src))
+ ;
+
+ return scan->status;
+}
+
+#if 0
+cairo_status_t
+_csi_tokenize_string (csi_t *ctx,
+ const char *code, int len,
+ csi_object_t **array_out)
+{
+ csi_scanner_t scan;
+ csi_object_t *src;
+ cairo_status_t status;
+
+ status = _csi_scanner_init (&scan, ctx);
+ if (status)
+ return status;
+
+ scan.build_procedure = csi_array_new (ctx, 0);
+ if (scan.build_procedure == NULL)
+ goto CLEANUP_SCAN;
+ csi_object_set_literal (scan.build_procedure, FALSE);
+
+ src = csi_file_new_for_string (ctx, (const uint8_t *) code, len);
+ if (src == NULL) {
+ status = _csi_error (CSI_STATUS_NO_MEMORY);
+ goto CLEANUP_SCAN;
+ }
+
+ status = _csi_scan_object (&scan, src);
+ if (status)
+ goto CLEANUP_SRC;
+
+ *array_out = scan.build_procedure;
+ scan.build_procedure = NULL;
+
+CLEANUP_SRC:
+ csi_object_free (src);
+
+CLEANUP_SCAN:
+ _csi_scanner_fini (&scan);
+
+ return status;
+}
+#endif
+
+csi_status_t
+_csi_scanner_init (csi_t *ctx, csi_scanner_t *scanner)
+{
+ csi_status_t status;
+
+ memset (scanner, 0, sizeof (csi_scanner_t));
+
+ status = _csi_buffer_init (ctx, &scanner->buffer);
+ if (status)
+ return status;
+
+ status = _csi_stack_init (ctx, &scanner->procedure_stack, 4);
+ if (status)
+ return status;
+
+ reset (scanner);
+
+ return CSI_STATUS_SUCCESS;
+}
+
+void
+_csi_scanner_fini (csi_t *ctx, csi_scanner_t *scanner)
+{
+ _csi_buffer_fini (ctx, &scanner->buffer);
+ _csi_stack_fini (ctx, &scanner->procedure_stack);
+ if (scanner->build_procedure.type != CSI_OBJECT_TYPE_NULL)
+ csi_object_free (ctx, &scanner->build_procedure);
+}
diff --git a/util/cairo-script/cairo-script-stack.c b/util/cairo-script/cairo-script-stack.c
new file mode 100644
index 00000000..bc1d889e
--- /dev/null
+++ b/util/cairo-script/cairo-script-stack.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright © 2008 Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Chris Wilson.
+ *
+ * Contributor(s):
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "cairo-script-private.h"
+
+#include <string.h>
+
+csi_status_t
+_csi_stack_init (csi_t *ctx, csi_stack_t *stack, csi_integer_t size)
+{
+ csi_status_t status = CSI_STATUS_SUCCESS;
+
+ stack->len = 0;
+ stack->size = size;
+ /* assert ((unsigned) size < INT32_MAX / sizeof (csi_object_t)); */
+ stack->objects = _csi_alloc (ctx, stack->size * sizeof (csi_object_t));
+ if (_csi_unlikely (stack->objects == NULL))
+ status = _csi_error (CSI_STATUS_NO_MEMORY);
+
+ return status;
+}
+
+void
+_csi_stack_fini (csi_t *ctx, csi_stack_t *stack)
+{
+ csi_integer_t n;
+
+ for (n = 0; n < stack->len; n++)
+ csi_object_free (ctx, &stack->objects[n]);
+
+ _csi_free (ctx, stack->objects);
+}
+
+csi_status_t
+_csi_stack_roll (csi_t *ctx,
+ csi_stack_t *stack,
+ csi_integer_t mod, csi_integer_t n)
+{
+ csi_object_t stack_copy[128];
+ csi_object_t *copy;
+ csi_integer_t last, i, len;
+
+ switch (mod) { /* special cases */
+ case 1:
+ last = stack->len - 1;
+ stack_copy[0] = stack->objects[last];
+ for (i = last; --n; i--)
+ stack->objects[i] = stack->objects[i-1];
+ stack->objects[i] = stack_copy[0];
+ return CSI_STATUS_SUCCESS;
+ case -1:
+ last = stack->len - 1;
+ stack_copy[0] = stack->objects[i = last - n + 1];
+ for (; --n; i++)
+ stack->objects[i] = stack->objects[i+1];
+ stack->objects[i] = stack_copy[0];
+ return CSI_STATUS_SUCCESS;
+ }
+
+ /* fall back to a copy */
+ if (n > ARRAY_LENGTH (stack_copy)) {
+ if (_csi_unlikely ((unsigned) n > INT32_MAX / sizeof (csi_object_t)))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ copy = _csi_alloc (ctx, n * sizeof (csi_object_t));
+ if (copy == NULL)
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+ } else
+ copy = stack_copy;
+
+ i = stack->len - n;
+ memcpy (copy, stack->objects + i, n * sizeof (csi_object_t));
+ mod = -mod;
+ if (mod < 0)
+ mod += n;
+ last = mod;
+ for (len = n; n--; i++) {
+ stack->objects[i] = copy[last];
+ if (++last == len)
+ last = 0;
+ }
+
+ if (copy != stack_copy)
+ _csi_free (ctx, copy);
+
+ return CSI_STATUS_SUCCESS;
+}
+
+csi_status_t
+_csi_stack_grow (csi_t *ctx, csi_stack_t *stack, csi_integer_t cnt)
+{
+ csi_integer_t newsize;
+ csi_object_t *newstack;
+
+ if (_csi_likely (cnt <= stack->size))
+ return CSI_STATUS_SUCCESS;
+ if (_csi_unlikely ((unsigned) cnt >= INT32_MAX / sizeof (csi_object_t)))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+
+ newsize = stack->size;
+ do {
+ newsize *= 2;
+ } while (newsize <= cnt);
+
+ newstack = _csi_realloc (ctx,
+ stack->objects,
+ newsize * sizeof (csi_object_t));
+ if (_csi_unlikely (newstack == NULL))
+ return _csi_error (CSI_STATUS_NO_MEMORY);
+
+ stack->objects = newstack;
+ stack->size = newsize;
+
+ return CSI_STATUS_SUCCESS;
+}
+
+csi_status_t
+_csi_stack_push (csi_t *ctx, csi_stack_t *stack, const csi_object_t *obj)
+{
+ if (_csi_unlikely (stack->len == stack->size)) {
+ csi_status_t status;
+
+ status = _csi_stack_grow (ctx, stack, stack->size + 1);
+ if (status)
+ return status;
+ }
+
+ stack->objects[stack->len++] = *obj;
+ return CSI_STATUS_SUCCESS;
+}
+
+csi_object_t *
+_csi_stack_peek (csi_stack_t *stack, csi_integer_t i)
+{
+ if (_csi_unlikely (stack->len < i))
+ return NULL;
+
+ return &stack->objects[stack->len - i -1];
+}
+
+void
+_csi_stack_pop (csi_t *ctx, csi_stack_t *stack, csi_integer_t count)
+{
+ if (_csi_unlikely (stack->len < count))
+ count = stack->len;
+
+ while (count--)
+ csi_object_free (ctx, &stack->objects[--stack->len]);
+}
+
+csi_status_t
+_csi_stack_exch (csi_stack_t *stack)
+{
+ csi_object_t tmp;
+ csi_integer_t n;
+
+ if (_csi_unlikely (stack->len < 2))
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ n = stack->len - 1;
+ tmp = stack->objects[n];
+ stack->objects[n] = stack->objects[n - 1];
+ stack->objects[n - 1] = tmp;
+
+ return CSI_STATUS_SUCCESS;
+}
diff --git a/util/cairo-script/csi-replay.c b/util/cairo-script/csi-replay.c
new file mode 100644
index 00000000..e5a847e4
--- /dev/null
+++ b/util/cairo-script/csi-replay.c
@@ -0,0 +1,93 @@
+#include <cairo.h>
+#include <cairo-script-interpreter.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static const cairo_user_data_key_t _key;
+
+#if CAIRO_HAS_XLIB_XRENDER_SURFACE
+#include <cairo-xlib.h>
+#include <cairo-xlib-xrender.h>
+
+static Display *
+_get_display (void)
+{
+ static Display *dpy;
+
+ if (dpy != NULL)
+ return dpy;
+
+ dpy = XOpenDisplay (NULL);
+ if (dpy == NULL) {
+ fprintf (stderr, "Failed to open display.\n");
+ exit (1);
+ }
+
+ return dpy;
+}
+
+static void
+_destroy_window (void *closure)
+{
+ XFlush (_get_display ());
+ XDestroyWindow (_get_display(), (Window) closure);
+}
+
+static cairo_surface_t *
+_surface_create (void *closure,
+ double width, double height)
+{
+ Display *dpy;
+ Visual *visual;
+ XRenderPictFormat *xrender_format;
+ XSetWindowAttributes attr;
+ Window w;
+ cairo_surface_t *surface;
+
+ dpy = _get_display ();
+
+ visual = DefaultVisual (dpy, DefaultScreen (dpy));
+ xrender_format = XRenderFindVisualFormat (dpy, visual);
+ if (xrender_format == NULL) {
+ fprintf (stderr, "X server does not have the Render extension.\n");
+ exit (1);
+ }
+
+ attr.override_redirect = True;
+ w = XCreateWindow (dpy, DefaultRootWindow (dpy), 0, 0,
+ width, height, 0, xrender_format->depth,
+ InputOutput, visual, CWOverrideRedirect, &attr);
+ XMapWindow (dpy, w);
+
+ surface = cairo_xlib_surface_create_with_xrender_format (dpy, w,
+ DefaultScreenOfDisplay (dpy),
+ xrender_format,
+ width, height);
+ cairo_surface_set_user_data (surface, &_key, (void *) w, _destroy_window);
+
+ return surface;
+}
+#else
+/* fallback: just use an image surface */
+static cairo_surface_t *
+_surface_create (void *closure,
+ double width, double height)
+{
+ return cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+}
+#endif
+
+int
+main (int argc, char **argv)
+{
+ cairo_script_interpreter_t *csi;
+ const cairo_script_interpreter_hooks_t hooks = {
+ .surface_create = _surface_create
+ };
+
+ csi = cairo_script_interpreter_create ();
+ cairo_script_interpreter_install_hooks (csi, &hooks);
+ cairo_script_interpreter_run (csi, argv[1]);
+ return cairo_script_interpreter_destroy (csi);
+}
diff --git a/util/cairo-trace/Makefile.am b/util/cairo-trace/Makefile.am
index 13161c6d..50bd255e 100644
--- a/util/cairo-trace/Makefile.am
+++ b/util/cairo-trace/Makefile.am
@@ -1,5 +1,8 @@
+cairolibdir = $(libdir)/cairo
+cairooutdir = $(localstatedir)/lib/cairo-trace
+
bin_SCRIPTS = cairo-trace
-lib_LTLIBRARIES = cairo-trace.la
+cairolib_LTLIBRARIES = cairo-trace.la
AM_CPPFLAGS = -I$(top_srcdir)/src \
-I$(top_builddir)/src
@@ -8,15 +11,19 @@ cairo_trace_la_SOURCES = \
lookup-symbol.c \
lookup-symbol.h \
trace.c
-cairo_trace_la_CFLAGS = @FREETYPE_CFLAGS@ @CAIRO_CFLAGS@
+cairo_trace_la_CPPFLAGS = -DCAIRO_TRACE_OUTDIR="\"$(cairooutdir)\"" \
+ $(AM_CPPFLAGS)
+cairo_trace_la_CFLAGS = $(CAIRO_CFLAGS)
cairo_trace_la_LDFLAGS = -module -no-undefined
-cairo_trace_la_LIBADD = -ldl -lz -lbfd
+cairo_trace_la_LIBADD = -ldl -lz $(BFD_LIBS)
+
-system-install:
- grep -sq @libdir@/cairo-trace.so /etc/ld.so.preload || echo @libdir@/cairo-trace.so >> /etc/ld.so.preload
+system-install: install
+ mkdir -p $(cairooutdir)
+ grep -sq $(cairolibdir)/cairo-trace.so /etc/ld.so.preload || echo $(cairolibdir)/cairo-trace.so >> /etc/ld.so.preload
-system-uninstall:
- sed -e '/\/usr\/local\/lib\/cairo-trace.so/d' < /etc/ld.so.preload > /tmp/ld.so.preload && mv /tmp/ld.so.preload /etc/ld.so.preload;
+system-uninstall: uninstall
+ sed -e '/cairo-trace.so/d' < /etc/ld.so.preload > /tmp/ld.so.preload && mv /tmp/ld.so.preload /etc/ld.so.preload;
EXTRA_DIST = \
COPYING \
diff --git a/util/cairo-trace/cairo-trace.in b/util/cairo-trace/cairo-trace.in
index ee381614..cab40823 100644
--- a/util/cairo-trace/cairo-trace.in
+++ b/util/cairo-trace/cairo-trace.in
@@ -4,20 +4,56 @@ prefix=@prefix@
exec_prefix=@exec_prefix@
nofile=
-silent=
+verbose=
+flush=
+nocallers=
+
+usage() {
+cat << EOF
+usage: cairo-trace [--no-file|--verbose] command
+cairo-trace will generate a log of all calls made by command to
+cairo. This log will be stored in a file in the local directory
+called command.pid.trace.
+Whatever else happens is driven by its argument:
+ --flush - Flush the output trace after every call.
+ --verbose - Show the trace on stdout.
+ --no-file - Disable the creation of an output file.
+ --no-callers - Do not lookup the caller address/symbol/line whilst tracing.
+
+Enviroment variables understood by cairo-trace:
+ CAIRO_TRACE_FLUSH - flush the output after every function call.
+ CAIRO_TRACE_LINE_INFO - emit line information for most function calls.
+EOF
+exit
+}
skip=1
while test $skip -eq 1; do
skip=0
case $1 in
- --silent)
+ --verbose)
+ skip=1
+ verbose=1
+ ;;
+ --flush)
skip=1
- silent=1
+ flush=1
;;
--no-file)
skip=1
nofile=1
;;
+ --no-callers)
+ skip=1
+ nocallers=1
+ ;;
+ --version)
+ echo "cairo-trace, version @CAIRO_VERSION_MAJOR@.@CAIRO_VERSION_MINOR@.@CAIRO_VERSION_MICRO@."
+ exit
+ ;;
+ --help)
+ usage
+ ;;
esac
if test $skip -eq 1; then
shift
@@ -25,34 +61,38 @@ while test $skip -eq 1; do
done
if test $# -eq 0; then
-cat << EOF
-usage: cairo-trace [--no-file|--silent] command
-cairo-trace will generate a log of all calls made by command to
-cairo. This log will be stored in a file in the local directory
-called command.pid.trace.
-Whatever else happens is driven by its argument:
- --silent - disables the overriding of stdout by cairo-trace.
- The trace file is still generated, but your application
- is free to continue to use stdout.
- --no-file - disables the generation of an output file
-
-Enviroment variables understood by cairo-trace:
- CAIRO_TRACE_FLUSH - flush the output after every function call.
-EOF
-exit
+ usage
fi
#echo $*
filename=""
if test -z "$nofile"; then
- filename=`basename $1`.$$.trace
+ filename=`basename -- $1`.$$.trace
+fi
+
+LD_PRELOAD=@libdir@/cairo/cairo-trace.so
+export LD_PRELOAD
+
+# Force the decimal output to the 'C' locale
+LC_ALL=C
+export LC_ALL
+
+if test -n "$nocallers"; then
+ CAIRO_TRACE_LINE_INFO=0
+ export CAIRO_TRACE_LINE_INFO
+fi
+
+if test -n "$flush"; then
+ CAIRO_TRACE_FLUSH=1
+ export CAIRO_TRACE_FLUSH
fi
if test -z "$filename"; then
- LD_PRELOAD=@libdir@/cairo-trace.so CAIRO_TRACE_FD=3 LC_ALL=C $* 3>&1 >/dev/null
-elif test -n "$silent"; then
- LD_PRELOAD=@libdir@/cairo-trace.so LC_ALL=C CAIRO_TRACE_OUTFILE_EXACT=$filename $*
+ CAIRO_TRACE_FD=3 $* 3>&1 >/dev/null
+elif test -z "$verbose"; then
+ echo "Recording trace in $filename."
+ CAIRO_TRACE_OUTFILE_EXACT=$filename $*
else
- LD_PRELOAD=@libdir@/cairo-trace.so CAIRO_TRACE_FD=3 LC_ALL=C $* 3>&1 >/dev/null | tee $filename
+ CAIRO_TRACE_FD=3 $* 3>&1 >/dev/null | tee $filename
fi
diff --git a/util/cairo-trace/lookup-symbol.c b/util/cairo-trace/lookup-symbol.c
index b5f0fdfd..eb1a656d 100644
--- a/util/cairo-trace/lookup-symbol.c
+++ b/util/cairo-trace/lookup-symbol.c
@@ -61,8 +61,9 @@
#include <stdlib.h>
#include <link.h>
#include <string.h>
+#include <pthread.h>
-#ifdef HAVE_LIBBFD
+#if HAVE_BFD
#include <bfd.h>
#include <libiberty.h>
@@ -177,43 +178,38 @@ _symbol_init (struct symbol *symbol, struct symtab *symtab, bfd_vma addr)
symbol->pc = addr;
}
-static int
+static void
_symbol_print (struct symbol *symbol, char *buf, int buflen, const char *filename)
{
- if (! symbol->found) {
- buflen = snprintf (buf, buflen,
- "[0x%llx] \?\?() \?\?:0",
- (long long unsigned int) symbol->pc);
- } else {
- const char *name, *h;
- char path[1024];
-
- name = symbol->functionname;
- if (name == NULL || *name == '\0')
- name = "??";
-
- if (symbol->filename != NULL)
- filename = symbol->filename;
- if (strcmp (filename, "/proc/self/exe") == 0) {
- int len = readlink ("/proc/self/exe", path, sizeof (path) - 1);
- if (len != -1) {
- path[len] = '\0';
- filename = path;
- }
- }
- h = strrchr (filename, '/');
- if (h != NULL)
- filename = h + 1;
-
- if (symbol->line) {
- buflen = snprintf (buf, buflen, "%s (%s:%u)",
- name, filename, symbol->line);
- } else {
- buflen = snprintf (buf, buflen, "%s (%s)", name, filename);
+ const char *name, *h;
+ char path[1024];
+
+ if (! symbol->found)
+ return;
+
+ name = symbol->functionname;
+ if (name == NULL || *name == '\0')
+ name = "??";
+
+ if (symbol->filename != NULL)
+ filename = symbol->filename;
+ if (strcmp (filename, "/proc/self/exe") == 0) {
+ int len = readlink ("/proc/self/exe", path, sizeof (path) - 1);
+ if (len != -1) {
+ path[len] = '\0';
+ filename = path;
}
}
+ h = strrchr (filename, '/');
+ if (h != NULL)
+ filename = h + 1;
- return buflen;
+ if (symbol->line) {
+ snprintf (buf, buflen, "%s() [%s:%u]",
+ name, filename, symbol->line);
+ } else {
+ snprintf (buf, buflen, "%s() [%s]", name, filename);
+ }
}
#endif
@@ -251,40 +247,86 @@ find_matching_file (struct dl_phdr_info *info, size_t size, void *data)
return 0;
}
+struct symbol_cache_entry {
+ const void *ptr;
+ struct symbol_cache_entry *hash_prev, *hash_next;
+ char name[0];
+};
+
+static struct symbol_cache_entry *symbol_cache_hash[13477];
+static pthread_mutex_t symbol_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
+
char *
lookup_symbol (char *buf, int buflen, const void *ptr)
{
struct file_match match;
-#ifdef HAVE_LIBBFD
+#if HAVE_BFD
struct symtab symtab;
struct symbol symbol;
#endif
- int i;
+ struct symbol_cache_entry *cache;
+ int bucket;
+ int len;
+
+ bucket = (unsigned long) ptr % (sizeof (symbol_cache_hash) / sizeof (symbol_cache_hash[0]));
+ pthread_mutex_lock (&symbol_cache_mutex);
+ for (cache = symbol_cache_hash[bucket];
+ cache != NULL;
+ cache = cache->hash_next)
+ {
+ if (cache->ptr == ptr) {
+ if (cache->hash_prev != NULL) {
+ cache->hash_prev->hash_next = cache->hash_next;
+ if (cache->hash_next != NULL)
+ cache->hash_next->hash_prev = cache->hash_prev;
+ cache->hash_prev = NULL;
+ cache->hash_next = symbol_cache_hash[bucket];
+ symbol_cache_hash[bucket]->hash_prev = cache;
+ symbol_cache_hash[bucket] = cache;
+ }
+
+ pthread_mutex_unlock (&symbol_cache_mutex);
+ return cache->name;
+ }
+ }
+ pthread_mutex_unlock (&symbol_cache_mutex);
+ match.file = NULL;
match.address = (ElfW(Addr)) ptr;
dl_iterate_phdr (find_matching_file, &match);
- i = snprintf (buf, buflen,
- "0x%llx",
- (long long unsigned int) match.address);
+ snprintf (buf, buflen, "0x%llx",
+ (long long unsigned int) match.address);
if (match.file == NULL || *match.file == '\0')
match.file = "/proc/self/exe";
-#ifdef HAVE_LIBBFD
- if (! _symtab_init (&symtab, match.file))
- return buf;
+#if HAVE_BFD
+ if (_symtab_init (&symtab, match.file)) {
+ _symbol_init (&symbol, &symtab, match.address - match.base);
+ bfd_map_over_sections (symtab.bfd, find_address_in_section, &symbol);
+ if (symbol.found)
+ _symbol_print (&symbol, buf, buflen, match.file);
+ _symbol_fini (&symbol);
- _symbol_init (&symbol, &symtab, match.address - match.base);
- bfd_map_over_sections (symtab.bfd, find_address_in_section, &symbol);
- if (symbol.found) {
- buf[i++] = ' ';
- _symbol_print (&symbol, buf + i, buflen - i, match.file);
+ _symtab_fini (&symtab);
}
- _symbol_fini (&symbol);
-
- _symtab_fini (&symtab);
#endif
+ len = strlen (buf);
+ cache = malloc (sizeof (struct symbol_cache_entry) + len + 1);
+ if (cache != NULL) {
+ cache->ptr = ptr;
+ memcpy (cache->name, buf, len + 1);
+
+ pthread_mutex_lock (&symbol_cache_mutex);
+ cache->hash_prev = NULL;
+ cache->hash_next = symbol_cache_hash[bucket];
+ if (symbol_cache_hash[bucket] != NULL)
+ symbol_cache_hash[bucket]->hash_prev = cache;
+ symbol_cache_hash[bucket] = cache;
+ pthread_mutex_unlock (&symbol_cache_mutex);
+ }
+
return buf;
}
diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c
index 548eb694..b272dd89 100644
--- a/util/cairo-trace/trace.c
+++ b/util/cairo-trace/trace.c
@@ -31,16 +31,35 @@
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
-#include <byteswap.h>
#include <zlib.h>
#include <math.h>
#include <ctype.h>
#include <cairo.h>
-#ifdef CAIRO_HAS_FT_FONT
+#if CAIRO_HAS_FT_FONT
# include <cairo-ft.h>
#endif
+#ifndef CAIRO_TRACE_OUTDIR
+#define CAIRO_TRACE_OUTDIR "."
+#endif
+
+#if HAVE_BYTESWAP_H
+# include <byteswap.h>
+#endif
+#ifndef bswap_16
+# define bswap_16(p) \
+ (((((uint16_t)(p)) & 0x00ff) << 8) | \
+ (((uint16_t)(p)) >> 8));
+#endif
+#ifndef bswap_32
+# define bswap_32(p) \
+ (((((uint32_t)(p)) & 0x000000ff) << 24) | \
+ ((((uint32_t)(p)) & 0x0000ff00) << 8) | \
+ ((((uint32_t)(p)) & 0x00ff0000) >> 8) | \
+ ((((uint32_t)(p))) >> 24));
+#endif
+
#include "lookup-symbol.h"
/* Reverse the bits in a byte with 7 operations (no 64-bit):
@@ -103,6 +122,8 @@ struct _object {
const void *addr;
Type *type;
unsigned long int token;
+ int width, height;
+ bool foreign;
bool defined;
int operand;
void *data;
@@ -141,9 +162,25 @@ static struct _type_table {
} Types;
static FILE *logfile;
-static int _flush;
+static bool _flush;
+static bool _error;
+static bool _line_info;
static const cairo_user_data_key_t destroy_key;
+#if __GNUC__ >= 3
+#define _emit_line_info() do { \
+ if (_line_info && _write_lock ()) { \
+ void *addr = __builtin_return_address(0); \
+ char caller[1024]; \
+ fprintf (logfile, "%% %s() called by %s\n", __FUNCTION__, \
+ lookup_symbol (caller, sizeof (caller), addr)); \
+ _write_unlock (); \
+ } \
+} while (0)
+#else
+#define _emit_line_info()
+#endif
+
static void
_type_release_token (Type *t, unsigned long int token)
{
@@ -329,6 +366,7 @@ _object_create (Type *type, const void *ptr)
obj = malloc (sizeof (Object));
obj->defined = false;
+ obj->foreign = false;
obj->operand = -1;
obj->type = type;
obj->addr = ptr;
@@ -412,6 +450,7 @@ _emit_header (void)
get_prog_name (name, sizeof (name));
fprintf (logfile, "%%!CairoScript - %s\n", name);
+ fprintf (logfile, "%%*** Warning CairoScript is still a new tracing format, and is subject to change.\n");
}
static bool
@@ -430,6 +469,11 @@ _init_logfile (void)
if (env != NULL)
_flush = atoi (env);
+ _line_info = true;
+ env = getenv ("CAIRO_TRACE_LINE_INFO");
+ if (env != NULL)
+ _line_info = atoi (env);
+
filename = getenv ("CAIRO_TRACE_FD");
if (filename != NULL) {
int fd = atoi (filename);
@@ -448,13 +492,13 @@ _init_logfile (void)
filename = getenv ("CAIRO_TRACE_OUTDIR");
if (filename == NULL)
- filename = ".";
+ filename = CAIRO_TRACE_OUTDIR;
get_prog_name (name, sizeof (name));
if (*name == '\0')
strcpy (name, "cairo-trace.dat");
- snprintf (buf, sizeof (buf), "%s/%s.%d.cs",
+ snprintf (buf, sizeof (buf), "%s/%s.%d.trace",
filename, name, getpid());
filename = buf;
@@ -476,6 +520,9 @@ done:
static bool
_write_lock (void)
{
+ if (_error)
+ return false;
+
if (! _init_logfile ())
return false;
@@ -677,7 +724,20 @@ _create_context_id (cairo_t *cr)
static long
_get_id (enum operand_type op_type, const void *ptr)
{
- return _get_object (op_type, ptr)->token;
+ Object *obj;
+
+ obj = _get_object (op_type, ptr);
+ if (obj == NULL) {
+ if (logfile != NULL) {
+ fprintf (logfile,
+ "%% Unknown object of type %s, trace is incomplete.",
+ _get_type (op_type)->name);
+ }
+ _error = true;
+ return -1;
+ }
+
+ return obj->token;
}
static bool
@@ -719,6 +779,22 @@ _has_font_face_id (cairo_font_face_t *font_face)
return _has_id (FONT_FACE, font_face);
}
+static void
+_emit_font_face_id (cairo_font_face_t *font_face)
+{
+ Object *obj = _get_object (FONT_FACE, font_face);
+ if (obj == NULL) {
+ fprintf (logfile, "null ");
+ } else {
+ if (obj->defined) {
+ fprintf (logfile, "f%ld ", obj->token);
+ } else {
+ fprintf (logfile, "%d index ",
+ current_stack_depth - obj->operand - 1);
+ }
+ }
+}
+
static bool
_has_pattern_id (cairo_pattern_t *pattern)
{
@@ -746,6 +822,22 @@ _get_pattern_id (cairo_pattern_t *pattern)
return _get_id (PATTERN, pattern);
}
+static void
+_emit_pattern_id (cairo_pattern_t *pattern)
+{
+ Object *obj = _get_object (PATTERN, pattern);
+ if (obj == NULL) {
+ fprintf (logfile, "null ");
+ } else {
+ if (obj->defined) {
+ fprintf (logfile, "p%ld ", obj->token);
+ } else {
+ fprintf (logfile, "%d index ",
+ current_stack_depth - obj->operand - 1);
+ }
+ }
+}
+
static long
_create_scaled_font_id (cairo_scaled_font_t *font)
{
@@ -800,6 +892,14 @@ _get_surface_id (cairo_surface_t *surface)
return _get_id (SURFACE, surface);
}
+static bool
+_matrix_is_identity (const cairo_matrix_t *m)
+{
+ return m->xx == 1. && m->yx == 0. &&
+ m->xy == 0. && m->yy == 1. &&
+ m->x0 == 0. && m->y0 == 0.;
+}
+
#define BUFFER_SIZE 16384
struct _data_stream {
z_stream zlib_stream;
@@ -912,7 +1012,9 @@ _write_zlib_data (struct _data_stream *stream, bool flush)
}
static void
-_write_data (struct _data_stream *stream, void *data, unsigned int length)
+_write_data (struct _data_stream *stream,
+ const void *data,
+ unsigned int length)
{
unsigned int count;
const unsigned char *p = data;
@@ -963,7 +1065,7 @@ _write_data_end (struct _data_stream *stream)
}
static void
-_emit_data (void *data, unsigned int length)
+_emit_data (const void *data, unsigned int length)
{
struct _data_stream stream;
@@ -972,8 +1074,62 @@ _emit_data (void *data, unsigned int length)
_write_data_end (&stream);
}
-static void
-_emit_image (cairo_surface_t *image)
+static const char *
+_format_to_string (cairo_format_t format)
+{
+ const char *names[] = {
+ "ARGB32", /* CAIRO_FORMAT_ARGB32 */
+ "RGB24", /* CAIRO_FORMAT_RGB24 */
+ "A8", /* CAIRO_FORMAT_A8 */
+ "A1" /* CAIRO_FORMAT_A1 */
+ };
+ return names[format];
+}
+
+static const char *
+_status_to_string (cairo_status_t status)
+{
+ const char *names[] = {
+ "STATUS_SUCCESS",
+ "STATUS_NO_MEMORY",
+ "STATUS_INVALID_RESTORE",
+ "STATUS_INVALID_POP_GROUP",
+ "STATUS_NO_CURRENT_POINT",
+ "STATUS_INVALID_MATRIX",
+ "STATUS_INVALID_STATUS",
+ "STATUS_NULL_POINTER",
+ "STATUS_INVALID_STRING",
+ "STATUS_INVALID_PATH_DATA",
+ "STATUS_READ_ERROR",
+ "STATUS_WRITE_ERROR",
+ "STATUS_SURFACE_FINISHED",
+ "STATUS_SURFACE_TYPE_MISMATCH",
+ "STATUS_PATTERN_TYPE_MISMATCH",
+ "STATUS_INVALID_CONTENT",
+ "STATUS_INVALID_FORMAT",
+ "STATUS_INVALID_VISUAL",
+ "STATUS_FILE_NOT_FOUND",
+ "STATUS_INVALID_DASH",
+ "STATUS_INVALID_DSC_COMMENT",
+ "STATUS_INVALID_INDEX",
+ "STATUS_CLIP_NOT_REPRESENTABLE",
+ "STATUS_TEMP_FILE_ERROR",
+ "STATUS_INVALID_STRIDE",
+ "STATUS_FONT_TYPE_MISMATCH",
+ "STATUS_USER_FONT_IMMUTABLE",
+ "STATUS_USER_FONT_ERROR",
+ "STATUS_NEGATIVE_COUNT",
+ "STATUS_INVALID_CLUSTERS",
+ "STATUS_INVALID_SLANT",
+ "STATUS_INVALID_WEIGHT"
+ };
+ return names[status];
+}
+
+static void CAIRO_PRINTF_FORMAT(2, 3)
+_emit_image (cairo_surface_t *image,
+ const char *info,
+ ...)
{
int stride, row, width, height;
cairo_format_t format;
@@ -981,6 +1137,20 @@ _emit_image (cairo_surface_t *image)
uint8_t *rowdata;
uint8_t *data;
struct _data_stream stream;
+ const char *mime_types[] = {
+ CAIRO_MIME_TYPE_JPEG,
+ CAIRO_MIME_TYPE_PNG,
+ NULL
+ }, **mime_type;
+
+ if (cairo_surface_status (image)) {
+ fprintf (logfile,
+ "dict\n"
+ " /status //%s set\n"
+ " image",
+ _status_to_string (cairo_surface_status (image)));
+ return;
+ }
width = cairo_image_surface_get_width (image);
height = cairo_image_surface_get_height (image);
@@ -988,6 +1158,43 @@ _emit_image (cairo_surface_t *image)
format = cairo_image_surface_get_format (image);
data = cairo_image_surface_get_data (image);
+ fprintf (logfile,
+ "dict\n"
+ " /width %d set\n"
+ " /height %d set\n"
+ " /format //%s set\n",
+ width, height,
+ _format_to_string (format));
+ if (info != NULL) {
+ va_list ap;
+
+ va_start (ap, info);
+ vfprintf (logfile, info, ap);
+ va_end (ap);
+ }
+
+ for (mime_type = mime_types; *mime_type; mime_type++) {
+ const unsigned char *mime_data;
+ unsigned int mime_length;
+
+ cairo_surface_get_mime_data (image, *mime_type,
+ &mime_data, &mime_length);
+ if (mime_data != NULL) {
+ fprintf (logfile,
+ " /mime-type (%s) set\n"
+ " /source <~",
+ *mime_type);
+ _write_base85_data_start (&stream);
+ _write_base85_data (&stream, mime_data, mime_length);
+ _write_base85_data_end (&stream);
+ fprintf (logfile,
+ "~> set\n"
+ " image");
+ return;
+ }
+ }
+
+ fprintf (logfile, " /source ");
_write_data_start (&stream);
#ifdef WORDS_BIGENDIAN
@@ -1000,7 +1207,7 @@ _emit_image (cairo_surface_t *image)
break;
case CAIRO_FORMAT_A8:
for (row = height; row--; ) {
- _write_data (&ouput, data, width);
+ _write_data (&stream, data, width);
data += stride;
}
break;
@@ -1009,7 +1216,7 @@ _emit_image (cairo_surface_t *image)
int col;
rowdata = data;
for (col = width; col--; ) {
- _write_data (&ouput, rowdata, 3);
+ _write_data (&stream, rowdata, 3);
rowdata+=4;
}
data += stride;
@@ -1022,16 +1229,13 @@ _emit_image (cairo_surface_t *image)
}
break;
default:
- ASSERT_NOT_REACHED;
break;
}
#else
if (stride > ARRAY_LENGTH (row_stack)) {
rowdata = malloc (stride);
- if (rowdata == NULL) {
- _write_data_end (&stream);
- return;
- }
+ if (rowdata == NULL)
+ goto BAIL;
} else
rowdata = row_stack;
@@ -1082,23 +1286,107 @@ _emit_image (cairo_surface_t *image)
if (rowdata != row_stack)
free (rowdata);
+BAIL:
_write_data_end (&stream);
#endif
+ fprintf (logfile,
+ " /deflate filter set\n"
+ " image");
}
static void
-_emit_string_literal (const char *utf8)
+_encode_string_literal (char *out, int max,
+ const char *utf8, int len)
{
char c;
+ const char *end;
+
+ *out++ = '(';
+ max--;
+
+ if (utf8 == NULL)
+ goto DONE;
+
+ if (len < 0)
+ len = strlen (utf8);
+ end = utf8 + len;
+
+ while (utf8 < end) {
+ if (max < 5)
+ break;
+
+ switch ((c = *utf8++)) {
+ case '\n':
+ *out++ = '\\';
+ *out++ = 'n';
+ max -= 2;
+ break;
+ case '\r':
+ *out++ = '\\';
+ *out++ = 'n';
+ max -= 2;
+ case '\t':
+ *out++ = '\\';
+ *out++ = 't';
+ max -= 2;
+ break;
+ case '\b':
+ *out++ = '\\';
+ *out++ = 'b';
+ max -= 2;
+ break;
+ case '\f':
+ *out++ = '\\';
+ *out++ = 'r';
+ max -= 2;
+ break;
+ case '\\':
+ case '(':
+ case ')':
+ *out++ = '\\';
+ *out++ = c;
+ max -= 2;
+ break;
+ default:
+ if (isprint (c) || isspace (c)) {
+ *out++ = c;
+ } else {
+ int octal = 0;
+ while (c) {
+ octal *= 10;
+ octal += c&7;
+ c /= 8;
+ }
+ octal = snprintf (out, max, "\\%03d", octal);
+ out += octal;
+ max -= octal;
+ }
+ break;
+ }
+ }
+DONE:
+ *out++ = ')';
+ *out = '\0';
+}
+
+static void
+_emit_string_literal (const char *utf8, int len)
+{
+ char c;
+ const char *end;
if (utf8 == NULL) {
fprintf (logfile, "()");
return;
}
+ if (len < 0)
+ len = strlen (utf8);
+ end = utf8 + len;
+
fprintf (logfile, "(");
- while ((c = *utf8++)) {
- switch (c) {
+ while (utf8 < end) {
+ switch ((c = *utf8++)) {
case '\n':
case '\r':
case '\\':
@@ -1130,7 +1418,7 @@ _emit_string_literal (const char *utf8)
static void
_emit_current (Object *obj)
{
- if (! _pop_operands_to_object (obj)) {
+ if (obj != NULL && ! _pop_operands_to_object (obj)) {
fprintf (logfile, "%s%ld\n", obj->type->op_code, obj->token);
_push_operand (obj->type->op_type, obj->addr);
}
@@ -1193,17 +1481,21 @@ cairo_create (cairo_surface_t *target)
ret = DLCALL (cairo_create, target);
context_id = _create_context_id (ret);
+ _emit_line_info ();
if (target != NULL && _write_lock ()) {
surface_id = _get_surface_id (target);
+ if (surface_id != -1) {
+ _get_object (SURFACE, target)->foreign = false;
- /* we presume that we will continue to use the context */
- if (_pop_operands_to (SURFACE, target)){
- _consume_operand ();
- } else {
- fprintf (logfile, "s%ld ", surface_id);
+ /* we presume that we will continue to use the context */
+ if (_pop_operands_to (SURFACE, target)){
+ _consume_operand ();
+ } else {
+ fprintf (logfile, "s%ld ", surface_id);
+ }
+ fprintf (logfile, "context %% c%ld\n", context_id);
+ _push_operand (CONTEXT, ret);
}
- fprintf (logfile, "context %% c%ld\n", context_id);
- _push_operand (CONTEXT, ret);
_write_unlock ();
}
@@ -1213,6 +1505,7 @@ cairo_create (cairo_surface_t *target)
void
cairo_save (cairo_t *cr)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "save\n");
return DLCALL (cairo_save, cr);
}
@@ -1220,6 +1513,7 @@ cairo_save (cairo_t *cr)
void
cairo_restore (cairo_t *cr)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "restore\n");
return DLCALL (cairo_restore, cr);
}
@@ -1227,6 +1521,7 @@ cairo_restore (cairo_t *cr)
void
cairo_push_group (cairo_t *cr)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "//COLOR_ALPHA push_group\n");
return DLCALL (cairo_push_group, cr);
}
@@ -1245,6 +1540,7 @@ _content_to_string (cairo_content_t content)
void
cairo_push_group_with_content (cairo_t *cr, cairo_content_t content)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "//%s push_group\n", _content_to_string (content));
return DLCALL (cairo_push_group_with_content, cr, content);
}
@@ -1256,6 +1552,7 @@ cairo_pop_group (cairo_t *cr)
ret = DLCALL (cairo_pop_group, cr);
+ _emit_line_info ();
_emit_cairo_op (cr, "pop_group %% p%ld\n", _create_pattern_id (ret));
_push_operand (PATTERN, ret);
@@ -1265,6 +1562,7 @@ cairo_pop_group (cairo_t *cr)
void
cairo_pop_group_to_source (cairo_t *cr)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "pop_group set_source\n");
return DLCALL (cairo_pop_group_to_source, cr);
}
@@ -1297,6 +1595,7 @@ _operator_to_string (cairo_operator_t op)
void
cairo_set_operator (cairo_t *cr, cairo_operator_t op)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "//%s set_operator\n", _operator_to_string (op));
return DLCALL (cairo_set_operator, cr, op);
}
@@ -1304,6 +1603,7 @@ cairo_set_operator (cairo_t *cr, cairo_operator_t op)
void
cairo_set_source_rgb (cairo_t *cr, double red, double green, double blue)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "%g %g %g rgb set_source\n", red, green, blue);
return DLCALL (cairo_set_source_rgb, cr, red, green, blue);
}
@@ -1311,14 +1611,76 @@ cairo_set_source_rgb (cairo_t *cr, double red, double green, double blue)
void
cairo_set_source_rgba (cairo_t *cr, double red, double green, double blue, double alpha)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "%g %g %g %g rgba set_source\n",
red, green, blue, alpha);
return DLCALL (cairo_set_source_rgba, cr, red, green, blue, alpha);
}
+static void
+_emit_source_image (cairo_surface_t *surface)
+{
+ Object *obj;
+ cairo_surface_t *image;
+ cairo_t *cr;
+
+ obj = _get_object (SURFACE, surface);
+ if (obj == NULL)
+ return;
+
+ image = DLCALL (cairo_image_surface_create,
+ CAIRO_FORMAT_ARGB32,
+ obj->width,
+ obj->height);
+ cr = DLCALL (cairo_create, image);
+ DLCALL (cairo_set_source_surface, cr, surface, 0, 0);
+ DLCALL (cairo_paint, cr);
+ DLCALL (cairo_destroy, cr);
+
+ _emit_image (image, NULL);
+ fprintf (logfile,
+ " set_source_image ");
+ DLCALL (cairo_surface_destroy, image);
+
+ obj->foreign = false;
+}
+
+static void
+_emit_source_image_rectangle (cairo_surface_t *surface,
+ int x, int y,
+ int width, int height)
+{
+ Object *obj;
+ cairo_surface_t *image;
+ cairo_t *cr;
+
+ obj = _get_object (SURFACE, surface);
+ if (obj == NULL)
+ return;
+
+ if (obj->foreign)
+ return _emit_source_image (surface);
+
+ image = DLCALL (cairo_image_surface_create,
+ CAIRO_FORMAT_ARGB32,
+ width,
+ height);
+ cr = DLCALL (cairo_create, image);
+ DLCALL (cairo_set_source_surface, cr, surface, x, y);
+ DLCALL (cairo_paint, cr);
+ DLCALL (cairo_destroy, cr);
+
+ _emit_image (image, NULL);
+ fprintf (logfile,
+ " %d %d set_device_offset set_source_image ",
+ x, y);
+ DLCALL (cairo_surface_destroy, image);
+}
+
void
cairo_set_source_surface (cairo_t *cr, cairo_surface_t *surface, double x, double y)
{
+ _emit_line_info ();
if (cr != NULL && surface != NULL && _write_lock ()) {
if (_is_current (SURFACE, surface, 0) &&
_is_current (CONTEXT, cr, 1))
@@ -1336,6 +1698,9 @@ cairo_set_source_surface (cairo_t *cr, cairo_surface_t *surface, double x, doubl
fprintf (logfile, "s%ld ", _get_surface_id (surface));
}
+ if (_get_object (SURFACE, surface)->foreign)
+ _emit_source_image (surface);
+
fprintf (logfile, "pattern");
if (x != 0. || y != 0.)
fprintf (logfile, " %g %g translate", -x, -y);
@@ -1350,6 +1715,7 @@ cairo_set_source_surface (cairo_t *cr, cairo_surface_t *surface, double x, doubl
void
cairo_set_source (cairo_t *cr, cairo_pattern_t *source)
{
+ _emit_line_info ();
if (cr != NULL && source != NULL && _write_lock ()) {
if (_is_current (PATTERN, source, 0) &&
_is_current (CONTEXT, cr, 1))
@@ -1363,17 +1729,10 @@ cairo_set_source (cairo_t *cr, cairo_pattern_t *source)
_exch_operands ();
_consume_operand ();
}
- else if (_is_current (PATTERN, source, 0))
- {
- _emit_context (cr);
- fprintf (logfile, "exch ");
- _exch_operands ();
- _consume_operand ();
- }
else
{
_emit_context (cr);
- fprintf (logfile, "p%ld ", _get_pattern_id (source));
+ _emit_pattern_id (source);
}
fprintf (logfile, "set_source\n");
@@ -1402,6 +1761,7 @@ cairo_get_source (cairo_t *cr)
void
cairo_set_tolerance (cairo_t *cr, double tolerance)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "%g set_tolerance\n", tolerance);
return DLCALL (cairo_set_tolerance, cr, tolerance);
}
@@ -1421,6 +1781,7 @@ _antialias_to_string (cairo_antialias_t antialias)
void
cairo_set_antialias (cairo_t *cr, cairo_antialias_t antialias)
{
+ _emit_line_info ();
_emit_cairo_op (cr,
"//%s set_antialias\n", _antialias_to_string (antialias));
return DLCALL (cairo_set_antialias, cr, antialias);
@@ -1439,6 +1800,7 @@ _fill_rule_to_string (cairo_fill_rule_t rule)
void
cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule)
{
+ _emit_line_info ();
_emit_cairo_op (cr,
"//%s set_fill_rule\n", _fill_rule_to_string (fill_rule));
return DLCALL (cairo_set_fill_rule, cr, fill_rule);
@@ -1447,6 +1809,7 @@ cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule)
void
cairo_set_line_width (cairo_t *cr, double width)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "%g set_line_width\n", width);
return DLCALL (cairo_set_line_width, cr, width);
}
@@ -1465,6 +1828,7 @@ _line_cap_to_string (cairo_line_cap_t line_cap)
void
cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "//%s set_line_cap\n", _line_cap_to_string (line_cap));
return DLCALL (cairo_set_line_cap, cr, line_cap);
}
@@ -1483,6 +1847,7 @@ _line_join_to_string (cairo_line_join_t line_join)
void
cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join)
{
+ _emit_line_info ();
_emit_cairo_op (cr,
"//%s set_line_join\n", _line_join_to_string (line_join));
return DLCALL (cairo_set_line_join, cr, line_join);
@@ -1491,6 +1856,7 @@ cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join)
void
cairo_set_dash (cairo_t *cr, const double *dashes, int num_dashes, double offset)
{
+ _emit_line_info ();
if (cr != NULL && _write_lock ()) {
int n;
@@ -1513,6 +1879,7 @@ cairo_set_dash (cairo_t *cr, const double *dashes, int num_dashes, double offset
void
cairo_set_miter_limit (cairo_t *cr, double limit)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "%g set_miter_limit\n", limit);
return DLCALL (cairo_set_miter_limit, cr, limit);
}
@@ -1520,6 +1887,7 @@ cairo_set_miter_limit (cairo_t *cr, double limit)
void
cairo_translate (cairo_t *cr, double tx, double ty)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "%g %g translate\n", tx, ty);
return DLCALL (cairo_translate, cr, tx, ty);
}
@@ -1527,6 +1895,7 @@ cairo_translate (cairo_t *cr, double tx, double ty)
void
cairo_scale (cairo_t *cr, double sx, double sy)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "%g %g scale\n", sx, sy);
return DLCALL (cairo_scale, cr, sx, sy);
}
@@ -1534,6 +1903,7 @@ cairo_scale (cairo_t *cr, double sx, double sy)
void
cairo_rotate (cairo_t *cr, double angle)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "%g rotate\n", angle);
return DLCALL (cairo_rotate, cr, angle);
}
@@ -1541,7 +1911,8 @@ cairo_rotate (cairo_t *cr, double angle)
void
cairo_transform (cairo_t *cr, const cairo_matrix_t *matrix)
{
- _emit_cairo_op (cr, "[%g %g %g %g %g %g] transform\n",
+ _emit_line_info ();
+ _emit_cairo_op (cr, "%g %g %g %g %g %g matrix transform\n",
matrix->xx, matrix->yx,
matrix->xy, matrix->yy,
matrix->x0, matrix->y0);
@@ -1551,10 +1922,15 @@ cairo_transform (cairo_t *cr, const cairo_matrix_t *matrix)
void
cairo_set_matrix (cairo_t *cr, const cairo_matrix_t *matrix)
{
- _emit_cairo_op (cr, "[%g %g %g %g %g %g] set_matrix\n",
- matrix->xx, matrix->yx,
- matrix->xy, matrix->yy,
- matrix->x0, matrix->y0);
+ _emit_line_info ();
+ if (_matrix_is_identity (matrix)) {
+ _emit_cairo_op (cr, "identity set_matrix\n");
+ } else {
+ _emit_cairo_op (cr, "%g %g %g %g %g %g matrix set_matrix\n",
+ matrix->xx, matrix->yx,
+ matrix->xy, matrix->yy,
+ matrix->x0, matrix->y0);
+ }
return DLCALL (cairo_set_matrix, cr, matrix);
}
@@ -1595,6 +1971,7 @@ cairo_get_group_target (cairo_t *cr)
void
cairo_identity_matrix (cairo_t *cr)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "identity set_matrix\n");
return DLCALL (cairo_identity_matrix, cr);
}
@@ -1603,6 +1980,7 @@ cairo_identity_matrix (cairo_t *cr)
void
cairo_new_path (cairo_t *cr)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "n ");
return DLCALL (cairo_new_path, cr);
}
@@ -1689,6 +2067,7 @@ cairo_close_path (cairo_t *cr)
void
cairo_paint (cairo_t *cr)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "paint\n");
DLCALL (cairo_paint, cr);
}
@@ -1696,6 +2075,7 @@ cairo_paint (cairo_t *cr)
void
cairo_paint_with_alpha (cairo_t *cr, double alpha)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "%g paint_with_alpha\n", alpha);
DLCALL (cairo_paint_with_alpha, cr, alpha);
}
@@ -1703,6 +2083,7 @@ cairo_paint_with_alpha (cairo_t *cr, double alpha)
void
cairo_mask (cairo_t *cr, cairo_pattern_t *pattern)
{
+ _emit_line_info ();
if (cr != NULL && pattern != NULL && _write_lock ()) {
if (_is_current (PATTERN, pattern, 0) &&
_is_current (CONTEXT, cr, 1))
@@ -1717,7 +2098,7 @@ cairo_mask (cairo_t *cr, cairo_pattern_t *pattern)
_consume_operand ();
} else {
_emit_context (cr);
- fprintf (logfile, "p%ld ", _get_pattern_id (pattern));
+ _emit_pattern_id (pattern);
}
fprintf (logfile, " mask\n");
@@ -1729,6 +2110,7 @@ cairo_mask (cairo_t *cr, cairo_pattern_t *pattern)
void
cairo_mask_surface (cairo_t *cr, cairo_surface_t *surface, double x, double y)
{
+ _emit_line_info ();
if (cr != NULL && surface != NULL && _write_lock ()) {
if (_is_current (SURFACE, surface, 0) &&
_is_current (CONTEXT, cr, 1))
@@ -1760,6 +2142,7 @@ cairo_mask_surface (cairo_t *cr, cairo_surface_t *surface, double x, double y)
void
cairo_stroke (cairo_t *cr)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "stroke\n");
DLCALL (cairo_stroke, cr);
}
@@ -1767,6 +2150,7 @@ cairo_stroke (cairo_t *cr)
void
cairo_stroke_preserve (cairo_t *cr)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "stroke+\n");
DLCALL (cairo_stroke_preserve, cr);
}
@@ -1774,6 +2158,7 @@ cairo_stroke_preserve (cairo_t *cr)
void
cairo_fill (cairo_t *cr)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "fill\n");
DLCALL (cairo_fill, cr);
}
@@ -1781,6 +2166,7 @@ cairo_fill (cairo_t *cr)
void
cairo_fill_preserve (cairo_t *cr)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "fill+\n");
DLCALL (cairo_fill_preserve, cr);
}
@@ -1788,6 +2174,7 @@ cairo_fill_preserve (cairo_t *cr)
void
cairo_copy_page (cairo_t *cr)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "copy_page\n");
return DLCALL (cairo_copy_page, cr);
}
@@ -1795,6 +2182,7 @@ cairo_copy_page (cairo_t *cr)
void
cairo_show_page (cairo_t *cr)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "show_page\n");
return DLCALL (cairo_show_page, cr);
}
@@ -1802,6 +2190,7 @@ cairo_show_page (cairo_t *cr)
void
cairo_clip (cairo_t *cr)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "clip\n");
DLCALL (cairo_clip, cr);
}
@@ -1809,6 +2198,7 @@ cairo_clip (cairo_t *cr)
void
cairo_clip_preserve (cairo_t *cr)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "clip+\n");
DLCALL (cairo_clip_preserve, cr);
}
@@ -1816,6 +2206,7 @@ cairo_clip_preserve (cairo_t *cr)
void
cairo_reset_clip (cairo_t *cr)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "reset_clip\n");
return DLCALL (cairo_reset_clip, cr);
}
@@ -1845,9 +2236,10 @@ _weight_to_string (cairo_font_weight_t font_weight)
void
cairo_select_font_face (cairo_t *cr, const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight)
{
+ _emit_line_info ();
if (cr != NULL && _write_lock ()) {
_emit_context (cr);
- _emit_string_literal (family);
+ _emit_string_literal (family, -1);
fprintf (logfile, " //%s //%s select_font_face\n",
_slant_to_string (slant),
_weight_to_string (weight));
@@ -1874,8 +2266,29 @@ cairo_get_font_face (cairo_t *cr)
void
cairo_set_font_face (cairo_t *cr, cairo_font_face_t *font_face)
{
- _emit_cairo_op (cr, "f%ld set_font_face\n",
- _get_font_face_id (font_face));
+ _emit_line_info ();
+ if (cr != NULL && font_face != NULL && _write_lock ()) {
+ if (_is_current (FONT_FACE, font_face, 0) &&
+ _is_current (CONTEXT, cr, 1))
+ {
+ _consume_operand ();
+ }
+ else if (_is_current (FONT_FACE, font_face, 1) &&
+ _is_current (CONTEXT, cr, 0))
+ {
+ fprintf (logfile, "exch ");
+ _exch_operands ();
+ _consume_operand ();
+ }
+ else
+ {
+ _emit_context (cr);
+ _emit_font_face_id (font_face);
+ }
+
+ fprintf (logfile, "set_font_face\n");
+ _write_unlock ();
+ }
return DLCALL (cairo_set_font_face, cr, font_face);
}
@@ -1883,6 +2296,7 @@ cairo_set_font_face (cairo_t *cr, cairo_font_face_t *font_face)
void
cairo_set_font_size (cairo_t *cr, double size)
{
+ _emit_line_info ();
_emit_cairo_op (cr, "%g set_font_size\n", size);
return DLCALL (cairo_set_font_size, cr, size);
}
@@ -1890,7 +2304,8 @@ cairo_set_font_size (cairo_t *cr, double size)
void
cairo_set_font_matrix (cairo_t *cr, const cairo_matrix_t *matrix)
{
- _emit_cairo_op (cr, "[%g %g %g %g %g %g] set_font_matrix\n",
+ _emit_line_info ();
+ _emit_cairo_op (cr, "%g %g %g %g %g %g matrix set_font_matrix\n",
matrix->xx, matrix->yx,
matrix->xy, matrix->yy,
matrix->x0, matrix->y0);
@@ -1969,6 +2384,7 @@ _emit_font_options (const cairo_font_options_t *options)
void
cairo_set_font_options (cairo_t *cr, const cairo_font_options_t *options)
{
+ _emit_line_info ();
if (cr != NULL && options != NULL && _write_lock ()) {
_emit_context (cr);
_emit_font_options (options);
@@ -1998,6 +2414,7 @@ cairo_get_scaled_font (cairo_t *cr)
void
cairo_set_scaled_font (cairo_t *cr, const cairo_scaled_font_t *scaled_font)
{
+ _emit_line_info ();
if (cr != NULL && scaled_font != NULL) {
if (_pop_operands_to (SCALED_FONT, scaled_font)) {
if (_is_current (CONTEXT, cr, 1)) {
@@ -2040,7 +2457,7 @@ _emit_matrix (const cairo_matrix_t *m)
else
{
fprintf (logfile,
- "[%g %g %g %g %g %g]",
+ "%g %g %g %g %g %g matrix",
m->xx, m->yx,
m->xy, m->yy,
m->x0, m->y0);
@@ -2055,37 +2472,36 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
{
cairo_scaled_font_t *ret;
long scaled_font_id;
- long font_face_id;
ret = DLCALL (cairo_scaled_font_create, font_face, font_matrix, ctm, options);
scaled_font_id = _create_scaled_font_id (ret);
+ _emit_line_info ();
if (font_face != NULL &&
font_matrix != NULL &&
ctm != NULL &&
options != NULL
&& _write_lock ())
{
- font_face_id = _get_font_face_id (font_face);
-
- if (_pop_operands_to (FONT_FACE, font_face)) {
+ if (_pop_operands_to (FONT_FACE, font_face))
_consume_operand ();
- _emit_matrix (font_matrix);
- fprintf (logfile, " ");
- _emit_matrix (ctm);
- fprintf (logfile, " ");
- } else {
- _emit_matrix (font_matrix);
- fprintf (logfile, " ");
- _emit_matrix (ctm);
- fprintf (logfile, " ");
- _emit_font_options (options);
- }
+ else
+ fprintf (logfile, "f%ld ", _get_font_face_id (font_face));
+
+ _emit_matrix (font_matrix);
+ fprintf (logfile, " ");
+
+ _emit_matrix (ctm);
+ fprintf (logfile, " ");
+
_emit_font_options (options);
+
fprintf (logfile, " scaled_font dup /sf%ld exch def\n",
scaled_font_id);
+
_get_object (SCALED_FONT, ret)->defined = true;
_push_operand (SCALED_FONT, ret);
+
_write_unlock ();
}
@@ -2095,9 +2511,10 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
void
cairo_show_text (cairo_t *cr, const char *utf8)
{
+ _emit_line_info ();
if (cr != NULL && _write_lock ()) {
_emit_context (cr);
- _emit_string_literal (utf8);
+ _emit_string_literal (utf8, -1);
fprintf (logfile, " show_text\n");
_write_unlock ();
}
@@ -2126,7 +2543,10 @@ _emit_glyphs (cairo_scaled_font_t *font,
x = glyphs->x;
y = glyphs->y;
if (n < num_glyphs) { /* need full glyph range */
- fprintf (logfile, "[ %g %g [", x, y);
+ bool first;
+
+ fprintf (logfile, "[%g %g [", x, y);
+ first = true;
while (num_glyphs--) {
cairo_text_extents_t extents;
@@ -2135,10 +2555,14 @@ _emit_glyphs (cairo_scaled_font_t *font,
{
x = glyphs->x;
y = glyphs->y;
- fprintf (logfile, " ] %g %g [", x, y);
+ fprintf (logfile, "] %g %g [", x, y);
+ first = true;
}
- fprintf (logfile, " %lu", glyphs->index);
+ if (! first)
+ fprintf (logfile, " ");
+ fprintf (logfile, "%lu", glyphs->index);
+ first = false;
cairo_scaled_font_glyph_extents (font, glyphs, 1, &extents);
x += extents.x_advance;
@@ -2146,37 +2570,41 @@ _emit_glyphs (cairo_scaled_font_t *font,
glyphs++;
}
- fprintf (logfile, " ] ]");
+ fprintf (logfile, "]]");
} else {
struct _data_stream stream;
- fprintf (logfile, "[ %g %g <~", x, y);
- _write_base85_data_start (&stream);
- while (num_glyphs--) {
- cairo_text_extents_t extents;
- unsigned char c;
-
- if (fabs (glyphs->x - x) > TOLERANCE ||
- fabs (glyphs->y - y) > TOLERANCE)
- {
- x = glyphs->x;
- y = glyphs->y;
- _write_base85_data_end (&stream);
- fprintf (logfile, "~> %g %g <~", x, y);
- _write_base85_data_start (&stream);
- }
+ if (num_glyphs == 1) {
+ fprintf (logfile, "[%g %g <%lx>]", x, y, glyphs->index);
+ } else {
+ fprintf (logfile, "[%g %g <~", x, y);
+ _write_base85_data_start (&stream);
+ while (num_glyphs--) {
+ cairo_text_extents_t extents;
+ unsigned char c;
+
+ if (fabs (glyphs->x - x) > TOLERANCE ||
+ fabs (glyphs->y - y) > TOLERANCE)
+ {
+ x = glyphs->x;
+ y = glyphs->y;
+ _write_base85_data_end (&stream);
+ fprintf (logfile, "~> %g %g <~", x, y);
+ _write_base85_data_start (&stream);
+ }
- c = glyphs->index;
- _write_base85_data (&stream, &c, 1);
+ c = glyphs->index;
+ _write_base85_data (&stream, &c, 1);
- cairo_scaled_font_glyph_extents (font, glyphs, 1, &extents);
- x += extents.x_advance;
- y += extents.y_advance;
+ cairo_scaled_font_glyph_extents (font, glyphs, 1, &extents);
+ x += extents.x_advance;
+ y += extents.y_advance;
- glyphs++;
+ glyphs++;
+ }
+ _write_base85_data_end (&stream);
+ fprintf (logfile, "~>]");
}
- _write_base85_data_end (&stream);
- fprintf (logfile, "~> ]");
}
}
@@ -2185,8 +2613,9 @@ cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs)
{
cairo_scaled_font_t *font;
- font = cairo_get_scaled_font (cr);
+ font = DLCALL (cairo_get_scaled_font, cr);
+ _emit_line_info ();
if (cr != NULL && glyphs != NULL && _write_lock ()) {
_emit_context (cr);
_emit_glyphs (font, glyphs, num_glyphs);
@@ -2219,19 +2648,19 @@ cairo_show_text_glyphs (cairo_t *cr,
{
cairo_scaled_font_t *font;
- font = cairo_get_scaled_font (cr);
+ font = DLCALL (cairo_get_scaled_font, cr);
+ _emit_line_info ();
if (cr != NULL && glyphs != NULL && clusters != NULL && _write_lock ()) {
int n;
_emit_context (cr);
- _emit_string_literal (utf8);
- fprintf (logfile, " %d ", utf8_len);
+ _emit_string_literal (utf8, utf8_len);
_emit_glyphs (font, glyphs, num_glyphs);
fprintf (logfile, " [");
- for (n = 0; n < num_clusters++; n++) {
+ for (n = 0; n < num_clusters; n++) {
fprintf (logfile, " %d %d",
clusters[n].num_bytes,
clusters[n].num_glyphs);
@@ -2252,9 +2681,10 @@ cairo_show_text_glyphs (cairo_t *cr,
void
cairo_text_path (cairo_t *cr, const char *utf8)
{
+ _emit_line_info ();
if (cr != NULL && _write_lock ()) {
_emit_context (cr);
- _emit_string_literal (utf8);
+ _emit_string_literal (utf8, -1);
fprintf (logfile, " text_path\n");
_write_unlock ();
}
@@ -2266,8 +2696,9 @@ cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs)
{
cairo_scaled_font_t *font;
- font = cairo_get_scaled_font (cr);
+ font = DLCALL (cairo_get_scaled_font, cr);
+ _emit_line_info ();
if (cr != NULL && glyphs != NULL && _write_lock ()) {
_emit_context (cr);
_emit_glyphs (font, glyphs, num_glyphs);
@@ -2286,6 +2717,7 @@ cairo_append_path (cairo_t *cr, const cairo_path_t *path)
int i;
cairo_path_data_t *p;
+ _emit_line_info ();
if (cr == NULL || path == NULL)
return DLCALL (cairo_append_path, cr, path);
@@ -2317,18 +2749,6 @@ cairo_append_path (cairo_t *cr, const cairo_path_t *path)
}
}
-static const char *
-_format_to_string (cairo_format_t format)
-{
- const char *names[] = {
- "ARGB32", /* CAIRO_FORMAT_ARGB32 */
- "RGB24", /* CAIRO_FORMAT_RGB24 */
- "A8", /* CAIRO_FORMAT_A8 */
- "A1" /* CAIRO_FORMAT_A1 */
- };
- return names[format];
-}
-
cairo_surface_t *
cairo_image_surface_create (cairo_format_t format, int width, int height)
{
@@ -2341,6 +2761,7 @@ cairo_image_surface_create (cairo_format_t format, int width, int height)
surface_id = _create_surface_id (ret);
format_str = _format_to_string (format);
+ _emit_line_info ();
if (_write_lock ()) {
fprintf (logfile,
"dict\n"
@@ -2349,6 +2770,8 @@ cairo_image_surface_create (cairo_format_t format, int width, int height)
" /format //%s set\n"
" image dup /s%ld exch def\n",
width, height, format_str, surface_id);
+ _get_object (SURFACE, ret)->width = width;
+ _get_object (SURFACE, ret)->height = height;
_get_object (SURFACE, ret)->defined = true;
_push_operand (SURFACE, ret);
_write_unlock ();
@@ -2362,26 +2785,39 @@ cairo_image_surface_create_for_data (unsigned char *data, cairo_format_t format,
{
cairo_surface_t *ret;
long surface_id;
- const char *format_str;
ret = DLCALL (cairo_image_surface_create_for_data, data, format, width, height, stride);
surface_id = _create_surface_id (ret);
- if (data != NULL && _write_lock ()) {
- format_str = _format_to_string (format);
+ _emit_line_info ();
+ if (_write_lock ()) {
+ /* cairo_image_surface_create_for_data() is both used to supply
+ * foreign pixel data to cairo and in order to read pixels back.
+ * Defer grabbing the pixel contents until we have to, but only for
+ * "large" images, for small images the overhead of embedding pixels
+ * is negligible.
+ */
+ if (width * height < 128) {
+ _emit_image (ret, NULL);
+ fprintf (logfile,
+ " dup /s%ld exch def\n",
+ surface_id);
+ } else {
+ fprintf (logfile,
+ "dict\n"
+ " /width %d set\n"
+ " /height %d set\n"
+ " /format //%s set\n"
+ " image dup /s%ld exch def\n",
+ width, height,
+ _format_to_string (format),
+ surface_id);
+
+ _get_object (SURFACE, ret)->foreign = true;
+ }
- fprintf (logfile,
- "dict\n"
- " /width %d set\n"
- " /height %d set\n"
- " /format //%s set\n"
- " /source ",
- width, height, format_str);
- _emit_image (ret);
- fprintf (logfile,
- " /deflate filter set\n"
- " image dup /s%ld exch def\n",
- surface_id);
+ _get_object (SURFACE, ret)->width = width;
+ _get_object (SURFACE, ret)->height = height;
_get_object (SURFACE, ret)->defined = true;
_push_operand (SURFACE, ret);
_write_unlock ();
@@ -2402,6 +2838,7 @@ cairo_surface_create_similar (cairo_surface_t *other,
ret = DLCALL (cairo_surface_create_similar, other, content, width, height);
surface_id = _create_surface_id (ret);
+ _emit_line_info ();
if (other != NULL && _write_lock ()) {
other_id = _get_surface_id (other);
@@ -2447,27 +2884,43 @@ _emit_surface_op (cairo_surface_t *surface, const char *fmt, ...)
void
cairo_surface_finish (cairo_surface_t *surface)
{
+ _emit_line_info ();
return DLCALL (cairo_surface_finish, surface);
}
void
cairo_surface_flush (cairo_surface_t *surface)
{
+ _emit_line_info ();
return DLCALL (cairo_surface_flush, surface);
}
void
cairo_surface_mark_dirty (cairo_surface_t *surface)
{
- /* XXX send update rect? */
+ _emit_line_info ();
+ if (surface != NULL && _write_lock ()) {
+ _emit_surface (surface);
+ fprintf (logfile, "%% mark_dirty\n");
+ _emit_source_image (surface);
+ _write_unlock ();
+ }
return DLCALL (cairo_surface_mark_dirty, surface);
}
void
-cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, int x, int y, int width, int height)
+cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
+ int x, int y, int width, int height)
{
- /* XXX send update rect? */
+ _emit_line_info ();
+ if (surface != NULL && _write_lock ()) {
+ _emit_surface (surface);
+ fprintf (logfile, "%% %d %d %d %d mark_dirty_rectangle\n",
+ x, y, width, height);
+ _emit_source_image_rectangle (surface, x,y, width, height);
+ _write_unlock ();
+ }
return DLCALL (cairo_surface_mark_dirty_rectangle, surface, x, y, width, height);
}
@@ -2475,6 +2928,7 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, int x, int y, int
void
cairo_surface_set_device_offset (cairo_surface_t *surface, double x_offset, double y_offset)
{
+ _emit_line_info ();
_emit_surface_op (surface, "%g %g set_device_offset\n",
x_offset, y_offset);
return DLCALL (cairo_surface_set_device_offset, surface, x_offset, y_offset);
@@ -2483,6 +2937,7 @@ cairo_surface_set_device_offset (cairo_surface_t *surface, double x_offset, doub
void
cairo_surface_set_fallback_resolution (cairo_surface_t *surface, double x_pixels_per_inch, double y_pixels_per_inch)
{
+ _emit_line_info ();
_emit_surface_op (surface, "%g %g set_fallback_resolution\n",
x_pixels_per_inch, y_pixels_per_inch);
return DLCALL (cairo_surface_set_fallback_resolution, surface, x_pixels_per_inch, y_pixels_per_inch);
@@ -2491,6 +2946,7 @@ cairo_surface_set_fallback_resolution (cairo_surface_t *surface, double x_pixels
void
cairo_surface_copy_page (cairo_surface_t *surface)
{
+ _emit_line_info ();
_emit_surface_op (surface, "copy_page\n");
return DLCALL (cairo_surface_copy_page, surface);
}
@@ -2498,16 +2954,45 @@ cairo_surface_copy_page (cairo_surface_t *surface)
void
cairo_surface_show_page (cairo_surface_t *surface)
{
+ _emit_line_info ();
_emit_surface_op (surface, "show_page\n");
return DLCALL (cairo_surface_show_page, surface);
}
cairo_status_t
+cairo_surface_set_mime_data (cairo_surface_t *surface,
+ const char *mime_type,
+ const unsigned char *data,
+ unsigned int length,
+ cairo_destroy_func_t destroy,
+ void *closure)
+{
+ _emit_line_info ();
+ if (surface != NULL && _write_lock ()) {
+ _emit_surface (surface);
+ _emit_string_literal (mime_type, -1);
+ fprintf (logfile, " ");
+ _emit_data (data, length);
+ fprintf (logfile, " /deflate filter set_mime_data\n");
+
+ _write_unlock ();
+ }
+
+ return DLCALL (cairo_surface_set_mime_data,
+ surface,
+ mime_type,
+ data, length,
+ destroy,
+ closure);
+}
+
+cairo_status_t
cairo_surface_write_to_png (cairo_surface_t *surface, const char *filename)
{
+ _emit_line_info ();
if (surface != NULL && _write_lock ()) {
fprintf (logfile, "%% s%ld ", _get_surface_id (surface));
- _emit_string_literal (filename);
+ _emit_string_literal (filename, -1);
fprintf (logfile, " write_to_png\n");
_write_unlock ();
}
@@ -2519,12 +3004,14 @@ cairo_surface_write_to_png_stream (cairo_surface_t *surface,
cairo_write_func_t write_func,
void *data)
{
+ _emit_line_info ();
if (surface != NULL && _write_lock ()) {
char symbol[1024];
fprintf (logfile, "%% s%ld ", _get_surface_id (surface));
- lookup_symbol (symbol, sizeof (symbol), write_func);
- _emit_string_literal (symbol);
+ _emit_string_literal (lookup_symbol (symbol, sizeof (symbol),
+ write_func),
+ -1);
fprintf (logfile, " write_to_png_stream\n");
_write_unlock ();
}
@@ -2558,6 +3045,7 @@ cairo_pattern_create_rgb (double red, double green, double blue)
ret = DLCALL (cairo_pattern_create_rgb, red, green, blue);
pattern_id = _create_pattern_id (ret);
+ _emit_line_info ();
if (_write_lock ()) {
fprintf (logfile, "/p%ld %g %g %g rgb def\n",
pattern_id, red, green, blue);
@@ -2577,6 +3065,7 @@ cairo_pattern_create_rgba (double red, double green, double blue, double alpha)
ret = DLCALL (cairo_pattern_create_rgba, red, green, blue, alpha);
pattern_id = _create_pattern_id (ret);
+ _emit_line_info ();
if (_write_lock ()) {
fprintf (logfile, "/p%ld %g %g %g %g rgba def\n",
pattern_id, red, green, blue, alpha);
@@ -2597,6 +3086,7 @@ cairo_pattern_create_for_surface (cairo_surface_t *surface)
ret = DLCALL (cairo_pattern_create_for_surface, surface);
pattern_id = _create_pattern_id (ret);
+ _emit_line_info ();
if (surface != NULL && _write_lock ()) {
surface_id = _get_surface_id (surface);
@@ -2605,6 +3095,10 @@ cairo_pattern_create_for_surface (cairo_surface_t *surface)
} else {
fprintf (logfile, "s%ld ", surface_id);
}
+
+ if (_get_object (SURFACE, surface)->foreign)
+ _emit_source_image (surface);
+
fprintf (logfile, "pattern %% p%ld\n", pattern_id);
_push_operand (PATTERN, ret);
_write_unlock ();
@@ -2622,6 +3116,7 @@ cairo_pattern_create_linear (double x0, double y0, double x1, double y1)
ret = DLCALL (cairo_pattern_create_linear, x0, y0, x1, y1);
pattern_id = _create_pattern_id (ret);
+ _emit_line_info ();
if (_write_lock ()) {
fprintf (logfile,
"%g %g %g %g linear %% p%ld\n",
@@ -2644,6 +3139,7 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0, double cx1,
cx1, cy1, radius1);
pattern_id = _create_pattern_id (ret);
+ _emit_line_info ();
if (_write_lock ()) {
fprintf (logfile,
"%g %g %g %g %g %g radial %% p%ld\n",
@@ -2659,6 +3155,7 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0, double cx1,
void
cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern, double offset, double red, double green, double blue)
{
+ _emit_line_info ();
_emit_pattern_op (pattern,
"%g %g %g %g 1 add_color_stop\n",
offset, red, green, blue);
@@ -2668,6 +3165,7 @@ cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern, double offset, doubl
void
cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern, double offset, double red, double green, double blue, double alpha)
{
+ _emit_line_info ();
_emit_pattern_op (pattern,
"%g %g %g %g %g add_color_stop\n",
offset, red, green, blue, alpha);
@@ -2677,11 +3175,16 @@ cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern, double offset, doub
void
cairo_pattern_set_matrix (cairo_pattern_t *pattern, const cairo_matrix_t *matrix)
{
- _emit_pattern_op (pattern,
- "[%g %g %g %g %g %g] set_matrix\n",
- matrix->xx, matrix->yx,
- matrix->xy, matrix->yy,
- matrix->x0, matrix->y0);
+ _emit_line_info ();
+ if (_matrix_is_identity (matrix)) {
+ _emit_pattern_op (pattern, "identity set_matrix\n");
+ } else {
+ _emit_pattern_op (pattern,
+ "%g %g %g %g %g %g matrix set_matrix\n",
+ matrix->xx, matrix->yx,
+ matrix->xy, matrix->yy,
+ matrix->x0, matrix->y0);
+ }
return DLCALL (cairo_pattern_set_matrix, pattern, matrix);
}
@@ -2702,7 +3205,8 @@ _filter_to_string (cairo_filter_t filter)
void
cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter)
{
- _emit_pattern_op (pattern, "%s set_filter\n", _filter_to_string (filter));
+ _emit_line_info ();
+ _emit_pattern_op (pattern, "//%s set_filter\n", _filter_to_string (filter));
return DLCALL (cairo_pattern_set_filter, pattern, filter);
}
@@ -2721,11 +3225,12 @@ _extend_to_string (cairo_extend_t extend)
void
cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend)
{
+ _emit_line_info ();
_emit_pattern_op (pattern, "//%s set_extend\n", _extend_to_string (extend));
return DLCALL (cairo_pattern_set_extend, pattern, extend);
}
-#ifdef CAIRO_HAS_FT_FONT
+#if CAIRO_HAS_FT_FONT
cairo_font_face_t *
cairo_ft_font_face_create_for_pattern (FcPattern *pattern)
{
@@ -2735,6 +3240,7 @@ cairo_ft_font_face_create_for_pattern (FcPattern *pattern)
ret = DLCALL (cairo_ft_font_face_create_for_pattern, pattern);
font_face_id = _create_font_face_id (ret);
+ _emit_line_info ();
if (pattern != NULL && _write_lock ()) {
FcChar8 *parsed;
@@ -2743,7 +3249,7 @@ cairo_ft_font_face_create_for_pattern (FcPattern *pattern)
"dict\n"
" /type 42 set\n"
" /pattern ");
- _emit_string_literal ((char *) parsed);
+ _emit_string_literal ((char *) parsed, -1);
fprintf (logfile,
" set\n"
" font\n");
@@ -2789,6 +3295,7 @@ cairo_ft_font_face_create_for_ft_face (FT_Face face, int load_flags)
if (data == NULL)
return ret;
+ _emit_line_info ();
if (_write_lock ()) {
fprintf (logfile,
"dict\n"
@@ -2909,7 +3416,7 @@ FT_Done_Face (FT_Face face)
}
#endif
-#ifdef CAIRO_HAS_PS_SURFACE
+#if CAIRO_HAS_PS_SURFACE
#include<cairo-ps.h>
cairo_surface_t *
@@ -2921,12 +3428,13 @@ cairo_ps_surface_create (const char *filename, double width_in_points, double he
ret = DLCALL (cairo_ps_surface_create, filename, width_in_points, height_in_points);
surface_id = _create_surface_id (ret);
+ _emit_line_info ();
if (_write_lock ()) {
fprintf (logfile,
"dict\n"
- " /type (PS) set\n"
+ " /type /PS set\n"
" /filename ");
- _emit_string_literal (filename);
+ _emit_string_literal (filename, -1);
fprintf (logfile,
" set\n"
" /width %g set\n"
@@ -2935,6 +3443,8 @@ cairo_ps_surface_create (const char *filename, double width_in_points, double he
width_in_points,
height_in_points,
surface_id);
+ _get_object (SURFACE, ret)->width = width_in_points;
+ _get_object (SURFACE, ret)->height = height_in_points;
_push_operand (SURFACE, ret);
_write_unlock ();
}
@@ -2951,16 +3461,19 @@ cairo_ps_surface_create_for_stream (cairo_write_func_t write_func, void *closure
ret = DLCALL (cairo_ps_surface_create_for_stream, write_func, closure, width_in_points, height_in_points);
surface_id = _create_surface_id (ret);
+ _emit_line_info ();
if (_write_lock ()) {
fprintf (logfile,
"dict\n"
- " /type (PS) set\n"
+ " /type /PS set\n"
" /width %g set\n"
" /height %g set\n"
" surface %% s%ld\n",
width_in_points,
height_in_points,
surface_id);
+ _get_object (SURFACE, ret)->width = width_in_points;
+ _get_object (SURFACE, ret)->height = height_in_points;
_push_operand (SURFACE, ret);
_write_unlock ();
}
@@ -2971,12 +3484,13 @@ cairo_ps_surface_create_for_stream (cairo_write_func_t write_func, void *closure
void
cairo_ps_surface_set_size (cairo_surface_t *surface, double width_in_points, double height_in_points)
{
+ _emit_line_info ();
return DLCALL (cairo_ps_surface_set_size, surface, width_in_points, height_in_points);
}
#endif
-#ifdef CAIRO_HAS_PDF_SURFACE
+#if CAIRO_HAS_PDF_SURFACE
#include <cairo-pdf.h>
cairo_surface_t *
@@ -2988,12 +3502,13 @@ cairo_pdf_surface_create (const char *filename, double width_in_points, double h
ret = DLCALL (cairo_pdf_surface_create, filename, width_in_points, height_in_points);
surface_id = _create_surface_id (ret);
+ _emit_line_info ();
if (_write_lock ()) {
fprintf (logfile,
"dict\n"
- " /type (PDF) set\n"
+ " /type /PDF set\n"
" /filename ");
- _emit_string_literal (filename);
+ _emit_string_literal (filename, -1);
fprintf (logfile,
" set\n"
" /width %g set\n"
@@ -3002,6 +3517,8 @@ cairo_pdf_surface_create (const char *filename, double width_in_points, double h
width_in_points,
height_in_points,
surface_id);
+ _get_object (SURFACE, ret)->width = width_in_points;
+ _get_object (SURFACE, ret)->height = height_in_points;
_push_operand (SURFACE, ret);
_write_unlock ();
}
@@ -3018,16 +3535,19 @@ cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func, void *closur
ret = DLCALL (cairo_pdf_surface_create_for_stream, write_func, closure, width_in_points, height_in_points);
surface_id = _create_surface_id (ret);
+ _emit_line_info ();
if (_write_lock ()) {
fprintf (logfile,
"dict\n"
- " /type (PDF) set\n"
+ " /type /PDF set\n"
" /width %g set\n"
" /height %g set\n"
" surface %% s%ld\n",
width_in_points,
height_in_points,
surface_id);
+ _get_object (SURFACE, ret)->width = width_in_points;
+ _get_object (SURFACE, ret)->height = height_in_points;
_push_operand (SURFACE, ret);
_write_unlock ();
}
@@ -3037,11 +3557,12 @@ cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func, void *closur
void
cairo_pdf_surface_set_size (cairo_surface_t *surface, double width_in_points, double height_in_points)
{
+ _emit_line_info ();
return DLCALL (cairo_pdf_surface_set_size, surface, width_in_points, height_in_points);
}
#endif
-#ifdef CAIRO_HAS_SVG_SURFACE
+#if CAIRO_HAS_SVG_SURFACE
#include <cairo-svg.h>
cairo_surface_t *
@@ -3053,12 +3574,13 @@ cairo_svg_surface_create (const char *filename, double width, double height)
ret = DLCALL (cairo_svg_surface_create, filename, width, height);
surface_id = _create_surface_id (ret);
+ _emit_line_info ();
if (_write_lock ()) {
fprintf (logfile,
"dict\n"
- " /type (SVG) set\n"
+ " /type /SVG set\n"
" /filename ");
- _emit_string_literal (filename);
+ _emit_string_literal (filename, -1);
fprintf (logfile,
" set\n"
" /width %g set\n"
@@ -3067,6 +3589,8 @@ cairo_svg_surface_create (const char *filename, double width, double height)
width,
height,
surface_id);
+ _get_object (SURFACE, ret)->width = width;
+ _get_object (SURFACE, ret)->height = height;
_push_operand (SURFACE, ret);
_write_unlock ();
}
@@ -3083,16 +3607,19 @@ cairo_svg_surface_create_for_stream (cairo_write_func_t write_func, void *closur
ret = DLCALL (cairo_svg_surface_create_for_stream, write_func, closure, width, height);
surface_id = _create_surface_id (ret);
+ _emit_line_info ();
if (_write_lock ()) {
fprintf (logfile,
"dict\n"
- " /type (SVG) set\n"
+ " /type /SVG set\n"
" /width %g set\n"
" /height %g set\n"
" surface %% s%ld\n",
width,
height,
surface_id);
+ _get_object (SURFACE, ret)->width = width;
+ _get_object (SURFACE, ret)->height = height;
_push_operand (SURFACE, ret);
_write_unlock ();
}
@@ -3106,38 +3633,24 @@ cairo_surface_t *
cairo_image_surface_create_from_png (const char *filename)
{
cairo_surface_t *ret;
- cairo_format_t format;
- int width;
- int height;
long surface_id;
- const char *format_str;
ret = DLCALL (cairo_image_surface_create_from_png, filename);
- width = cairo_image_surface_get_width (ret);
- height = cairo_image_surface_get_height (ret);
- format = cairo_image_surface_get_format (ret);
-
surface_id = _create_surface_id (ret);
- format_str = _format_to_string (format);
+ _emit_line_info ();
if (_write_lock ()) {
+ char filename_string[4096];
+
+ _encode_string_literal (filename_string, sizeof (filename_string),
+ filename, -1);
+ _emit_image (ret, " /filename %s set\n", filename_string);
fprintf (logfile,
- "dict\n"
- " /width %d set\n"
- " /height %d set\n"
- " /format //%s set\n"
- " /filename ",
- width, height, format_str);
- _emit_string_literal (filename);
- fprintf (logfile,
- " set\n"
- " /source ");
- _emit_image (ret);
- fprintf (logfile,
- " /deflate filter set\n"
- " image dup /s%ld exch def\n",
+ " dup /s%ld exch def\n",
surface_id);
+ _get_object (SURFACE, ret)->width = cairo_image_surface_get_width (ret);
+ _get_object (SURFACE, ret)->height = cairo_image_surface_get_height (ret);
_get_object (SURFACE, ret)->defined = true;
_push_operand (SURFACE, ret);
_write_unlock ();
@@ -3150,33 +3663,19 @@ cairo_surface_t *
cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func, void *closure)
{
cairo_surface_t *ret;
- cairo_format_t format;
- int width;
- int height;
- const char *format_str;
long surface_id;
ret = DLCALL (cairo_image_surface_create_from_png_stream, read_func, closure);
- width = cairo_image_surface_get_width (ret);
- height = cairo_image_surface_get_height (ret);
- format = cairo_image_surface_get_format (ret);
-
surface_id = _create_surface_id (ret);
- format_str = _format_to_string (format);
+ _emit_line_info ();
if (_write_lock ()) {
+ _emit_image (ret, NULL);
fprintf (logfile,
- "dict\n"
- " /width %d set\n"
- " /height %d set\n"
- " /format //%s set\n"
- " /source ",
- width, height, format_str);
- _emit_image (ret);
- fprintf (logfile,
- " /deflate filter set\n"
- " image dup /s%ld exch def\n",
+ " dup /s%ld exch def\n",
surface_id);
+ _get_object (SURFACE, ret)->width = cairo_image_surface_get_width (ret);
+ _get_object (SURFACE, ret)->height = cairo_image_surface_get_height (ret);
_get_object (SURFACE, ret)->defined = true;
_push_operand (SURFACE, ret);
_write_unlock ();
@@ -3185,11 +3684,14 @@ cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func, void *c
return ret;
}
-#ifdef CAIRO_HAS_XLIB_SURFACE
+#if CAIRO_HAS_XLIB_SURFACE
#include <cairo-xlib.h>
cairo_surface_t *
-cairo_xlib_surface_create (Display *dpy, Drawable drawable, Visual *visual, int width, int height)
+cairo_xlib_surface_create (Display *dpy,
+ Drawable drawable,
+ Visual *visual,
+ int width, int height)
{
cairo_surface_t *ret;
long surface_id;
@@ -3198,17 +3700,23 @@ cairo_xlib_surface_create (Display *dpy, Drawable drawable, Visual *visual, int
dpy, drawable, visual, width, height);
surface_id = _create_surface_id (ret);
+ _emit_line_info ();
if (_write_lock ()) {
fprintf (logfile,
"dict\n"
- " /type (xlib) set\n"
+ " /type /xlib set\n"
+ " /drawable 16!%lx set\n"
" /width %d set\n"
" /height %d set\n"
" surface dup /s%ld exch def\n",
+ drawable,
width,
height,
surface_id);
_get_object (SURFACE, ret)->defined = true;
+ _get_object (SURFACE, ret)->width = width;
+ _get_object (SURFACE, ret)->height = height;
+ _get_object (SURFACE, ret)->foreign = true;
_push_operand (SURFACE, ret);
_write_unlock ();
}
@@ -3217,7 +3725,10 @@ cairo_xlib_surface_create (Display *dpy, Drawable drawable, Visual *visual, int
}
cairo_surface_t *
-cairo_xlib_surface_create_for_bitmap (Display *dpy, Pixmap bitmap, Screen *screen, int width, int height)
+cairo_xlib_surface_create_for_bitmap (Display *dpy,
+ Pixmap bitmap,
+ Screen *screen,
+ int width, int height)
{
cairo_surface_t *ret;
long surface_id;
@@ -3226,18 +3737,24 @@ cairo_xlib_surface_create_for_bitmap (Display *dpy, Pixmap bitmap, Screen *scree
dpy, bitmap, screen, width, height);
surface_id = _create_surface_id (ret);
+ _emit_line_info ();
if (_write_lock ()) {
fprintf (logfile,
"dict\n"
- " /type (xlib) set\n"
+ " /type /xlib set\n"
+ " /drawable 16!%lx set\n"
" /width %d set\n"
" /height %d set\n"
" /depth 1 set\n"
" surface dup /s%ld exch def\n",
+ bitmap,
width,
height,
surface_id);
_get_object (SURFACE, ret)->defined = true;
+ _get_object (SURFACE, ret)->width = width;
+ _get_object (SURFACE, ret)->height = height;
+ _get_object (SURFACE, ret)->foreign = true;
_push_operand (SURFACE, ret);
_write_unlock ();
}
@@ -3245,10 +3762,14 @@ cairo_xlib_surface_create_for_bitmap (Display *dpy, Pixmap bitmap, Screen *scree
return ret;
}
-#ifdef CAIRO_HAS_XLIB_XRENDER_SURFACE
+#if CAIRO_HAS_XLIB_XRENDER_SURFACE
#include <cairo-xlib-xrender.h>
cairo_surface_t *
-cairo_xlib_surface_create_with_xrender_format (Display *dpy, Drawable drawable, Screen *screen, XRenderPictFormat *format, int width, int height)
+cairo_xlib_surface_create_with_xrender_format (Display *dpy,
+ Drawable drawable,
+ Screen *screen,
+ XRenderPictFormat *format,
+ int width, int height)
{
cairo_surface_t *ret;
long surface_id;
@@ -3257,19 +3778,25 @@ cairo_xlib_surface_create_with_xrender_format (Display *dpy, Drawable drawable,
dpy, drawable, screen, format, width, height);
surface_id = _create_surface_id (ret);
+ _emit_line_info ();
if (_write_lock ()) {
fprintf (logfile,
"dict\n"
- " /type (xrender) set\n"
+ " /type /xrender set\n"
+ " /drawable 16!%lx set\n"
" /width %d set\n"
" /height %d set\n"
" /depth %d set\n"
" surface dup /s%ld exch def\n",
+ drawable,
width,
height,
format->depth,
surface_id);
_get_object (SURFACE, ret)->defined = true;
+ _get_object (SURFACE, ret)->width = width;
+ _get_object (SURFACE, ret)->height = height;
+ _get_object (SURFACE, ret)->foreign = true;
_push_operand (SURFACE, ret);
_write_unlock ();
}
@@ -3279,7 +3806,7 @@ cairo_xlib_surface_create_with_xrender_format (Display *dpy, Drawable drawable,
#endif
#endif
-#ifdef CAIRO_HAS_SCRIPT_SURFACE
+#if CAIRO_HAS_SCRIPT_SURFACE
#include <cairo-script.h>
cairo_surface_t *
cairo_script_surface_create (const char *filename,
@@ -3292,12 +3819,13 @@ cairo_script_surface_create (const char *filename,
ret = DLCALL (cairo_script_surface_create, filename, width, height);
surface_id = _create_surface_id (ret);
+ _emit_line_info ();
if (_write_lock ()) {
fprintf (logfile,
"dict\n"
- " /type (script) set\n"
+ " /type /script set\n"
" /filename ");
- _emit_string_literal (filename);
+ _emit_string_literal (filename, -1);
fprintf (logfile,
" set\n"
" /width %g set\n"
@@ -3305,6 +3833,8 @@ cairo_script_surface_create (const char *filename,
" surface dup /s%ld exch def\n",
width, height,
surface_id);
+ _get_object (SURFACE, ret)->width = width;
+ _get_object (SURFACE, ret)->height = height;
_get_object (SURFACE, ret)->defined = true;
_push_operand (SURFACE, ret);
_write_unlock ();
@@ -3326,15 +3856,127 @@ cairo_script_surface_create_for_stream (cairo_write_func_t write_func,
write_func, data, width, height);
surface_id = _create_surface_id (ret);
+ _emit_line_info ();
if (_write_lock ()) {
fprintf (logfile,
"dict\n"
- " /type (script) set\n"
+ " /type /script set\n"
" /width %g set\n"
" /height %g set\n"
" surface dup /s%ld exch def\n",
width, height,
surface_id);
+ _get_object (SURFACE, ret)->width = width;
+ _get_object (SURFACE, ret)->height = height;
+ _get_object (SURFACE, ret)->defined = true;
+ _push_operand (SURFACE, ret);
+ _write_unlock ();
+ }
+
+ return ret;
+}
+#endif
+
+#if CAIRO_HAS_TEST_SURFACES
+#include <test-fallback-surface.h>
+cairo_surface_t *
+_cairo_test_fallback_surface_create (cairo_content_t content,
+ int width,
+ int height)
+{
+ cairo_surface_t *ret;
+ long surface_id;
+
+ ret = DLCALL (_cairo_test_fallback_surface_create, content, width, height);
+ surface_id = _create_surface_id (ret);
+
+ _emit_line_info ();
+ if (_write_lock ()) {
+ fprintf (logfile,
+ "dict\n"
+ " /type /test-fallback set\n"
+ " /content //%s set\n"
+ " /width %d set\n"
+ " /height %d set\n"
+ " surface dup /s%ld exch def\n",
+ _content_to_string (content),
+ width, height,
+ surface_id);
+ _get_object (SURFACE, ret)->width = width;
+ _get_object (SURFACE, ret)->height = height;
+ _get_object (SURFACE, ret)->defined = true;
+ _push_operand (SURFACE, ret);
+ _write_unlock ();
+ }
+
+ return ret;
+}
+
+#include <test-paginated-surface.h>
+cairo_surface_t *
+_cairo_test_paginated_surface_create_for_data (unsigned char *data,
+ cairo_content_t content,
+ int width,
+ int height,
+ int stride)
+{
+ cairo_surface_t *ret;
+ long surface_id;
+
+ ret = DLCALL (_cairo_test_paginated_surface_create_for_data,
+ data, content, width, height, stride);
+ surface_id = _create_surface_id (ret);
+
+ _emit_line_info ();
+ if (_write_lock ()) {
+ /* XXX store initial data? */
+ fprintf (logfile,
+ "dict\n"
+ " /type /test-paginated set\n"
+ " /content //%s set\n"
+ " /width %d set\n"
+ " /height %d set\n"
+ " /stride %d set\n"
+ " surface dup /s%ld exch def\n",
+ _content_to_string (content),
+ width, height, stride,
+ surface_id);
+ _get_object (SURFACE, ret)->width = width;
+ _get_object (SURFACE, ret)->height = height;
+ _get_object (SURFACE, ret)->defined = true;
+ _push_operand (SURFACE, ret);
+ _write_unlock ();
+ }
+
+ return ret;
+}
+
+#include <test-meta-surface.h>
+cairo_surface_t *
+_cairo_test_meta_surface_create (cairo_content_t content,
+ int width,
+ int height)
+{
+ cairo_surface_t *ret;
+ long surface_id;
+
+ ret = DLCALL (_cairo_test_meta_surface_create, content, width, height);
+ surface_id = _create_surface_id (ret);
+
+ _emit_line_info ();
+ if (_write_lock ()) {
+ fprintf (logfile,
+ "dict\n"
+ " /type /test-meta set\n"
+ " /content //%s set\n"
+ " /width %d set\n"
+ " /height %d set\n"
+ " surface dup /s%ld exch def\n",
+ _content_to_string (content),
+ width, height,
+ surface_id);
+ _get_object (SURFACE, ret)->width = width;
+ _get_object (SURFACE, ret)->height = height;
_get_object (SURFACE, ret)->defined = true;
_push_operand (SURFACE, ret);
_write_unlock ();