summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml156
-rw-r--r--.gitlab-ci/ignore-ps2-argb32.txt207
-rw-r--r--.gitlab-ci/ignore-ps2-rgb24.txt197
-rw-r--r--.gitlab-ci/ignore-ps3-argb32.txt218
-rw-r--r--.gitlab-ci/ignore-ps3-rgb24.txt209
-rw-r--r--.gitlab-ci/ignore-quartz-argb32.txt1
-rw-r--r--.gitlab-ci/ignore-quartz-rgb24.txt2
-rw-r--r--.gitlab-ci/ignore-svg11-argb32.txt1
-rw-r--r--.gitlab-ci/ignore-svg11-rgb24.txt1
-rw-r--r--BIBLIOGRAPHY109
-rw-r--r--CODING_STYLE1
-rw-r--r--INSTALL205
-rw-r--r--INSTALL.meson57
-rw-r--r--KNOWN_ISSUES3
-rw-r--r--Makefile.am118
-rw-r--r--Makefile.win3224
-rw-r--r--NEWS52
-rw-r--r--PORTING_GUIDE265
-rw-r--r--README184
-rw-r--r--README.md177
-rw-r--r--RELEASING215
-rw-r--r--acinclude.m455
-rwxr-xr-xautogen.sh31
-rw-r--r--boilerplate/Makefile.am56
-rw-r--r--boilerplate/Makefile.sources34
-rw-r--r--boilerplate/Makefile.win3224
-rw-r--r--boilerplate/Makefile.win32.features353
-rw-r--r--boilerplate/cairo-boilerplate-egl.c192
-rw-r--r--boilerplate/cairo-boilerplate-glx.c457
-rw-r--r--boilerplate/cairo-boilerplate-quartz.c6
-rw-r--r--boilerplate/cairo-boilerplate-wgl.c239
-rw-r--r--boilerplate/cairo-boilerplate-win32-printing.c8
-rw-r--r--boilerplate/meson.build4
-rw-r--r--build/.gitignore16
-rw-r--r--build/Makefile.am.analysis37
-rw-r--r--build/Makefile.am.changelog82
-rw-r--r--build/Makefile.am.common14
-rw-r--r--build/Makefile.am.gtk-doc173
-rw-r--r--build/Makefile.am.releasing194
-rw-r--r--build/Makefile.win32.common74
-rw-r--r--build/Makefile.win32.features33
-rw-r--r--build/Makefile.win32.features-h106
-rw-r--r--build/Makefile.win32.inform13
-rw-r--r--build/aclocal.cairo.m4228
-rw-r--r--build/aclocal.compare.m4162
-rw-r--r--build/aclocal.enable.m4409
-rw-r--r--build/aclocal.float.m468
-rw-r--r--build/aclocal.gtk-doc.m439
-rw-r--r--build/aclocal.makefile.m4234
-rw-r--r--build/aclocal.pkg.m4157
-rw-r--r--build/configure.ac.analysis106
-rw-r--r--build/configure.ac.features416
-rw-r--r--build/configure.ac.noversion23
-rw-r--r--build/configure.ac.pthread253
-rw-r--r--build/configure.ac.system170
-rw-r--r--build/configure.ac.tools24
-rw-r--r--build/configure.ac.version42
-rw-r--r--build/configure.ac.warnings99
-rw-r--r--configure.ac816
-rw-r--r--doc/Makefile.am7
-rw-r--r--doc/bibliography.md103
-rw-r--r--doc/public/Makefile.am60
-rw-r--r--doc/public/cairo-docs.xml41
-rw-r--r--doc/public/cairo-sections.txt18
-rw-r--r--doc/public/language-bindings.xml10
-rw-r--r--doc/public/meson.build2
-rw-r--r--doc/releasing.md175
-rw-r--r--meson-cc-tests/fuzzer.c7
-rw-r--r--meson.build182
-rw-r--r--meson_options.txt12
-rw-r--r--perf/Makefile.am154
-rw-r--r--perf/Makefile.sources38
-rw-r--r--perf/Makefile.win3278
-rw-r--r--perf/cairo-perf-chart.c2
-rw-r--r--perf/cairo-perf-graph-files.c15
-rw-r--r--perf/cairo-perf-graph-widget.c2
-rw-r--r--perf/cairo-perf.c1
-rw-r--r--perf/dirent-win32.h1
-rw-r--r--perf/micro/Makefile.am16
-rw-r--r--perf/micro/Makefile.sources51
-rw-r--r--perf/micro/Makefile.win3212
-rw-r--r--src/Makefile.am99
-rw-r--r--src/Makefile.am.analysis35
-rw-r--r--src/Makefile.sources405
-rw-r--r--src/Makefile.win3228
-rw-r--r--src/Makefile.win32.features459
-rw-r--r--src/cairo-analysis-surface-private.h15
-rw-r--r--src/cairo-analysis-surface.c160
-rw-r--r--src/cairo-array.c14
-rw-r--r--src/cairo-atomic-private.h8
-rw-r--r--src/cairo-atomic.c34
-rw-r--r--src/cairo-boxes.c31
-rw-r--r--src/cairo-cache.c10
-rw-r--r--src/cairo-cff-subset.c20
-rw-r--r--src/cairo-colr-glyph-render.c1248
-rw-r--r--src/cairo-debug.c99
-rw-r--r--src/cairo-device.c1
-rw-r--r--src/cairo-dwrite.h (renamed from src/cairo-xml.h)51
-rw-r--r--src/cairo-egl-context.c317
-rw-r--r--src/cairo-error-private.h1
-rw-r--r--src/cairo-features-uninstalled.pc.in7
-rw-r--r--src/cairo-features.pc.in12
-rw-r--r--src/cairo-font-options.c171
-rw-r--r--src/cairo-ft-font.c1105
-rw-r--r--src/cairo-ft-private.h36
-rw-r--r--src/cairo-gl-composite.c1364
-rw-r--r--src/cairo-gl-device.c851
-rw-r--r--src/cairo-gl-dispatch-private.h129
-rw-r--r--src/cairo-gl-dispatch.c273
-rw-r--r--src/cairo-gl-ext-def-private.h143
-rw-r--r--src/cairo-gl-glyphs.c507
-rw-r--r--src/cairo-gl-gradient-private.h96
-rw-r--r--src/cairo-gl-gradient.c339
-rw-r--r--src/cairo-gl-info.c147
-rw-r--r--src/cairo-gl-msaa-compositor.c956
-rw-r--r--src/cairo-gl-operand.c793
-rw-r--r--src/cairo-gl-private.h865
-rw-r--r--src/cairo-gl-shaders.c1111
-rw-r--r--src/cairo-gl-source.c113
-rw-r--r--src/cairo-gl-spans-compositor.c556
-rw-r--r--src/cairo-gl-surface-legacy.c602
-rw-r--r--src/cairo-gl-surface.c1552
-rw-r--r--src/cairo-gl-traps-compositor.c531
-rw-r--r--src/cairo-gl.h155
-rw-r--r--src/cairo-glx-context.c324
-rw-r--r--src/cairo-gstate.c8
-rw-r--r--src/cairo-image-info.c30
-rw-r--r--src/cairo-image-source.c6
-rw-r--r--src/cairo-lzw.c9
-rw-r--r--src/cairo-matrix.c10
-rw-r--r--src/cairo-mesh-pattern-rasterizer.c2
-rw-r--r--src/cairo-misc.c38
-rw-r--r--src/cairo-mutex-impl-private.h9
-rw-r--r--src/cairo-mutex-list-private.h4
-rw-r--r--src/cairo-output-stream.c15
-rw-r--r--src/cairo-paginated-private.h4
-rw-r--r--src/cairo-paginated-surface.c40
-rw-r--r--src/cairo-path-stroke-polygon.c95
-rw-r--r--src/cairo-path-stroke-traps.c32
-rw-r--r--src/cairo-pattern-private.h11
-rw-r--r--src/cairo-pattern.c41
-rw-r--r--src/cairo-pdf-surface-private.h17
-rw-r--r--src/cairo-pdf-surface.c468
-rw-r--r--src/cairo-png.c1
-rw-r--r--src/cairo-ps-surface-private.h1
-rw-r--r--src/cairo-ps-surface.c111
-rw-r--r--src/cairo-quartz-font.c2
-rw-r--r--src/cairo-quartz-image-surface.c169
-rw-r--r--src/cairo-quartz-private.h25
-rw-r--r--src/cairo-quartz-surface.c443
-rw-r--r--src/cairo-recording-surface-private.h70
-rw-r--r--src/cairo-recording-surface.c574
-rw-r--r--src/cairo-region.c1
-rw-r--r--src/cairo-scaled-font-private.h10
-rw-r--r--src/cairo-scaled-font-subsets-private.h37
-rw-r--r--src/cairo-scaled-font-subsets.c119
-rwxr-xr-xsrc/cairo-scaled-font.c82
-rw-r--r--src/cairo-script-surface.c25
-rw-r--r--src/cairo-shape-mask-compositor.c6
-rw-r--r--src/cairo-spans-compositor.c2
-rw-r--r--src/cairo-spans.c2
-rw-r--r--src/cairo-spline.c2
-rw-r--r--src/cairo-surface-backend-private.h14
-rw-r--r--src/cairo-surface-observer.c9
-rw-r--r--src/cairo-surface-private.h3
-rw-r--r--src/cairo-surface-wrapper-private.h100
-rw-r--r--src/cairo-surface-wrapper.c163
-rw-r--r--src/cairo-surface.c90
-rw-r--r--src/cairo-svg-glyph-render.c3243
-rw-r--r--src/cairo-svg-surface.c8
-rw-r--r--src/cairo-svg.h6
-rw-r--r--src/cairo-tag-attributes.c5
-rw-r--r--src/cairo-tee-surface-private.h47
-rw-r--r--src/cairo-tee-surface.c65
-rw-r--r--src/cairo-time.c1
-rw-r--r--src/cairo-toy-font-face.c2
-rw-r--r--src/cairo-traps-compositor.c2
-rw-r--r--src/cairo-truetype-subset.c9
-rw-r--r--src/cairo-type3-glyph-surface.c49
-rw-r--r--src/cairo-types-private.h7
-rw-r--r--src/cairo-uninstalled.pc.in8
-rw-r--r--src/cairo-user-font.c203
-rw-r--r--src/cairo-version.h2
-rw-r--r--src/cairo-wgl-context.c261
-rw-r--r--src/cairo-win32.h11
-rw-r--r--src/cairo-xcb-surface-render.c12
-rw-r--r--src/cairo-xlib-source.c3
-rw-r--r--src/cairo-xml-surface.c1212
-rw-r--r--src/cairo.c52
-rw-r--r--src/cairo.h92
-rw-r--r--src/cairo.pc.in13
-rw-r--r--src/cairoint.h141
-rwxr-xr-xsrc/check-def.sh48
-rw-r--r--src/make-cairo-def.sh27
-rw-r--r--src/meson-check-def.sh38
-rw-r--r--src/meson.build66
-rw-r--r--src/win32/cairo-dwrite-font-public.c130
-rw-r--r--src/win32/cairo-dwrite-font.cpp760
-rw-r--r--src/win32/cairo-dwrite-private.hpp121
-rw-r--r--src/win32/cairo-win32-debug.c9
-rw-r--r--src/win32/cairo-win32-device.c9
-rw-r--r--src/win32/cairo-win32-display-surface.c9
-rw-r--r--src/win32/cairo-win32-font.c20
-rw-r--r--src/win32/cairo-win32-gdi-compositor.c3
-rw-r--r--src/win32/cairo-win32-printing-surface.c13
-rw-r--r--src/win32/cairo-win32-private.h7
-rw-r--r--src/win32/cairo-win32-surface.c9
-rw-r--r--src/win32/cairo-win32-system.c9
-rw-r--r--src/win32/dw-extra.h159
-rw-r--r--subprojects/glib.wrap15
-rw-r--r--test/Makefile.am409
-rw-r--r--test/Makefile.sources479
-rw-r--r--test/Makefile.win3255
-rw-r--r--test/README381
-rw-r--r--test/api-special-cases.c41
-rw-r--r--test/bug-277.c94
-rw-r--r--test/bug-535.c51
-rw-r--r--test/cairo-logo-font.ttx539
-rw-r--r--test/cairo-svg-test-color.ttx362
-rw-r--r--test/cairo-svg-test-doc.ttx689
-rw-r--r--test/cairo-svg-test-fill.ttx365
-rw-r--r--test/cairo-svg-test-gradient.ttx441
-rw-r--r--test/cairo-svg-test-path.ttx281
-rw-r--r--test/cairo-svg-test-shapes.ttx333
-rw-r--r--test/cairo-svg-test-stroke.ttx608
-rw-r--r--test/cairo-svg-test-transform.ttx403
-rw-r--r--test/cairo-test-runner.c74
-rw-r--r--test/cairo-test.c67
-rw-r--r--test/cairo-test.h5
-rwxr-xr-xtest/check-refs.sh6
-rw-r--r--test/completion.bash1
-rw-r--r--test/coverage.c122
-rw-r--r--test/create-from-png-16bit.c80
-rw-r--r--test/create-regions.c435
-rw-r--r--test/egl-oversized-surface.c117
-rw-r--r--test/egl-surface-source.c135
-rw-r--r--test/error-setters.c8
-rw-r--r--test/ft-svg-cairo-logo.c66
-rw-r--r--test/ft-svg-color-font.c146
-rw-r--r--test/ft-svg-render-color.c98
-rw-r--r--test/ft-svg-render.c159
-rw-r--r--test/gl-device-release.c182
-rw-r--r--test/gl-oversized-surface.c88
-rw-r--r--test/gl-surface-source.c111
-rw-r--r--test/meson.build68
-rw-r--r--test/pattern-getters.c2
-rw-r--r--test/pdf-operators-text.c1
-rw-r--r--test/pdf-tagged-text.c5
-rw-r--r--test/pdiff/CMakeLists.txt55
-rw-r--r--test/pdiff/Makefile.am19
-rw-r--r--test/pdiff/Makefile.win3214
-rw-r--r--test/reference/arc-direction.pdf.ref.pngbin6175 -> 0 bytes
-rw-r--r--test/reference/big-little-triangle.traps.argb32.ref.pngbin399 -> 0 bytes
-rw-r--r--test/reference/big-little-triangle.traps.rgb24.ref.pngbin320 -> 0 bytes
-rw-r--r--test/reference/bug-535.ref.pngbin0 -> 87 bytes
-rw-r--r--test/reference/clip-fill-rule.pdf.rgb24.ref.pngbin375 -> 0 bytes
-rw-r--r--test/reference/coverage-column-triangles.ref.pngbin208 -> 886 bytes
-rw-r--r--test/reference/coverage-column-triangles.xfail.pngbin7632 -> 560 bytes
-rw-r--r--test/reference/coverage-column-triangles.xlib.xfail.pngbin12745 -> 1364 bytes
-rw-r--r--test/reference/create-from-png-16bit.base.pngbin0 -> 113 bytes
-rw-r--r--test/reference/create-from-png-16bit.image16.ref.pngbin0 -> 98 bytes
-rw-r--r--test/reference/create-from-png-16bit.ref.pngbin0 -> 98 bytes
-rw-r--r--test/reference/create-regions.pdf.ref.pngbin0 -> 3227 bytes
-rw-r--r--test/reference/create-regions.ps.ref.pngbin0 -> 2524 bytes
-rw-r--r--test/reference/create-regions.svg.ref.pngbin0 -> 4514 bytes
-rw-r--r--test/reference/dash-offset-negative.pdf.ref.pngbin129 -> 0 bytes
-rw-r--r--test/reference/font-matrix-translation.traps.ref.pngbin865 -> 0 bytes
-rw-r--r--test/reference/ft-color-font.pdf.ref.pngbin1191 -> 0 bytes
-rw-r--r--test/reference/ft-color-font.pdf.xfail.pngbin0 -> 585 bytes
-rw-r--r--test/reference/ft-show-glyphs-positioning.traps.ref.pngbin3243 -> 0 bytes
-rw-r--r--test/reference/ft-show-glyphs-table.traps.ref.pngbin9975 -> 0 bytes
-rw-r--r--test/reference/ft-svg-cairo-logo.ref.pngbin0 -> 13204 bytes
-rw-r--r--test/reference/ft-svg-color-font.ref.pngbin0 -> 10973 bytes
-rw-r--r--test/reference/ft-svg-render-color.ref.pngbin0 -> 4117 bytes
-rw-r--r--test/reference/ft-svg-render-doc.ref.pngbin0 -> 11069 bytes
-rw-r--r--test/reference/ft-svg-render-fill.ref.pngbin0 -> 1641 bytes
-rw-r--r--test/reference/ft-svg-render-gradient.ref.pngbin0 -> 9156 bytes
-rw-r--r--test/reference/ft-svg-render-path.ref.pngbin0 -> 2570 bytes
-rw-r--r--test/reference/ft-svg-render-shapes.ref.pngbin0 -> 3073 bytes
-rw-r--r--test/reference/ft-svg-render-stroke.ref.pngbin0 -> 2224 bytes
-rw-r--r--test/reference/ft-svg-render-transform.ref.pngbin0 -> 4248 bytes
-rw-r--r--test/reference/glyph-cache-pressure.traps.ref.pngbin2858 -> 0 bytes
-rw-r--r--test/reference/inverse-text.traps.ref.pngbin2162 -> 0 bytes
-rw-r--r--test/reference/line-width-large-overlap-offset.ps.ref.pngbin305 -> 0 bytes
-rw-r--r--test/reference/partial-clip-text-right.traps.ref.pngbin155 -> 0 bytes
-rw-r--r--test/reference/partial-clip-text-top.traps.ref.pngbin181 -> 0 bytes
-rw-r--r--test/reference/quartz-color-font.ref.pngbin2442 -> 2443 bytes
-rw-r--r--test/reference/record-fill-alpha.pdf.ref.pngbin2831 -> 0 bytes
-rw-r--r--test/reference/record-mesh.ps.ref.pngbin15215 -> 0 bytes
-rw-r--r--test/reference/record90-fill-alpha.pdf.ref.pngbin2663 -> 0 bytes
-rw-r--r--test/reference/record90-paint-alpha-clip.quartz.ref.pngbin335 -> 0 bytes
-rw-r--r--test/reference/recordflip-whole-fill-alpha.quartz.ref.pngbin2799 -> 0 bytes
-rw-r--r--test/reference/recordflip-whole-paint-alpha-clip-mask.quartz.ref.pngbin351 -> 0 bytes
-rw-r--r--test/reference/round-join-bug-520-bevel.pdf.ref.pngbin0 -> 705 bytes
-rw-r--r--test/reference/round-join-bug-520-bevel.quartz.ref.pngbin0 -> 673 bytes
-rw-r--r--test/reference/round-join-bug-520-bevel.ref.pngbin0 -> 512 bytes
-rw-r--r--test/reference/round-join-bug-520-bevel.svg.ref.pngbin0 -> 705 bytes
-rw-r--r--test/reference/round-join-bug-520-round.ref.pngbin0 -> 705 bytes
-rw-r--r--test/reference/round-join-bug-520-round.xlib-window.ref.pngbin0 -> 806 bytes
-rw-r--r--test/reference/round-join-bug-520-round.xlib.ref.pngbin0 -> 806 bytes
-rw-r--r--test/reference/select-font-face.traps.ref.pngbin2250 -> 0 bytes
-rw-r--r--test/reference/show-glyphs-advance.traps.ref.pngbin1394 -> 0 bytes
-rw-r--r--test/reference/show-text-current-point.traps.ref.pngbin2151 -> 0 bytes
-rw-r--r--test/reference/surface-pattern.quartz.xfail.pngbin9216 -> 9216 bytes
-rw-r--r--test/reference/text-antialias-gray.traps.ref.pngbin966 -> 0 bytes
-rw-r--r--test/reference/user-font-color.image16.ref.pngbin3527 -> 9080 bytes
-rw-r--r--test/reference/user-font-color.pdf.ref.pngbin4234 -> 7700 bytes
-rw-r--r--test/reference/user-font-color.ps.ref.pngbin3924 -> 8826 bytes
-rw-r--r--test/reference/user-font-color.quartz.ref.pngbin4163 -> 9402 bytes
-rw-r--r--test/reference/user-font-color.recording.ref.pngbin4903 -> 10758 bytes
-rw-r--r--test/reference/user-font-color.ref.pngbin4233 -> 9435 bytes
-rw-r--r--test/reference/user-font-color.script.xfail.pngbin2189 -> 9182 bytes
-rw-r--r--test/reference/user-font-color.svg.ref.pngbin4289 -> 0 bytes
-rw-r--r--test/reference/user-font-color.svg.rgb24.xfail.pngbin3040 -> 0 bytes
-rw-r--r--test/reference/user-font-color.xcb.ref.pngbin0 -> 9347 bytes
-rw-r--r--test/reference/user-font-color.xlib.ref.pngbin0 -> 9347 bytes
-rw-r--r--test/reference/user-font-proxy.pdf.argb32.ref.pngbin4049 -> 10978 bytes
-rw-r--r--test/reference/user-font-proxy.pdf.rgb24.ref.pngbin16937 -> 10978 bytes
-rw-r--r--test/reference/user-font-proxy.quartz.ref.pngbin19737 -> 19701 bytes
-rw-r--r--test/reference/user-font-proxy.ref.pngbin16961 -> 20856 bytes
-rw-r--r--test/reference/user-font-proxy.svg.ref.pngbin16938 -> 20847 bytes
-rw-r--r--test/reference/user-font.pdf.xfail.pngbin0 -> 11853 bytes
-rw-r--r--test/reference/user-font.quartz.ref.pngbin9865 -> 10533 bytes
-rw-r--r--test/reference/user-font.recording.ref.pngbin12398 -> 13876 bytes
-rw-r--r--test/reference/user-font.ref.pngbin9867 -> 10557 bytes
-rw-r--r--test/reference/user-font.svg.argb32.ref.pngbin0 -> 10561 bytes
-rw-r--r--test/reference/user-font.svg.rgb24.ref.pngbin0 -> 13988 bytes
-rw-r--r--test/round-join-bug-520.c109
-rw-r--r--test/svg/README22
-rwxr-xr-xtest/svg/build_ttx_fonts.py161
-rw-r--r--test/svg/color.0.color0.svg4
-rw-r--r--test/svg/color.1.color1.svg4
-rw-r--r--test/svg/color.2.foreground-solid.svg4
-rw-r--r--test/svg/color.3.foreground-alpha.svg4
-rw-r--r--test/svg/color.4.foreground-linear.svg10
-rw-r--r--test/svg/color.5.foreground-linear-alpha.svg10
-rw-r--r--test/svg/color.6.foreground-radial.svg10
-rw-r--r--test/svg/color.7.foreground-radial-alpha.svg10
-rw-r--r--test/svg/doc.0.viewBox1.svg4
-rw-r--r--test/svg/doc.1.viewBox2.svg4
-rw-r--r--test/svg/doc.2.image.svg121
-rw-r--r--test/svg/doc.3.image-transform.svg122
-rw-r--r--test/svg/doc.4.clip-user.svg9
-rw-r--r--test/svg/doc.5.clip-object.svg10
-rw-r--r--test/svg/doc.6.clip-user2.svg10
-rw-r--r--test/svg/doc.7.clip-object2.svg11
-rw-r--r--test/svg/doc.8.clip-user3.svg15
-rw-r--r--test/svg/doc.9.clip-object3.svg15
-rw-r--r--test/svg/doc.A.g.svg14
-rw-r--r--test/svg/fill.0.name.svg4
-rw-r--r--test/svg/fill.1.hex6.svg4
-rw-r--r--test/svg/fill.2.hex3.svg4
-rw-r--r--test/svg/fill.3.rgb.svg4
-rw-r--r--test/svg/fill.4.current-color.svg4
-rw-r--r--test/svg/fill.5.palette.svg4
-rw-r--r--test/svg/fill.6.opacity.svg4
-rw-r--r--test/svg/fill.7.color.svg5
-rw-r--r--test/svg/fill.8.rule.svg8
-rw-r--r--test/svg/fuzzer/README19
-rw-r--r--test/svg/fuzzer/meson.build14
-rw-r--r--test/svg/fuzzer/svg-render-fuzzer.c57
-rw-r--r--test/svg/gradient.0.lin-pad.svg10
-rw-r--r--test/svg/gradient.1.lin-reflect.svg11
-rw-r--r--test/svg/gradient.2.lin-repeat.svg11
-rw-r--r--test/svg/gradient.3.lin-user.svg11
-rw-r--r--test/svg/gradient.4.lin-transform.svg10
-rw-r--r--test/svg/gradient.5.rad-pad.svg10
-rw-r--r--test/svg/gradient.6.rad-reflect.svg11
-rw-r--r--test/svg/gradient.7.rad-repeat.svg11
-rw-r--r--test/svg/gradient.8.rad-user.svg11
-rw-r--r--test/svg/gradient.9.rad-transform.svg11
-rw-r--r--test/svg/meson.build9
-rw-r--r--test/svg/path.0.line.svg8
-rw-r--r--test/svg/path.1.curve.svg9
-rw-r--r--test/svg/path.2.quad.svg8
-rw-r--r--test/svg/path.3.arc.svg7
-rw-r--r--test/svg/shapes.0.rect.svg3
-rw-r--r--test/svg/shapes.1.rounded-rect.svg3
-rw-r--r--test/svg/shapes.2.circle.svg3
-rw-r--r--test/svg/shapes.3.ellipse.svg3
-rw-r--r--test/svg/shapes.4.line.svg3
-rw-r--r--test/svg/shapes.5.polyline.svg12
-rw-r--r--test/svg/shapes.6.polygon.svg12
-rw-r--r--test/svg/stroke.0.name.svg6
-rw-r--r--test/svg/stroke.1.hex6.svg6
-rw-r--r--test/svg/stroke.2.hex3.svg6
-rw-r--r--test/svg/stroke.3.rgb.svg6
-rw-r--r--test/svg/stroke.4.current-color.svg6
-rw-r--r--test/svg/stroke.5.palette.svg6
-rw-r--r--test/svg/stroke.6.opacity.svg6
-rw-r--r--test/svg/stroke.7.color.svg7
-rw-r--r--test/svg/stroke.8.width.svg14
-rw-r--r--test/svg/stroke.9.cap.svg17
-rw-r--r--test/svg/stroke.A.dash.svg27
-rw-r--r--test/svg/stroke.B.dash-offset.svg31
-rw-r--r--test/svg/stroke.C.miter.svg10
-rw-r--r--test/svg/stroke.D.round.svg10
-rw-r--r--test/svg/stroke.E.bevel.svg10
-rw-r--r--test/svg/stroke.F.miter-limit.svg11
-rw-r--r--test/svg/svg-font-template.ttx190
-rw-r--r--test/svg/svg-render.c308
-rw-r--r--test/svg/transform.0.translate.svg8
-rw-r--r--test/svg/transform.1.scale.svg10
-rw-r--r--test/svg/transform.2.rotate.svg10
-rw-r--r--test/svg/transform.3.skewX.svg10
-rw-r--r--test/svg/transform.4.skewY.svg10
-rw-r--r--test/svg/transform.5.matrix.svg10
-rw-r--r--test/svg/transform.6.multiple.svg16
-rw-r--r--test/svg/transform.7.stroke.svg20
-rw-r--r--test/user-font-color.c218
-rw-r--r--test/user-font-proxy.c31
-rw-r--r--test/user-font.c49
-rw-r--r--util/Makefile.am98
-rw-r--r--util/cairo-fdr/Makefile.am15
-rw-r--r--util/cairo-gobject/Makefile.am15
-rw-r--r--util/cairo-missing/Makefile.am10
-rw-r--r--util/cairo-missing/Makefile.sources8
-rw-r--r--util/cairo-missing/Makefile.win3210
-rw-r--r--util/cairo-missing/cairo-missing.h1
-rw-r--r--util/cairo-missing/strndup.c8
-rw-r--r--util/cairo-script/Makefile.am37
-rw-r--r--util/cairo-script/Makefile.sources13
-rw-r--r--util/cairo-script/Makefile.win3210
-rw-r--r--util/cairo-script/cairo-script-operators.c3
-rw-r--r--util/cairo-script/csi-replay.c61
-rw-r--r--util/cairo-script/examples/Makefile.am10
-rw-r--r--util/cairo-sphinx/Makefile.am43
-rw-r--r--util/cairo-sphinx/sphinx.c11
-rw-r--r--util/cairo-trace/Makefile.am40
-rw-r--r--util/cairo-trace/trace.c189
-rw-r--r--util/malloc-stats.c32
-rw-r--r--util/meson.build8
-rw-r--r--util/trace-to-xml.c76
-rw-r--r--util/xml-to-trace.c263
-rwxr-xr-xversion.py60
435 files changed, 18182 insertions, 26919 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index e6fe8610d..e7479889e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -8,17 +8,14 @@ include:
variables:
FDO_UPSTREAM_REPO: 'cairo/cairo'
FDO_DISTRIBUTION_VERSION: '34'
- FDO_DISTRIBUTION_TAG: '2021-08-26.0'
+ FDO_DISTRIBUTION_TAG: '2021-09-20.0'
# TODO: should probably get its own image at some point instead of reusing the GStreamer one
- # See https://gitlab.freedesktop.org/gstreamer/gstreamer/container_registry/18035 for latest
- WINDOWS_IMAGE: "registry.freedesktop.org/gstreamer/gstreamer/amd64/windows:2022-05-16.1-main"
+ # See https://gitlab.freedesktop.org/gstreamer/gstreamer/-/blob/main/.gitlab-image-tags.yml for latest
+ WINDOWS_IMAGE: "registry.freedesktop.org/gstreamer/gstreamer/amd64/windows:2022-12-10.0-main"
DEFAULT_MESON_ARGS: >
--default-library=both
- -Dgl-backend=auto
- -Dglesv2=auto
- -Dglesv3=auto
stages:
- prep
@@ -73,15 +70,11 @@ fedora image:
librsvg2-devel
gtk2-devel
poppler-glib-devel
+ libspectre-devel
+ ghostscript
pixman-devel
systemd-devel
systemd-udev
- mesa-libEGL
- mesa-libGL
- mesa-libGL-devel
- mesa-libgbm
- mesa-libgbm-devel
- mesa-libglapi
expat-devel
autoconf
automake
@@ -94,26 +87,13 @@ fedora image:
dejavu-sans-mono-fonts
dejavu-serif-fonts
google-noto-emoji-color-fonts
+ fonttools
-fedora autotools build:
- extends:
- - '.fdo.distribution-image@fedora'
- - '.ccache_setup'
- stage: 'build'
- script:
- - ./autogen.sh
- - make V=1 VERBOSE=1 -j $(nproc)
- artifacts:
- when: 'always'
- expire_in: '2 days'
- paths:
- - "*"
-
-.test fedora autotools:
+.test fedora meson:
dependencies:
- - 'fedora autotools build'
+ - 'fedora meson build'
needs:
- - 'fedora autotools build'
+ - 'fedora meson build'
extends:
- '.fdo.distribution-image@fedora'
- '.ccache_setup'
@@ -122,49 +102,79 @@ fedora autotools build:
when: 'always'
expire_in: "7 days"
paths:
- - config.log
- - test/*.log
- - test/pdiff/*.log
- - test/output
+ - builddir/meson-logs/*
+ - builddir/test/*.log
+ - builddir/test/pdiff/*.log
+ - builddir/test/output
exclude:
- - "test/**/*.cs"
- - "test/**/*.trace"
+ - "builddir/test/**/*.cs"
+ - "builddir/test/**/*.trace"
-test fedora autotools pdf:
- extends: '.test fedora autotools'
+fedora meson build check-refs.sh:
+ extends: '.test fedora meson'
+ script:
+ # Check for duplicate reference images
+ - ./test/check-refs.sh "$(pwd)/builddir/test/pdiff/perceptualdiff"
+
+test fedora meson pdf:
+ extends: '.test fedora meson'
script:
- export CAIRO_TEST_IGNORE_pdf_argb32=$(tr '\n' ',' < .gitlab-ci/ignore-pdf-argb32.txt)
- export CAIRO_TEST_IGNORE_pdf_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-pdf-rgb24.txt)
- export CAIRO_TEST_TARGET=pdf
- - xvfb-run make check V=1 VERBOSE=1
+ - export srcdir=../../test
+ - (cd builddir/test && xvfb-run ./cairo-test-suite)
-test fedora autotools script:
- extends: '.test fedora autotools'
+test fedora meson ps2:
+ extends: '.test fedora meson'
+ script:
+ - export CAIRO_TEST_IGNORE_ps2_argb32=$(tr '\n' ',' < .gitlab-ci/ignore-ps2-argb32.txt)
+ - export CAIRO_TEST_IGNORE_ps2_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-ps2-rgb24.txt)
+ - export CAIRO_TEST_TARGET=ps2
+ - export CAIRO_TEST_UGLY_HACK_TO_IGNORE_PS_FAILURES=1
+ - export srcdir=../../test
+ - (cd builddir/test && xvfb-run ./cairo-test-suite)
+
+test fedora meson ps3:
+ extends: '.test fedora meson'
+ script:
+ - export CAIRO_TEST_IGNORE_ps3_argb32=$(tr '\n' ',' < .gitlab-ci/ignore-ps3-argb32.txt)
+ - export CAIRO_TEST_IGNORE_ps3_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-ps3-rgb24.txt)
+ - export CAIRO_TEST_TARGET=ps3
+ - export CAIRO_TEST_UGLY_HACK_TO_IGNORE_PS_FAILURES=1
+ - export srcdir=../../test
+ - (cd builddir/test && xvfb-run ./cairo-test-suite)
+
+test fedora meson script:
+ extends: '.test fedora meson'
script:
- export CAIRO_TEST_UGLY_HACK_TO_SOMETIMES_IGNORE_SCRIPT_XCB_HUGE_IMAGE_SHM=1
- export CAIRO_TEST_IGNORE_script_argb32=$(tr '\n' ',' < .gitlab-ci/ignore-script-argb32.txt)
- export CAIRO_TEST_TARGET=script
- - xvfb-run make check V=1 VERBOSE=1
+ - export srcdir=../../test
+ - (cd builddir/test && xvfb-run ./cairo-test-suite)
-test fedora autotools image:
- extends: '.test fedora autotools'
+test fedora meson image:
+ extends: '.test fedora meson'
script:
- export CAIRO_TEST_IGNORE_image_argb32=$(tr '\n' ',' < .gitlab-ci/ignore-image-argb32.txt)
- export CAIRO_TEST_IGNORE_image_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-image-rgb24.txt)
- export CAIRO_TEST_IGNORE_image16_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-image16-rgb24.txt)
- export CAIRO_TEST_TARGET=image,image16
- - xvfb-run make check V=1 VERBOSE=1
+ - export srcdir=../../test
+ - (cd builddir/test && xvfb-run ./cairo-test-suite)
-test fedora autotools recording:
- extends: '.test fedora autotools'
+test fedora meson recording:
+ extends: '.test fedora meson'
script:
- export CAIRO_TEST_IGNORE_recording_argb32=$(tr '\n' ',' < .gitlab-ci/ignore-recording-argb32.txt)
- export CAIRO_TEST_IGNORE_recording_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-recording-rgb24.txt)
- export CAIRO_TEST_TARGET=recording
- - xvfb-run make check V=1 VERBOSE=1
+ - export srcdir=../../test
+ - (cd builddir/test && xvfb-run ./cairo-test-suite)
-test fedora autotools svg:
- extends: '.test fedora autotools'
+test fedora meson svg:
+ extends: '.test fedora meson'
script:
- export CAIRO_TEST_IGNORE_svg11_argb32=$(tr '\n' ',' < .gitlab-ci/ignore-svg11-argb32.txt)
- export CAIRO_TEST_IGNORE_svg11_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-svg11-rgb24.txt)
@@ -173,10 +183,11 @@ test fedora autotools svg:
- export CAIRO_BOILERPLATE_DO_NOT_CRASH_ON_ANY2PPM_ERROR=1
- export ANY2PPM="timeout 3m ./any2ppm"
- ulimit -S -s 131072
- - xvfb-run make check V=1 VERBOSE=1
+ - export srcdir=../../test
+ - (cd builddir/test && xvfb-run ./cairo-test-suite)
-test fedora autotools xcb:
- extends: '.test fedora autotools'
+test fedora meson xcb:
+ extends: '.test fedora meson'
script:
- export CAIRO_TEST_IGNORE_xcb_argb32=$(tr '\n' ',' < .gitlab-ci/ignore-xcb-argb32.txt)
- export CAIRO_TEST_IGNORE_xcb_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-xcb-rgb24.txt)
@@ -186,10 +197,11 @@ test fedora autotools xcb:
- export CAIRO_TEST_IGNORE_xcb_render_0_0_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-xcb-render-0-0-rgb24.txt)
- export CAIRO_TEST_IGNORE_xcb_fallback_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-xcb-fallback-rgb24.txt)
- export CAIRO_TEST_TARGET="xcb,xcb-window,xcb-window&,xcb-render-0_0,xcb-fallback"
- - xvfb-run make check V=1 VERBOSE=1
+ - export srcdir=../../test
+ - (cd builddir/test && xvfb-run ./cairo-test-suite)
-test fedora autotools xlib:
- extends: '.test fedora autotools'
+test fedora meson xlib:
+ extends: '.test fedora meson'
script:
- export CAIRO_TEST_IGNORE_xlib_argb32=$(tr '\n' ',' < .gitlab-ci/ignore-xlib-argb32.txt)
- export CAIRO_TEST_IGNORE_xlib_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-xlib-rgb24.txt)
@@ -197,7 +209,8 @@ test fedora autotools xlib:
- export CAIRO_TEST_IGNORE_xlib_render_0_0_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-xlib-render-0-0-rgb24.txt)
- export CAIRO_TEST_IGNORE_xlib_fallback_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-xlib-fallback-rgb24.txt)
- export CAIRO_TEST_TARGET="xlib,xlib-window,xlib-render-0_0,xlib-fallback"
- - xvfb-run make check V=1 VERBOSE=1
+ - export srcdir=../../test
+ - (cd builddir/test && xvfb-run ./cairo-test-suite)
fedora meson build:
extends:
@@ -207,19 +220,17 @@ fedora meson build:
variables:
MESON_ARGS: >
${DEFAULT_MESON_ARGS}
- -Dgl-backend=gl
script:
- export CFLAGS="-Werror -Wno-error=deprecated-declarations"
- meson builddir ${MESON_ARGS}
- ninja -C builddir
# Run test scripts
- #- (cd builddir/src && srcdir=../../src bash "$srcdir/check-def.sh") This script calls "make cairo.def" and thus does not work with meson
- mkdir builddir/src/.libs
- touch builddir/src/.libs/libfoo.so
# Run all the tests, except for the big test executable which
# gets run separately
- - meson test -C builddir --no-suite=slow
+ - meson test -C builddir --no-suite=slow --print-errorlogs
# TODO: These aren't set up as Meson tests yet
- (cd doc/public && bash "check-doc-syntax.sh")
@@ -231,7 +242,7 @@ fedora meson build:
expire_in: "7 days"
when: "always"
paths:
- - 'builddir/meson-logs/'
+ - "*"
meson mingw-32 build:
extends:
@@ -285,17 +296,22 @@ meson mingw-64 build:
-Dfreetype=enabled
-Dglib=enabled
-Dzlib=enabled
+ ${EXTRA_MESON_ARGS}
before_script:
# Make sure meson is up to date, so we don't need to rebuild the image with each release
- - pip3 install -U meson
+ # FIXME: don't update meson version for now, since there seems to be a bug
+ # in newer meson versions (0.63.3 at the time of writing) where it can't
+ # find some hash file and then meson subprojects update fails)
+ # - pip3 install -U meson
script:
# Make sure powershell exists on errors
# https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables?view=powershell-6
- $ErrorActionPreference = "Stop"
# Copy GLib from existing subproject cache to avoid downloading it
- - cd $env:CI_PROJECT_DIR
- - cp -r C:/subprojects/glib subprojects/
+ # FIXME: no longer cached in GStreamer image, using tarball for now
+ #- cd $env:CI_PROJECT_DIR
+ #- cp -r C:/subprojects/glib subprojects/
# For some reason, options are separated by newline instead of space, so we
# have to replace them first.
@@ -309,15 +325,23 @@ meson mingw-64 build:
meson build $env:MESON_ARGS &&
ninja -C build"
-meson vs2019 amd64:
+meson vs2019 shared amd64:
+ extends: '.build meson windows'
+ variables:
+ ARCH: 'amd64'
+ EXTRA_MESON_ARGS: '--default-library=shared'
+
+meson vs2019 static amd64:
extends: '.build meson windows'
variables:
ARCH: 'amd64'
+ EXTRA_MESON_ARGS: '--default-library=static'
-meson vs2019 x86:
+meson vs2019 shared x86:
extends: '.build meson windows'
variables:
ARCH: 'x86'
+ EXTRA_MESON_ARGS: '--default-library=shared'
meson android arm64 fedora:
# TODO: should probably build our own image here some day
@@ -364,7 +388,7 @@ meson android arm64 fedora:
meson macOS:
tags:
- - gst-macos-11.1
+ - gst-macos-12.3
stage: 'build'
artifacts:
when: 'always'
diff --git a/.gitlab-ci/ignore-ps2-argb32.txt b/.gitlab-ci/ignore-ps2-argb32.txt
new file mode 100644
index 000000000..75c599fc4
--- /dev/null
+++ b/.gitlab-ci/ignore-ps2-argb32.txt
@@ -0,0 +1,207 @@
+arc-direction
+arc-looping-dash
+bug-448
+bug-51910
+bug-bo-ricotz
+bug-extents
+bug-spline
+caps
+caps-05
+caps-1
+caps-2
+caps-joins
+caps-joins-05
+caps-joins-1
+caps-joins-2
+caps-joins-curve
+caps-sub-paths
+caps-tails-curve
+clear-source
+clip-complex-bug61592
+clip-disjoint
+clip-fill
+clip-fill-rule
+clip-group-shapes-circles
+clip-image
+clip-nesting
+clip-push-group
+clip-rotate-image-surface-paint
+clip-shape
+clip-stroke
+clip-text
+clip-twice
+clip-unbounded
+close-path
+close-path-current-point
+copy-path
+culled-glyphs
+curve-to-as-line-to
+dash-caps-joins
+dash-curve
+dash-infinite-loop
+dash-no-dash
+dash-offset
+dash-offset-negative
+dash-scale
+dash-state
+dash-zero-length
+degenerate-arc
+degenerate-curve-to
+degenerate-dash
+degenerate-path
+degenerate-pen
+degenerate-rel-curve-to
+degenerate-solid-dash
+drunkard-tails
+extend-reflect
+extend-reflect-similar
+extended-blend
+extended-blend-alpha-mask
+extended-blend-solid
+fallback
+fill-and-stroke
+fill-degenerate-sort-order
+fill-image
+fill-rule
+filter-nearest-offset
+finer-grained-fallbacks
+font-matrix-translation
+ft-color-font
+ft-text-vertical-layout-type1
+ft-text-vertical-layout-type3
+group-unaligned
+hairline
+hairline-anisotropic
+hairline-anisotropic-incorrect
+hairline-big
+hairline-scaled
+halo
+halo-transform
+horizontal-clip
+inverse-text
+joins
+joins-loop
+joins-retrace
+joins-star
+large-font
+leaky-dash
+leaky-dashed-rectangle
+leaky-dashed-stroke
+leaky-polygon
+line-width
+line-width-large-overlap-dashed
+line-width-overlap
+line-width-overlap-dashed
+line-width-overlap-flipped
+line-width-overlap-flopped
+line-width-overlap-offset
+line-width-scale
+line-width-tolerance
+long-dashed-lines
+miter-precision
+new-sub-path
+operator-www
+over-above-source
+over-around-source
+over-below-source
+over-between-source
+overlapping-glyphs
+path-append
+path-stroke-twice
+pixman-downscale-fast-95
+pixman-downscale-nearest-95
+pixman-rotate
+pthread-same-source
+radial-gradient
+radial-gradient-mask
+radial-gradient-mask-source
+random-clip
+random-intersections-curves-eo
+random-intersections-curves-nz
+random-intersections-eo
+random-intersections-nonzero
+record-extend-reflect
+record-neg-extents-bounded
+record-neg-extents-unbounded
+record-replay-extend-reflect
+record-replay-extend-repeat
+record-select-font-face
+record-self-intersecting
+record-text-transform
+record1414x-fill-alpha
+record1414x-select-font-face
+record1414x-self-intersecting
+record1414x-text-transform
+record2x-select-font-face
+record2x-self-intersecting
+record2x-text-transform
+record90-select-font-face
+record90-self-intersecting
+record90-text-transform
+recordflip-select-font-face
+recordflip-self-intersecting
+recordflip-text-transform
+recordflip-whole-select-font-face
+recordflip-whole-self-intersecting
+recordflip-whole-text-transform
+rectilinear-dash
+rectilinear-dash-scale
+rectilinear-dash-scale-unaligned
+rectilinear-grid
+rectilinear-miter-limit
+rectilinear-stroke
+reflected-stroke
+rotate-clip-image-surface-paint
+rotate-image-surface-paint
+rotate-stroke-box
+rotated-clip
+round-join-bug-520-bevel
+round-join-bug-520-round
+rounded-rectangle-fill
+rounded-rectangle-stroke
+scale-offset-image
+scale-offset-similar
+self-copy-overlap
+stroke-ctm-caps
+stroke-clipped
+stroke-image
+stroke-open-box
+select-font-face
+self-copy-overlap
+self-intersecting
+shape-general-convex
+shape-sierpinski
+show-glyphs-advance
+show-text-current-point
+smask
+smask-text
+smp-glyph
+spline-decomposition
+stroke-clipped
+stroke-ctm-caps
+stroke-image
+stroke-open-box
+surface-pattern
+surface-pattern-scale-down
+surface-pattern-scale-down-extend-reflect
+surface-pattern-scale-up
+text-glyph-range
+text-pattern
+text-rotate
+text-transform
+text-unhinted-metrics
+thin-lines
+tiger
+transforms
+trap-clip
+twin
+unclosed-strokes
+user-font
+user-font-color
+user-font-mask
+user-font-proxy
+user-font-rescale
+user-font-subpixel
+world-map
+world-map-fill
+world-map-stroke
diff --git a/.gitlab-ci/ignore-ps2-rgb24.txt b/.gitlab-ci/ignore-ps2-rgb24.txt
new file mode 100644
index 000000000..0ca0b8b45
--- /dev/null
+++ b/.gitlab-ci/ignore-ps2-rgb24.txt
@@ -0,0 +1,197 @@
+arc-direction
+arc-looping-dash
+bug-361
+bug-431
+bug-448
+bug-51910
+bug-bo-ricotz
+bug-extents
+bug-spline
+caps
+caps-05
+caps-1
+caps-2
+caps-joins
+caps-joins-05
+caps-joins-1
+caps-joins-2
+caps-joins-curve
+caps-sub-paths
+caps-tails-curve
+clear-source
+clip-complex-bug61592
+clip-fill
+clip-fill-rule
+clip-group-shapes-circles
+clip-image
+clip-nesting
+clip-push-group
+clip-rotate-image-surface-paint
+clip-shape
+clip-stroke
+clip-text
+clip-twice
+close-path
+close-path-current-point
+copy-path
+culled-glyphs
+curve-to-as-line-to
+dash-caps-joins
+dash-curve
+dash-infinite-loop
+dash-no-dash
+dash-offset
+dash-offset-negative
+dash-scale
+dash-state
+dash-zero-length
+degenerate-arc
+degenerate-curve-to
+degenerate-dash
+degenerate-path
+degenerate-pen
+degenerate-rel-curve-to
+degenerate-solid-dash
+drunkard-tails
+extend-reflect
+extend-reflect-similar
+extended-blend-alpha-mask
+fill-and-stroke
+fill-degenerate-sort-order
+fill-image
+fill-rule
+filter-nearest-offset
+font-matrix-translation
+ft-color-font
+ft-text-vertical-layout-type1
+ft-text-vertical-layout-type3
+gradient-constant-alpha
+gradient-zero-stops
+group-unaligned
+hairline
+hairline-anisotropic
+hairline-anisotropic-incorrect
+hairline-big
+hairline-scaled
+halo
+halo-transform
+horizontal-clip
+image-surface-source
+inverse-text
+joins
+joins-loop
+joins-retrace
+joins-star
+large-font
+leaky-dash
+leaky-dashed-rectangle
+leaky-dashed-stroke
+leaky-polygon
+line-width
+line-width-large-overlap-dashed
+line-width-overlap
+line-width-overlap-dashed
+line-width-overlap-flipped
+line-width-overlap-flopped
+line-width-overlap-offset
+line-width-scale
+line-width-tolerance
+long-dashed-lines
+miter-precision
+new-sub-path
+overlapping-glyphs
+path-append
+path-stroke-twice
+pdf-surface-source
+pixman-downscale-fast-95
+pixman-downscale-nearest-95
+pixman-rotate
+ps-surface-source
+pthread-same-source
+radial-gradient-source
+random-intersections-curves-eo
+random-intersections-curves-nz
+random-intersections-eo
+random-intersections-nonzero
+record-extend-reflect
+record-neg-extents-bounded
+record-neg-extents-unbounded
+record-replay-extend-reflect
+record-replay-extend-repeat
+record-select-font-face
+record-self-intersecting
+record-text-transform
+record1414x-fill-alpha
+record1414x-select-font-face
+record1414x-self-intersecting
+record1414x-text-transform
+record2x-select-font-face
+record2x-self-intersecting
+record2x-text-transform
+record90-select-font-face
+record90-self-intersecting
+record90-text-transform
+recordflip-select-font-face
+recordflip-self-intersecting
+recordflip-text-transform
+recordflip-whole-select-font-face
+recordflip-whole-self-intersecting
+recordflip-whole-text-transform
+rectilinear-dash
+rectilinear-dash-scale
+rectilinear-dash-scale-unaligned
+rectilinear-grid
+rectilinear-miter-limit
+rectilinear-stroke
+reflected-stroke
+rel-path
+rotate-clip-image-surface-paint
+rotate-image-surface-paint
+rotate-stroke-box
+round-join-bug-520-bevel
+round-join-bug-520-round
+rounded-rectangle-fill
+rounded-rectangle-stroke
+scale-offset-image
+scale-offset-similar
+scale-source-surface-paint
+select-font-face
+self-intersecting
+set-source
+shape-general-convex
+shape-sierpinski
+show-glyphs-advance
+show-text-current-point
+smask
+smask-text
+smp-glyph
+source-surface-scale-paint
+spline-decomposition
+stroke-clipped
+stroke-ctm-caps
+stroke-image
+stroke-open-box
+surface-pattern
+surface-pattern-scale-down
+surface-pattern-scale-down-extend-reflect
+surface-pattern-scale-up
+text-glyph-range
+text-pattern
+text-rotate
+text-transform
+text-unhinted-metrics
+thin-lines
+tiger
+transforms
+twin
+unclosed-strokes
+user-font
+user-font-mask
+user-font-proxy
+user-font-rescale
+user-font-subpixel
+world-map
+world-map-fill
+world-map-stroke
+xcb-surface-source
+xlib-surface-source
diff --git a/.gitlab-ci/ignore-ps3-argb32.txt b/.gitlab-ci/ignore-ps3-argb32.txt
new file mode 100644
index 000000000..9e433d5c3
--- /dev/null
+++ b/.gitlab-ci/ignore-ps3-argb32.txt
@@ -0,0 +1,218 @@
+arc-direction
+arc-looping-dash
+bug-448
+bug-51910
+bug-bo-ricotz
+bug-extents
+bug-image-compositor
+bug-spline
+caps
+caps-05
+caps-1
+caps-2
+caps-joins
+caps-joins-05
+caps-joins-1
+caps-joins-2
+caps-joins-curve
+caps-sub-paths
+caps-tails-curve
+clear-source
+clip-complex-bug61592
+clip-disjoint
+clip-fill
+clip-fill-rule
+clip-group-shapes-circles
+clip-image
+clip-nesting
+clip-push-group
+clip-rotate-image-surface-paint
+clip-shape
+clip-stroke
+clip-text
+clip-twice
+clip-unbounded
+close-path
+close-path-current-point
+copy-path
+culled-glyphs
+curve-to-as-line-to
+dash-caps-joins
+dash-curve
+dash-infinite-loop
+dash-no-dash
+dash-offset
+dash-offset-negative
+dash-scale
+dash-state
+dash-zero-length
+degenerate-arc
+degenerate-curve-to
+degenerate-dash
+degenerate-path
+degenerate-pen
+degenerate-rel-curve-to
+degenerate-solid-dash
+drunkard-tails
+extend-reflect
+extend-reflect-similar
+extended-blend
+extended-blend-alpha-mask
+extended-blend-solid
+fallback
+fill-and-stroke
+fill-degenerate-sort-order
+fill-image
+fill-rule
+filter-nearest-offset
+filter-nearest-transformed
+finer-grained-fallbacks
+font-matrix-translation
+ft-color-font
+ft-text-vertical-layout-type1
+ft-text-vertical-layout-type3
+gradient-constant-alpha
+group-unaligned
+hairline
+hairline-anisotropic
+hairline-anisotropic-incorrect
+hairline-big
+hairline-scaled
+halo
+halo-transform
+horizontal-clip
+inverse-text
+joins
+joins-loop
+joins-retrace
+joins-star
+large-font
+leaky-dash
+leaky-dashed-rectangle
+leaky-dashed-stroke
+leaky-polygon
+line-width
+line-width-large-overlap-dashed
+line-width-overlap
+line-width-overlap-dashed
+line-width-overlap-flipped
+line-width-overlap-flopped
+line-width-overlap-offset
+line-width-scale
+line-width-tolerance
+linear-gradient
+linear-gradient-reflect
+linear-gradient-subset
+long-dashed-lines
+mask-transformed-image
+mesh-pattern-conical
+mesh-pattern-control-points
+mesh-pattern-fold
+mesh-pattern-overlap
+miter-precision
+new-sub-path
+operator-www
+over-around-source
+over-below-source
+overlapping-glyphs
+path-append
+path-stroke-twice
+pixman-downscale-fast-95
+pixman-downscale-nearest-95
+pixman-rotate
+pthread-same-source
+push-group-color
+radial-gradient
+radial-gradient-mask
+radial-gradient-mask-source
+radial-gradient-one-stop
+random-clip
+random-intersections-curves-eo
+random-intersections-curves-nz
+random-intersections-eo
+random-intersections-nonzero
+record-extend-reflect
+record-neg-extents-bounded
+record-neg-extents-unbounded
+record-replay-extend-reflect
+record-replay-extend-repeat
+record-select-font-face
+record-self-intersecting
+record-text-transform
+record1414x-fill-alpha
+record1414x-select-font-face
+record1414x-self-intersecting
+record1414x-text-transform
+record2x-select-font-face
+record2x-self-intersecting
+record2x-text-transform
+record90-select-font-face
+record90-self-intersecting
+record90-text-transform
+recordflip-select-font-face
+recordflip-self-intersecting
+recordflip-text-transform
+recordflip-whole-select-font-face
+recordflip-whole-self-intersecting
+recordflip-whole-text-transform
+rectilinear-dash
+rectilinear-dash-scale
+rectilinear-dash-scale-unaligned
+rectilinear-grid
+rectilinear-miter-limit
+rectilinear-stroke
+reflected-stroke
+rotate-clip-image-surface-paint
+rotate-image-surface-paint
+rotate-stroke-box
+rotated-clip
+round-join-bug-520-bevel
+round-join-bug-520-round
+rounded-rectangle-fill
+rounded-rectangle-stroke
+scale-offset-image
+scale-offset-similar
+self-copy-overlap
+stroke-ctm-caps
+stroke-clipped
+stroke-image
+stroke-open-box
+select-font-face
+self-copy-overlap
+self-intersecting
+shape-general-convex
+shape-sierpinski
+show-glyphs-advance
+show-text-current-point
+smask
+smask-text
+smp-glyph
+spline-decomposition
+stroke-clipped
+stroke-ctm-caps
+stroke-image
+stroke-open-box
+surface-pattern
+surface-pattern-scale-down
+surface-pattern-scale-down-extend-reflect
+surface-pattern-scale-up
+text-glyph-range
+text-pattern
+text-rotate
+text-transform
+text-unhinted-metrics
+thin-lines
+tiger
+transforms
+trap-clip
+twin
+unclosed-strokes
+user-font
+user-font-color
+user-font-mask
+user-font-proxy
+user-font-rescale
+user-font-subpixel
+world-map
+world-map-fill
+world-map-stroke
diff --git a/.gitlab-ci/ignore-ps3-rgb24.txt b/.gitlab-ci/ignore-ps3-rgb24.txt
new file mode 100644
index 000000000..c4c6a0362
--- /dev/null
+++ b/.gitlab-ci/ignore-ps3-rgb24.txt
@@ -0,0 +1,209 @@
+arc-direction
+arc-looping-dash
+bug-361
+bug-431
+bug-448
+bug-51910
+bug-bo-ricotz
+bug-extents
+bug-image-compositor
+bug-spline
+caps
+caps-05
+caps-1
+caps-2
+caps-joins
+caps-joins-05
+caps-joins-1
+caps-joins-2
+caps-joins-curve
+caps-sub-paths
+caps-tails-curve
+clear-source
+clip-complex-bug61592
+clip-fill
+clip-fill-rule
+clip-group-shapes-circles
+clip-image
+clip-nesting
+clip-push-group
+clip-rotate-image-surface-paint
+clip-shape
+clip-stroke
+clip-text
+clip-twice
+close-path
+close-path-current-point
+copy-path
+culled-glyphs
+curve-to-as-line-to
+dash-caps-joins
+dash-curve
+dash-infinite-loop
+dash-no-dash
+dash-offset
+dash-offset-negative
+dash-scale
+dash-state
+dash-zero-length
+degenerate-arc
+degenerate-curve-to
+degenerate-dash
+degenerate-path
+degenerate-pen
+degenerate-rel-curve-to
+degenerate-solid-dash
+drunkard-tails
+extend-reflect
+extend-reflect-similar
+extended-blend-alpha-mask
+fill-and-stroke
+fill-degenerate-sort-order
+fill-image
+fill-rule
+filter-nearest-offset
+filter-nearest-transformed
+font-matrix-translation
+ft-color-font
+ft-text-vertical-layout-type1
+ft-text-vertical-layout-type3
+gradient-zero-stops
+group-unaligned
+hairline
+hairline-anisotropic
+hairline-anisotropic-incorrect
+hairline-big
+hairline-scaled
+halo
+halo-transform
+horizontal-clip
+image-surface-source
+inverse-text
+joins
+joins-loop
+joins-retrace
+joins-star
+large-font
+leaky-dash
+leaky-dashed-rectangle
+leaky-dashed-stroke
+leaky-polygon
+line-width
+line-width-large-overlap-dashed
+line-width-overlap
+line-width-overlap-dashed
+line-width-overlap-flipped
+line-width-overlap-flopped
+line-width-overlap-offset
+line-width-scale
+line-width-tolerance
+linear-gradient
+linear-gradient-reflect
+linear-gradient-subset
+long-dashed-lines
+mask-transformed-image
+mesh-pattern-conical
+mesh-pattern-control-points
+mesh-pattern-fold
+mesh-pattern-overlap
+miter-precision
+new-sub-path
+overlapping-glyphs
+path-append
+path-stroke-twice
+pdf-surface-source
+pixman-downscale-fast-95
+pixman-downscale-nearest-95
+pixman-rotate
+ps-surface-source
+pthread-same-source
+push-group-color
+radial-gradient-one-stop
+radial-gradient-source
+random-intersections-curves-eo
+random-intersections-curves-nz
+random-intersections-eo
+random-intersections-nonzero
+record-extend-reflect
+record-neg-extents-bounded
+record-neg-extents-unbounded
+record-replay-extend-reflect
+record-replay-extend-repeat
+record-select-font-face
+record-self-intersecting
+record-text-transform
+record1414x-fill-alpha
+record1414x-select-font-face
+record1414x-self-intersecting
+record1414x-text-transform
+record2x-select-font-face
+record2x-self-intersecting
+record2x-text-transform
+record90-select-font-face
+record90-self-intersecting
+record90-text-transform
+recordflip-select-font-face
+recordflip-self-intersecting
+recordflip-text-transform
+recordflip-whole-select-font-face
+recordflip-whole-self-intersecting
+recordflip-whole-text-transform
+rectilinear-dash
+rectilinear-dash-scale
+rectilinear-dash-scale-unaligned
+rectilinear-grid
+rectilinear-miter-limit
+rectilinear-stroke
+reflected-stroke
+rel-path
+rotate-clip-image-surface-paint
+rotate-image-surface-paint
+rotate-stroke-box
+round-join-bug-520-bevel
+round-join-bug-520-round
+rounded-rectangle-fill
+rounded-rectangle-stroke
+scale-offset-image
+scale-offset-similar
+scale-source-surface-paint
+select-font-face
+self-intersecting
+set-source
+shape-general-convex
+shape-sierpinski
+show-glyphs-advance
+show-text-current-point
+smask
+smask-text
+smp-glyph
+source-surface-scale-paint
+spline-decomposition
+stroke-clipped
+stroke-ctm-caps
+stroke-image
+stroke-open-box
+surface-pattern
+surface-pattern-scale-down
+surface-pattern-scale-down-extend-reflect
+surface-pattern-scale-up
+text-glyph-range
+text-pattern
+text-rotate
+text-transform
+text-unhinted-metrics
+thin-lines
+tiger
+transforms
+trap-clip
+twin
+unclosed-strokes
+user-font
+user-font-mask
+user-font-proxy
+user-font-rescale
+user-font-subpixel
+world-map
+world-map-fill
+world-map-stroke
+xcb-surface-source
+xlib-surface-source
diff --git a/.gitlab-ci/ignore-quartz-argb32.txt b/.gitlab-ci/ignore-quartz-argb32.txt
index e00077831..fb30f4bb0 100644
--- a/.gitlab-ci/ignore-quartz-argb32.txt
+++ b/.gitlab-ci/ignore-quartz-argb32.txt
@@ -12,7 +12,6 @@ fallback
ft-show-glyphs-positioning
ft-text-vertical-layout-type1
ft-text-vertical-layout-type3
-negative-stride-image
operator-www
radial-gradient
radial-gradient-mask
diff --git a/.gitlab-ci/ignore-quartz-rgb24.txt b/.gitlab-ci/ignore-quartz-rgb24.txt
index 47a12de09..92416e16b 100644
--- a/.gitlab-ci/ignore-quartz-rgb24.txt
+++ b/.gitlab-ci/ignore-quartz-rgb24.txt
@@ -1,5 +1,4 @@
a1-clip-fill-rule
-alpha-similar
big-empty-box
big-empty-triangle
big-little-box
@@ -32,7 +31,6 @@ image-surface-source
linear-gradient-one-stop
mask-ctm
mask-surface-ctm
-negative-stride-image
nil-surface
operator-www
overlapping-boxes
diff --git a/.gitlab-ci/ignore-svg11-argb32.txt b/.gitlab-ci/ignore-svg11-argb32.txt
index c0f6bb287..a37cf287d 100644
--- a/.gitlab-ci/ignore-svg11-argb32.txt
+++ b/.gitlab-ci/ignore-svg11-argb32.txt
@@ -50,3 +50,4 @@ text-rotate
text-unhinted-metrics
tighten-bounds
unbounded-operator
+user-font-color
diff --git a/.gitlab-ci/ignore-svg11-rgb24.txt b/.gitlab-ci/ignore-svg11-rgb24.txt
index d598bfa9f..952ab2786 100644
--- a/.gitlab-ci/ignore-svg11-rgb24.txt
+++ b/.gitlab-ci/ignore-svg11-rgb24.txt
@@ -107,3 +107,4 @@ tighten-bounds
unbounded-operator
xcb-surface-source
xlib-surface-source
+user-font-color
diff --git a/BIBLIOGRAPHY b/BIBLIOGRAPHY
deleted file mode 100644
index 90a6cef20..000000000
--- a/BIBLIOGRAPHY
+++ /dev/null
@@ -1,109 +0,0 @@
-Here's an effort to document some of the academic work that was
-referenced during the implementation of cairo. It is presented in the
-context of operations as they would be performed by either
-cairo_stroke() or cairo_fill():
-
-Given a Bézier path, approximate it with line segments:
-
- The deCasteljau algorithm
- "Outillages methodes calcul", P de Casteljau, technical
- report, - Andre Citroen Automobiles SA, Paris, 1959
-
- That technical report might be "hard" to find, but fortunately
- this algorithm will be described in any reasonable textbook on
- computational geometry. Two that have been recommended by
- cairo contributors are:
-
- "Computational Geometry, Algorithms and Applications", M. de
- Berg, M. van Kreveld, M. Overmars, M. Schwarzkopf;
- Springer-Verlag, ISBN: 3-540-65620-0.
-
- "Computational Geometry in C (Second Edition)", Joseph
- O'Rourke, Cambridge University Press, ISBN 0521640105.
-
-Then, if stroking, construct a polygonal representation of the pen
-approximating a circle (if filling skip three steps):
-
- "Good approximation of circles by curvature-continuous Bezier
- curves", Tor Dokken and Morten Daehlen, Computer Aided
- Geometric Design 8 (1990) 22-41.
-
-Add points to that pen based on the initial/final path faces and take
-the convex hull:
-
- Convex hull algorithm
-
- [Again, see your favorite computational geometry
- textbook. Should cite the name of the algorithm cairo uses
- here, if it has a name.]
-
-Now, "convolve" the "tracing" of the pen with the tracing of the path:
-
- "A Kinetic Framework for Computational Geometry", Leonidas
- J. Guibas, Lyle Ramshaw, and Jorge Stolfi, Proceedings of the
- 24th IEEE Annual Symposium on Foundations of Computer Science
- (FOCS), November 1983, 100-111.
-
-The result of the convolution is a polygon that must be filled. A fill
-operations begins here. We use a very conventional Bentley-Ottmann
-pass for computing the intersections, informed by some hints on robust
-implementation courtesy of John Hobby:
-
- John D. Hobby, Practical Segment Intersection with Finite
- Precision Output, Computation Geometry Theory and
- Applications, 13(4), 1999.
-
- http://cm.bell-labs.com/who/hobby/93_2-27.pdf
-
-Hobby's primary contribution in that paper is his "tolerance square"
-algorithm for robustness against edges being "bent" due to restricting
-intersection coordinates to the grid available by finite-precision
-arithmetic. This is one algorithm we have not implemented yet.
-
-We use a data-structure called Skiplists in the our implementation
-of Bentley-Ottmann:
-
- W. Pugh, Skip Lists: a Probabilistic Alternative to Balanced Trees,
- Communications of the ACM, vol. 33, no. 6, pp.668-676, 1990.
-
- 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
-may want to rasterize directly from those edges at some point.
-
-Given the set of tessellated trapezoids, we currently execute a
-straightforward, (and slow), point-sampled rasterization, (and
-currently with a near-pessimal regular 15x17 grid).
-
-We've now computed a mask which gets fed along with the source and
-destination into cairo's fundamental rendering equation. The most
-basic form of this equation is:
-
- destination = (source IN mask) OP destination
-
-with the restriction that no part of the destination outside the
-current clip region is affected. In this equation, IN refers to the
-Porter-Duff "in" operation, while OP refers to a any user-selected
-Porter-Duff operator:
-
- T. Porter & T. Duff, Compositing Digital Images Computer
- Graphics Volume 18, Number 3 July 1984 pp 253-259
-
- http://keithp.com/~keithp/porterduff/p253-porter.pdf
diff --git a/CODING_STYLE b/CODING_STYLE
index 95ceac04d..7e96c36d1 100644
--- a/CODING_STYLE
+++ b/CODING_STYLE
@@ -281,6 +281,7 @@ popular editors:
/*
* vim:sw=4:sts=4:ts=8:tw=78:fo=tcroq:cindent:cino=\:0,(0
* vim:isk=a-z,A-Z,48-57,_,.,-,>
+ * -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*-
*/
diff --git a/INSTALL b/INSTALL
index dfdc2139e..222968049 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,184 +1,47 @@
-Quick-start build instructions
-------------------------------
-1) Configure the package:
+Installation Instructions
+=========================
- ./configure
+Requirements
+------------
+As well as the requirements listed in README, the meson build also requires:
+ meson (http://mesonbuild.com)
+ ninja (http://ninja-build.org)
-2) Compile it:
+Basic Installation
+------------------
+ meson setup $builddir
+ ninja -C $builddir
+ ninja -C $builddir install
- make
+where $builddir is the name of the directory where the build artifacts
+will be written to.
-3) Install it:
+Some of the common options that can be used with "meson setup" include:
- make install
+Set the install prefix.
+ --prefix=<path>
-This final step may require temporary root access (eg. with sudo) if
-you don't have write permission to the directory in which cairo will
-be installed.
+Set the build type. Some common build types include "debug" and "release"
+ --buildtype=<buildtype>
-NOTE: If you are working with source from git/cvs rather than from a tar
-file, then you should use ./autogen.sh in place of ./configure
-anywhere it is mentioned in these instructions.
+Compiler and linker flags can be set with the CFLAGS and LDFLAGS
+environment variables.
-More detailed build instructions
---------------------------------
-1) Configure the package
+Configuring cairo backends
+--------------------------
+After running "meson build", "meson configure" can be used to display
+or modify the build configuration.
- The first step in building cairo is to configure the package by
- running the configure script. [Note: if you don't have a configure
- script, skip down below to the Extremely detailed build
- instructions.]
+eg
- The configure script attempts to automatically detect as much as
- possible about your system. So, you should primarily just accept
- its defaults by running:
+ Display configuration:
+ meson configure $builddir
- ./configure
+ Enable pdf and disable ps:
+ meson configure $builddir -Dpdf=enabled -Dps=disabled
- The configure script does accept a large number of options for
- fine-tuning its behavior. See "./configure --help" for a complete
- list. The most commonly used options are discussed here.
+The "-D" options can also be used with "meson setup"
- --prefix=PREFIX
-
- This option specifies the directory under which the software
- should be installed. By default configure will choose a
- directory such as /usr/local. If you would like to install
- cairo to some other location, pass the director to configure
- with the --prefix option. For example:
-
- ./configure --prefix=/opt/cairo
-
- would install cairo into the /opt/cairo directory. You could
- also choose a prefix directory within your home directory if
- you don't have write access to any system-wide directory.
-
- After installing into a custom prefix, you will need to set
- some environment variables to allow the software to be
- found. Assuming the /opt/cairo prefix and assuming you are
- using the bash shell, the following environment variables
- should be set:
-
- PKG_CONFIG_PATH=/opt/cairo/lib/pkgconfig
- LD_LIBRARY_PATH=/opt/cairo/lib
- export PKG_CONFIG_PATH LD_LIBRARY_PATH
-
- (NOTE: On Mac OS X, at least, use DYLD_LIBRARY_PATH in place
- of LD_LIBRARY_PATH above.)
-
- --enable-XYZ
- --enable-XYZ=yes
- --enable-XYZ=auto
- --enable-XYZ=no
- --disable-XYZ
-
- Cairo's various font and surface backends and other features can be
- enabled or disabled at configure time. Features can be divided into
- three categories based on their default state:
-
- * default=yes: These are the recommended features like PNG functions
- and PS/PDF/SVG backends. It is highly recommended to not disable
- these features but if that's really what one wants, they can be
- disabled using --disable-XYZ.
-
- * default=auto: These are the "native" features, that is, they are
- platform specific, like the Xlib surface backend. You probably
- want one or two of these. They will be automatically enabled if
- all their required facilities are available. Or you can use
- --enable-XYZ or --disable-XYZ to make your desire clear, and then
- cairo errs during configure if your intention cannot be followed.
-
- * default=no: These are the "experimental" features, and hence by
- default off. Use --enable-XYZ to enable them.
-
- The list of all features and their default state can be seen in the
- output of ./configure --help.
-
-2) Compile the package:
-
- This step is very simple. Just:
-
- make
-
- The Makefiles included with cairo are designed to work on as many
- different systems as possible.
-
- When cairo is compiled, you can also run some automated tests of
- cairo with:
-
- make check
-
- NOTE: Some versions of X servers will cause the -xlib tests to
- report failures in make check even when cairo is working just
- fine. If you see failures in nothing but -xlib tests, please
- examine the corresponding -xlib-out.png images and compare them to
- the -ref.png reference images (the -xlib-diff.png images might also
- be useful). If the results seem "close enough" please do not report
- a bug against cairo as the "failures" you are seeing are just due
- to subtle variations in X server implementations.
-
-3) Install the package:
-
- The final step is to install the package with:
-
- make install
-
- If you are installing to a system-wide location you may need to
- temporarily acquire root access in order to perform this
- operation. A good way to do this is to use the sudo program:
-
- sudo make install
-
-Extremely detailed build instructions
--------------------------------------
-So you want to build cairo but it didn't come with a configure
-script. This is probably because you have checked out the latest
-in-development code via git. If you need to be on the bleeding edge,
-(for example, because you're wanting to develop some aspect of cairo
-itself), then you're in the right place and should read on.
-
-However, if you don't need such a bleeding-edge version of cairo, then
-you might prefer to start by building the latest stable cairo release:
-
- https://cairographics.org/releases
-
-or perhaps the latest (unstable) development snapshot:
-
- https://cairographics.org/snapshots
-
-There you'll find nicely packaged tar files that include a configure
-script so you can go back the the simpler instructions above.
-
-But you're still reading, so you're someone that loves to
-learn. Excellent! We hope you'll learn enough to make some excellent
-contributions to cairo. Since you're not using a packaged tar file,
-you're going to need some additional tools beyond just a C compiler in
-order to compile cairo. Specifically, you need the following utilities:
-
- automake
- autoconf
- autoheader
- aclocal
- libtoolize
- pkg-config [at least version 0.16]
- gtk-doc (recommended)
-
-Hopefully your platform of choice has packages readily available so
-that you can easily install things with your system's package
-management tool, (such as "apt-get install automake" on Debian or "yum
-install automake" on Fedora, etc.). Note that Mac OS X ships with
-glibtoolize instead of libtoolize.
-
-Once you have all of those packages installed, the next step is to run
-the autogen.sh script. That can be as simple as:
-
- ./autogen.sh
-
-But before you run that command, note that the autogen.sh script
-accepts all the same arguments as the configure script, (and in fact,
-will generate the configure script and run it with the arguments you
-provide). So go back up to step (1) above and see what additional
-arguments you might want to pass, (such as prefix). Then continue with
-the instructions, simply using ./autogen.sh in place of ./configure.
-
-Happy hacking!
+Tests
+-----
+Refer to test/README
diff --git a/INSTALL.meson b/INSTALL.meson
deleted file mode 100644
index 4040b5479..000000000
--- a/INSTALL.meson
+++ /dev/null
@@ -1,57 +0,0 @@
-Installation Instructions
-=========================
-
-Requirements
-------------
-As well as the requirements listed in README, the meson build also requires:
- meson (http://mesonbuild.com)
- ninja (http://ninja-build.org)
-
-Basic Installation
-------------------
- meson setup $builddir
- ninja -C $builddir
- ninja -C $builddir install
-
-where $builddir is the name of the directory where the build artifacts
-will be written to.
-
-Some of the common options that can be used with "meson setup" include:
-
-Set the install prefix.
- --prefix=<path>
-
-Set the build type. Some common build types include "debug" and "release"
- --buildtype=<buildtype>
-
-Compiler and linker flags can be set with the CFLAGS and LDFLAGS
-environment variables.
-
-Configuring cairo backends
---------------------------
-After running "meson build", "meson configure" can be used to display
-or modify the build configuration.
-
-eg
-
- Display configuration:
- meson configure $builddir
-
- Enable pdf and disable ps:
- meson configure $builddir -Dpdf=enabled -Dps=disabled
-
-The "-D" options can also be used with "meson setup"
-
-Tests
------
-Refer to test/README. The main difference with running a test from a
-meson build is that the cairo-test-suite executable needs to be run in
-$builddir/test to find the image conversion executables but also needs
-to be told where the reference images are.
-
-eg
- cd $builddir/test
- srcdir="../../test" ./cairo-test-suite
-
-Where srcdir is the path to the "test" directory in the cairo source. The
-above example assumes $builddir is a directory in the cairo source tree.
diff --git a/KNOWN_ISSUES b/KNOWN_ISSUES
deleted file mode 100644
index c367f918e..000000000
--- a/KNOWN_ISSUES
+++ /dev/null
@@ -1,3 +0,0 @@
-Known Issues
-------------
-None
diff --git a/Makefile.am b/Makefile.am
deleted file mode 100644
index 8eb394ee5..000000000
--- a/Makefile.am
+++ /dev/null
@@ -1,118 +0,0 @@
-include $(top_srcdir)/build/Makefile.am.common
-
-EXTRA_DIST += \
- KNOWN_ISSUES \
- README.win32 \
- Makefile.win32 \
- build/Makefile.win32.common \
- build/Makefile.win32.inform \
- build/Makefile.win32.features \
- build/Makefile.win32.features-h \
- $(NULL)
-#MAINTAINERCLEANFILES += \
-# $(srcdir)/build/Makefile.win32.features \
-# $(srcdir)/build/Makefile.win32.features-h \
-# $(NULL)
-
-ACLOCAL_AMFLAGS = -I build ${ACLOCAL_FLAGS}
-
-DIST_SUBDIRS = src doc util boilerplate test perf
-SUBDIRS = src doc util
-# libpng is required for our test programs
-if CAIRO_HAS_PNG_FUNCTIONS
-SUBDIRS += boilerplate test perf
-endif
-
-doc:
- cd doc && $(MAKE) $(AM_MAKEFLAGS) $@
-test retest recheck: all
- cd test && $(MAKE) $(AM_MAKEFLAGS) $@
-perf: all
- cd perf && $(MAKE) $(AM_MAKEFLAGS) $@
-check-valgrind: all
- cd test && $(MAKE) $(AM_MAKEFLAGS) check-valgrind
- cd perf && $(MAKE) $(AM_MAKEFLAGS) check-valgrind
-.PHONY: doc test retest recheck perf check-valgrind
-
-
-EXTRA_DIST += \
- AUTHORS \
- BIBLIOGRAPHY \
- BUGS \
- CODING_STYLE \
- COPYING \
- COPYING-LGPL-2.1 \
- COPYING-MPL-1.1 \
- HACKING \
- INSTALL \
- NEWS \
- PORTING_GUIDE \
- README \
- RELEASING \
- autogen.sh \
- $(NULL)
-
-# Meson build system files
-EXTRA_DIST += \
- meson.build \
- meson_options.txt \
- version.py \
- boilerplate/make-cairo-boilerplate-constructors.py \
- boilerplate/meson.build \
- doc/public/meson.build \
- doc/public/version.xml.in \
- src/meson.build \
- test/make-cairo-test-constructors.py \
- test/meson.build \
- test/pdiff/meson.build \
- util/cairo-fdr/meson.build \
- util/cairo-gobject/meson.build \
- util/cairo-missing/meson.build \
- util/cairo-script/meson.build \
- util/cairo-sphinx/meson.build \
- util/cairo-trace/meson.build \
- util/meson.build \
- meson-cc-tests/atomic-ops-cxx11.c \
- meson-cc-tests/atomic-ops-gcc-legacy.c \
- meson-cc-tests/bfd-section-flags.c \
- meson-cc-tests/check-unused-result.c \
- meson-cc-tests/ft_has_color.c \
- meson-cc-tests/ipc_rmid_deferred_release.c \
- meson-cc-tests/mkdir-variant-1.c \
- meson-cc-tests/mkdir-variant-2.c \
- meson-cc-tests/pthread.c \
- subprojects/expat.wrap \
- subprojects/fontconfig.wrap \
- subprojects/freetype2.wrap \
- subprojects/glib.wrap \
- subprojects/libpng.wrap \
- subprojects/pixman.wrap \
- subprojects/zlib.wrap \
- $(NULL)
-
-DISTCLEANFILES += config.cache
-
-MAINTAINERCLEANFILES += \
- $(srcdir)/aclocal.m4 \
- $(srcdir)/autoscan.log \
- $(srcdir)/build/compile \
- $(srcdir)/build/config.guess \
- $(srcdir)/build/config.sub \
- $(srcdir)/build/depcomp \
- $(srcdir)/build/install-sh \
- $(srcdir)/build/ltmain.sh \
- $(srcdir)/build/missing \
- $(srcdir)/build/mkinstalldirs \
- $(srcdir)/config.h.in \
- $(srcdir)/configure.scan \
- $(NULL)
-
-DISTCHECK_CONFIGURE_FLAGS = \
- --enable-gtk-doc \
- --enable-test-surfaces \
- --enable-full-testing \
- $(NULL)
-
-include $(srcdir)/build/Makefile.am.changelog
-include $(srcdir)/build/Makefile.am.releasing
-include $(srcdir)/build/Makefile.am.analysis
diff --git a/Makefile.win32 b/Makefile.win32
deleted file mode 100644
index fbad7f3e4..000000000
--- a/Makefile.win32
+++ /dev/null
@@ -1,24 +0,0 @@
-default: all
-
-# Do not edit this file.
-# Edit build/Makefile.win32.common for customization
-
-top_srcdir = .
-include $(top_srcdir)/build/Makefile.win32.inform
-
-all: cairo
-
-cairo: inform
- @$(MAKE) -C src -f Makefile.win32
-
-perf: inform
- @$(MAKE) -C perf -f Makefile.win32 perf
-
-test: inform
- @$(MAKE) -C test -f Makefile.win32 test
-
-clean:
- @$(MAKE) -C boilerplate -f Makefile.win32 clean
- @$(MAKE) -C perf -f Makefile.win32 clean
- @$(MAKE) -C src -f Makefile.win32 clean
- @$(MAKE) -C test -f Makefile.win32 clean
diff --git a/NEWS b/NEWS
index a6b14d937..29e4a0aa0 100644
--- a/NEWS
+++ b/NEWS
@@ -1,16 +1,58 @@
+Release 1.17.8 (2023-01-30 Emmanuele Bassi <ebassi@gnome.org>)
+==============================================================
+
+A new cairo snapshot! And it only took less than one year, this time!
+
+Many thanks to everyone who contributed to cairo, and especially
+to (in no particular order):
+
+- Adrian Johnson
+- Khaled Hosny
+- Behdad Esfahbod
+- Matthias Clasen
+- Uli Schlachter
+- Manuel Stoeckl
+- Fujii Hironori
+- Tim-Philipp Müller
+- Luca Bacci
+- Caolán McNamara
+- John Ralls
+
+In a continuing effort to reduce the amount of legacy code, and increase
+the long-term maintainability of cairo, the following backends have been
+removed:
+
+- GL and GLES drawing
+
+Additionally, cairo's Autotools build system has been removed; from now on,
+cairo will only support the Meson build system. While the end result should
+be identical, further testing is appreciated.
+
+In this snapshot, cairo gained support for rendering COLRv1 fonts, and
+rendering SVG and COLRv1 fonts with custom palettes.
+
+Support for macOS and Windows has been improved, with lots of build and bug
+fixes.
+
+Lots of safety issues have been fixed, with array bounds checking and
+plugging memory leaks, as well as fixes for bugs identified via fuzzying.
+
+This is going to be the last snapshot of the 1.17 development cycle; we only
+expect minor bug fixing and improvements until the 1.18.0 release.
+
Release 1.17.6 (2022-03-18 Emmanuele Bassi <ebassi@gnome.org>)
==============================================================
-I spy with my little eye… a Cairo snapshot!
+I spy with my little eye… a cairo snapshot!
-First of all, many, many thanks to everyone who contributed to Cairo
+First of all, many, many thanks to everyone who contributed to cairo
during this development cycle. A special thank you goes to:
- Adrian Johnson
- Uli Schlachter
for their tireless efforts in ensuring that the lights are still on
-in the Cairo project.
+in the cairo project.
This snapshot sees the removal of the following backends and platform
support:
@@ -24,7 +66,7 @@ support:
- OpenVG
Thanks to all past contributors for their work on them. If you were using
-any of these backends then you will need to stick to Cairo 1.16.
+any of these backends then you will need to stick to cairo 1.16.
To offset the removal of the backends above, Adrian Johnson landed the
DWrite font rendering backend on Windows.
@@ -34,7 +76,7 @@ John Ralls.
Tim-Philipp Müller has kept the Meson build in top shape.
-This snapshot is going to be the **last** release of Cairo with the
+This snapshot is going to be the **last** release of cairo with the
Autotools build system. The Meson build has seen many improvements and
it is considerably easier to maintain and faster to build.
diff --git a/PORTING_GUIDE b/PORTING_GUIDE
deleted file mode 100644
index 7488173c4..000000000
--- a/PORTING_GUIDE
+++ /dev/null
@@ -1,265 +0,0 @@
- ...-----=======-----...
- Cairo 1.0 Porting Guide
- ...-----=======-----...
-
-Here are some notes on more easily porting cairo_code from cairo 0.4
-to cairo 1.0. It is sorted roughly in order of importance, (the items
-near the top are expected to affect the most people).
-
-Automated API renamings
-=======================
-There have been a lot of simple renamings where the functionality is
-the same but the name of the symbol is different. We have provided a
-script to automate the conversion of these symbols. It can be found
-within the cairo distribution in:
-
- util/cairo-api-update
-
-This script is used by installing it somewhere on your PATH, and the
-running it and providing the names of your source files on the command
-line. For example:
-
- cairo-api-update *.[ch]
-
-The script will first save backup copies of each file (renamed with a
-.bak extension) and then will perform all of the simple renamings.
-
-For your benefit, the script also produces messages giving filenames
-and line numbers for several of the manual API updates that you will
-need to perform as described below.
-
-
-Manual API changes
-==================
-This section of the porting guide describes changes you will have to
-manually make to your source code. In addition to the information in
-this guide, the cairo-api-update script will notify you of some of
-these issues as described above.
-
-Cairo's deprecation warnings
-----------------------------
-Also, if your compiler provides warnings for implicit declarations of
-functions, (eg. "gcc -Wall"), then simply attempting to compile your
-program will cause cairo to generate messages intended to guide you
-through the porting process.
-
-For example, if you neglect to update an old call to
-cairo_set_target_drawable, you might see an error message as follows:
-
- foo.c:10: warning: implicit declaration of function
- ‘cairo_set_target_drawable_DEPRECATED_BY_cairo_xlib_surface_create’
-
-This message is indicating to you that the deprecatd function
-cairo_set_target_drawable appears in your program foo.c on line 10,
-and you should rewrite your program to call cairo_xlib_surface_create
-instead.
-
-The remainder of this porting guide is arranged as a set of common
-code patterns that appear in old (cairo-0.4) code and how it should be
-transformed to new (cairo-0.5) code.
-
-cairo_create
-------------
-Was: cr = cairo_create ();
- cairo_set_target_foo (cr, args);
- /* draw */
- cairo_destroy (cr);
-
-Now: cairo_surface_t *surface;
-
- surface = cairo_foo_surface_create (args);
- cr = cairo_create (surface);
- /* draw */
- cairo_destroy (cr);
- cairo_surface_destroy (surface);
-
-Or: cairo_surface_t *surface;
-
- surface = cairo_foo_surface_create (args);
- cr = cairo_create (surface);
- cairo_surface_destroy (surface);
- /* draw */
- cairo_destroy (cr);
-
-NOTE: Many of the cairo_foo_surface_create functions accept the
- identical arguments as the the old cairo_set_target_foo
- functions, (minus the cairo_t*), making this transformation
- quite easy. One notable exception is cairo_set_target_drawable
- which, when it becomes cairo_xlib_surface_create must pickup new
- arguments for the Visual*, the width, and the height.
-
-cairo_set_alpha (1)
--------------------
-Was: cairo_set_rgb_color (cr, red, green, blue);
- cairo_set_alpha (cr, alpha);
-
-Now: cairo_set_source_rgba (cr, red, green, blue, alpha);
-
-cairo_show_surface
-------------------
-Was: cairo_show_surface (cr, surface, width, height);
-
-Now: cairo_set_source_surface (cr, surface, x, y);
- cairo_paint (cr);
-
-NOTE: The type signatures of cairo_show_surface and cairo_set_source
- are the same, but pay attention that cairo_show_surface required
- the width and height, while cairo_set_source_surface requires
- the X,Y location to where the surface will be placed.
-
-cairo_set_alpha (2)
--------------------
-Was: cairo_set_alpha (cr, alpha);
- cairo_show_surface (cr, surface, width, height);
-
-Now: cairo_set_source_surface (cr, surface, x, y);
- cairo_paint_with_alpha (cr, alpha);
-
-filling and stroking
---------------------
-Was: cairo_save (cr);
- /* set fill color */
- cairo_fiill (cr);
- cairo_restore (cr);
- /* set stroke color */
- cairo_stroke (cr);
-
-Now: /* set fill color */
- cairo_fill_preserve (cr);
- /* set stroke color */
- cairo_stroke (cr);
-
-NOTE: The current path is no longer saved/restored by
- cairo_save/cairo_restore. This can lead to some subtle
- surprises, so look out.
-
-cairo_matrix_t
---------------
-Was: cairo_matrix_t *matrix;
-
- matrix = cairo_matrix_create ();
- /* Do stuff with matrix */
- cairo_matrix_destroy (matrix);
-
-Now: cairo_matrix_t matrix;
- cairo_matrix_init_identity (&matrix);
- /* Do stuff with &matrix */
-
-NOTE: If you are really lazy, you can still use a cairo_matrix_t* and
- avoid putting the &matrix all over by just replacing
- cairo_matrix_create() with malloc() and cairo_matrix_destroy()
- with free(). That's not as nice, and you still need to be
- careful to see if you need to initialize it to an identity
- matrix as cairo_matrix_create() did for you.
-
-Rendering to a temporary surface
---------------------------------
-Was: cairo_save (cr);
- {
- cairo_set_target_surface (cr, temporary);
- /* draw through cr onto temporary */
- }
- cairo_restore (cr);
- /* use temporary as source on cr */
-
-Now: {
- cr2 = cairo_create (temporary);
- /* draw through cr2 onto temporary */
- cairo_destory (cr2);
- }
- /* use temporary as source on cr */
-
-NOTE: Having to create another cairo_t is a bit annoying, but having
- to invent a new name for it is just awful, (imagine a deeply
- nested version of this code). Fortunately, the style above is
- just a stop-gap measure until the new group API comes along.
-
-Iterating over a path
----------------------
-Was: cairo_current_path (cr,
- my_move_to,
- my_line_to,
- my_curve_to,
- my_close_path,
- closure);
-
-Now: int i;
- cairo_path_t *path;
- cairo_path_data_t *data;
-
- path = cairo_copy_path (cr);
-
- for (i=0; i < path->num_data; i += path->data[i].header.length) {
- data = &path->data[i];
- switch (data->header.type) {
- case CAIRO_PATH_MOVE_TO:
- my_move_to (closure, data[1].point.x, data[1].point.y);
- break;
- case CAIRO_PATH_LINE_TO:
- my_line_to (closure, data[1].point.x, data[1].point.y);
- break;
- case CAIRO_PATH_CURVE_TO:
- my_curve_to (closure, data[1].point.x, data[1].point.y,
- data[2].point.x, data[2].point.y,
- data[3].point.x, data[3].point.y);
- break;
- case CAIRO_PATH_CLOSE_PATH:
- my_close_path (closure);
- break;
- }
- }
- cairo_path_destroy (path);
-
-NOTE: This version makes it looks like the new form is a _lot_ more
- verbose than the old version. But realize that the old version
- required the support of 4 additional functions. The new approach
- allows great flexibility including the ability to inline the
- entire operation within the switch statement when appropriate.
-
-Erasing a surface to transparent
---------------------------------
-Was: cairo_set_rgb_color (cr, 0., 0., 0.);
- cairo_set_alpha (cr, 0.)
- cairo_set_operator (cr, CAIRO_OPERATOR_SRC);
- cairo_rectangle (cr, 0., 0., surface_width, surface_height);
- cairo_fill (cr);
-
- or: cairo_set_rgb_color (cr, 0., 0., 0.);
- cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
- cairo_rectangle (cr, 0., 0., surface_width, surface_height);
- cairo_fill (cr);
-
-Now: cairo_set_source_rgba (cr, 0., 0., 0., 0.);
- cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
- cairo_paint (cr);
-
- or: cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
- cairo_paint (cr);
-
-NOTE: Using cairo_rectangle and fill would still work just fine. It's
- just a lot more convenient to use cairo_paint now, (particularly
- as it doesn't require you to even know what the bounds of the
- target surface are).
-
-Drawing to a PNG file
----------------------
-Was: file = fopen (filename, "w");
- cr = cairo_create ();
- cairo_set_target_png (cr, file, format, width, height);
- /* draw image */
- cairo_destroy (cr);
- fclose (file);
-
-Now: surface = cairo_image_surface_create (format, width, height);
- cr = cairo_create (surface);
- /* draw image */
- cairo_surface_write_to_png (surface, filename);
- cairo_destroy (cr);
- cairo_surface_destroy (surface);
-
-NOTE: The png backend is gone. So there is no cairo_png_surface_create
- to take the place of cairo_set_target_png. And notice that we
- used an image surface here, but it is just as easy to use
- cairo_surface_write_to_png with an xlib or other surface, (but
- not PDF at the moment). This is one of the big advantages of
- this approach as opposed to a PNG surface.
diff --git a/README b/README
deleted file mode 100644
index 40df870f2..000000000
--- a/README
+++ /dev/null
@@ -1,184 +0,0 @@
-Cairo - Multi-platform 2D graphics library
-https://cairographics.org
-
-What is cairo
-=============
-Cairo is a 2D graphics library with support for multiple output
-devices. Currently supported output targets include the X Window
-System (via both Xlib and XCB), quartz, win32, and image buffers,
-as well as PDF, PostScript, and SVG file output. Experimental backends
-include OpenGL.
-
-Cairo is designed to produce consistent output on all output media
-while taking advantage of display hardware acceleration when available
-(for example, through the X Render Extension).
-
-The cairo API provides operations similar to the drawing operators of
-PostScript and PDF. Operations in cairo include stroking and filling
-cubic Bézier splines, transforming and compositing translucent images,
-and antialiased text rendering. All drawing operations can be
-transformed by any affine transformation (scale, rotation, shear,
-etc.).
-
-Cairo has been designed to let you draw anything you want in a modern
-2D graphical user interface. At the same time, the cairo API has been
-designed to be as fun and easy to learn as possible. If you're not
-having fun while programming with cairo, then we have failed
-somewhere---let us know and we'll try to fix it next time around.
-
-Cairo is free software and 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.
-
-Where to get more information about cairo
-=========================================
-The primary source of information about cairo is:
-
- https://cairographics.org/
-
-The latest versions of cairo can always be found at:
-
- https://cairographics.org/download
-
-Documentation on using cairo and frequently-asked questions:
-
- https://cairographics.org/documentation
- https://cairographics.org/FAQ
-
-Mailing lists for contacting cairo users and developers:
-
- https://cairographics.org/lists
-
-Roadmap and unscheduled things to do, (please feel free to help out):
-
- https://cairographics.org/roadmap
- https://cairographics.org/todo
-
-Dependencies
-============
-The set of libraries needed to compile cairo depends on which backends
-are enabled when cairo is configured. So look at the list below to
-determine which dependencies are needed for the backends of interest.
-
-For the surface backends, we have both "supported" and "experimental"
-backends. Further, the supported backends can be divided into the
-"standard" backends which can be easily built on any platform, and the
-"platform" backends which depend on some underlying platform-specific
-system, (such as the X Window System or some other window system).
-
-As an example, for a standard Linux build similar to what's shipped by
-your distro, (with image, png, pdf, PostScript, svg, and xlib surface
-backends, and the freetype font backend), the following sample commands
-will install necessary dependencies:
-
- Debian (and similar):
-
- apt-get build-dep cairo
-
- Fedora (and similar):
-
- yum install libpng-devel zlib-devel libXrender-devel fontconfig-devel
-
-Technically you probably don't need pixman from the distribution since
-if you're manually compiling Cairo you probably want an updated pixman
-as well. However, if you follow the default settings and install pixman
-to /usr/local, your Cairo build should properly use it in preference to
-the system pixman.
-
-
-Supported, "standard" surface backends
-------------------------------------
- image backend (required)
- ------------------------
- pixman >= 0.30.0 https://cairographics.org/releases
-
- png support (can be left out if desired, but many
- ----------- applications expect it to be present)
- libpng http://www.libpng.org/pub/png/libpng.html
-
- pdf backend
- -----------
- zlib http://www.gzip.org/zlib
-
- postscript backend
- ------------------
- zlib http://www.gzip.org/zlib
-
- svg backend
- -----------
- [none]
-
-Supported, "platform" surface backends
------------------------------------
- xlib backend
- ------------
- X11 https://freedesktop.org/Software/xlibs
-
- xlib-xrender backend
- --------------------
- Xrender >= 0.6 https://freedesktop.org/Software/xlibs
-
- quartz backend
- --------------
- MacOS X >= 10.4 with Xcode >= 2.5
-
- win32 backend
- -------------
- Microsoft Windows 2000 or newer[*].
-
- xcb backend
- -----------
- XCB https://xcb.freedesktop.org
-
-Font backends (required to have at least one)
----------------------------------------------
- freetype font backend
- ---------------------
- freetype >= 2.1.9 http://freetype.org
- fontconfig http://fontconfig.org
-
- quartz-font backend
- -------------------
- MacOS X >= 10.4 with Xcode >= 2.4
-
- win32 font backend
- ------------------
- Microsoft Windows 2000 or newer[*].
-
- [*] The Win32 backend should work on Windows 2000 and newer
- (excluding Windows Me.) Most testing has been done on
- Windows XP. While some portions of the code have been
- adapted to work on older versions of Windows, considerable
- work still needs to be done to get cairo running in those
- environments.
-
- Cairo can be compiled on Windows with either the gcc
- toolchain (see http://www.mingw.org) or with Microsoft
- Visual C++. If the gcc toolchain is used, the standard
- build instructions using configure apply, (see INSTALL).
- If Visual C++ is desired, GNU make is required and
- Makefile.win32 can be used via 'make -f Makefile.win32'.
- The compiler, include paths, and library paths must be set
- up correctly in the environment.
-
- MSVC versions earlier than 7.1 are known to miscompile
- parts of cairo and pixman, and so should be avoided. MSVC
- 7.1 or later, including the free Microsoft Visual Studio
- Express editions, produce correct code.
-
-
-Compiling
-=========
-See the INSTALL document for build instructions.
-
-
-History
-=======
-Cairo was originally developed by Carl Worth <cworth@cworth.org> and
-Keith Packard <keithp@keithp.com>. Many thanks are due to Lyle Ramshaw
-without whose patient help our ignorance would be much more apparent.
-
-Since the original development, many more people have contributed to
-cairo. See the AUTHORS files for as complete a list as we've been able
-to compile so far.
diff --git a/README.md b/README.md
new file mode 100644
index 000000000..025f8486d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,177 @@
+# Cairo: Multi-platform 2D graphics library
+
+<https://cairographics.org>
+
+What is cairo
+-------------
+
+Cairo is a 2D graphics library with support for multiple output
+devices. Currently supported output targets include the X Window
+System (via both Xlib and XCB), quartz, win32, and image buffers,
+as well as PDF, PostScript, and SVG file output. Experimental backends
+include OpenGL.
+
+Cairo is designed to produce consistent output on all output media
+while taking advantage of display hardware acceleration when available
+(for example, through the X Render Extension).
+
+The cairo API provides operations similar to the drawing operators of
+PostScript and PDF. Operations in cairo include stroking and filling
+cubic Bézier splines, transforming and compositing translucent images,
+and antialiased text rendering. All drawing operations can be
+transformed by any affine transformation (scale, rotation, shear,
+etc.).
+
+Cairo has been designed to let you draw anything you want in a modern
+2D graphical user interface. At the same time, the cairo API has been
+designed to be as fun and easy to learn as possible. If you're not
+having fun while programming with cairo, then we have failed
+somewhere---let us know and we'll try to fix it next time around.
+
+Cairo is free software and 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.
+
+Where to get more information about cairo
+-----------------------------------------
+
+The primary source of information about cairo is its website:
+
+- <https://cairographics.org>
+
+The latest versions of cairo can always be found at:
+
+- <https://cairographics.org/download>
+
+Documentation on using cairo and frequently-asked questions:
+
+- <https://cairographics.org/documentation>
+- <https://cairographics.org/FAQ>
+
+Mailing lists for contacting cairo users and developers:
+
+- <https://cairographics.org/lists>
+
+Roadmap and unscheduled things to do, (please feel free to help out):
+
+- https://cairographics.org/roadmap
+- https://cairographics.org/todo
+
+Dependencies
+------------
+
+The set of libraries needed to compile cairo depends on which backends are
+enabled when cairo is configured. So look at the list below to determine
+which dependencies are needed for the backends of interest.
+
+For the surface backends, we have both "supported" and "experimental"
+backends. Further, the supported backends can be divided into the "standard"
+backends which can be easily built on any platform, and the "platform"
+backends which depend on some underlying platform-specific system, (such as
+the X Window System or some other window system).
+
+As an example, for a standard Linux build similar to what's shipped by your
+distro, (with image, png, pdf, PostScript, svg, and xlib surface backends,
+and the freetype font backend), the following sample commands will install
+necessary dependencies:
+
+- Debian (and similar):
+ - `apt-get build-dep cairo`
+
+- Fedora (and similar):
+ - `dnf builddep cairo`
+
+Technically you probably don't need pixman from the distribution since if
+you're manually compiling Cairo you probably want an updated pixman as well.
+However, if you follow the default settings and install pixman to
+/usr/local, your Cairo build should properly use it in preference to the
+system pixman.
+
+
+### Supported, "standard" surface backends
+
+#### image backend (required)
+
+- [pixman](https://cairographics.org/releases) >= 0.30.0
+
+#### PNG support (preferred)
+
+- [libpng](http://www.libpng.org/pub/png/libpng.html)
+
+#### PDF backend
+
+- [zlib](http://www.gzip.org/zlib)
+
+#### PostScript backend
+
+- [zlib](http://www.gzip.org/zlib)
+
+#### SVG backend
+
+- none
+
+### Supported, "platform" surface backends
+
+#### Xlib backend
+
+- [X11](https://freedesktop.org/Software/xlibs)
+
+#### xlib-xrender backend
+
+- [Xrender](https://freedesktop.org/Software/xlibs) >= 0.6
+
+#### Quartz backend
+
+- macOS >= 10.4 with Xcode >= 2.5
+
+#### Windows backend
+
+- Microsoft Windows 2000 or newer.
+
+#### XCB backend
+
+- [XCB](https://xcb.freedesktop.org)
+
+### Font backends (required)
+
+#### freetype font backend
+
+- [freetype](https://freetype.org) >= 2.1.9
+- [fontconfig](https://www.freedesktop.org/wiki/Software/fontconfig/)
+
+#### Quartz-font backend
+
+- MacOS X >= 10.4 with Xcode >= 2.5
+
+#### Windows GDI font backend
+
+- Microsoft Windows 2000 or newer
+
+#### Windows DirectWrite font backend
+
+- Microsoft Windows 7 or newer
+
+Compiling
+---------
+
+See the [`INSTALL`](./INSTALL) document for build instructions.
+
+Licensing
+---------
+
+Cairo is released under the terms of either the GNU Lesser General Public
+License version 2.1, or the terms of the Mozilla Public License version 1.1.
+
+See the [`COPYING`](./COPYING) document for more information.
+
+History
+-------
+
+Cairo was originally developed by Carl Worth <cworth@cworth.org> and Keith
+Packard <keithp@keithp.com>. Many thanks are due to Lyle Ramshaw without
+whose patient help our ignorance would be much more apparent.
+
+Since the original development, many more people have contributed to cairo.
+See the [`AUTHORS`](./AUTHORS) document for as complete a list as we've been
+able to compile so far.
diff --git a/RELEASING b/RELEASING
deleted file mode 100644
index 04c78e20a..000000000
--- a/RELEASING
+++ /dev/null
@@ -1,215 +0,0 @@
-Here are the steps to follow to create a new cairo release:
-
-0) Decide type of release and checkout the appropriate branch.
-
- The Cairo project makes three types of releases: Development
- snapshot releases, stable minor releases, and stable micro (aka
- "point") releases. Micro releases should be only bugfixes and
- no API additions. If there are API additions consider making a
- Minor release. Snapshot releases can be done of the current
- development tree between Minor releases, as desired.
-
- For stable releases (both minor and micro), the work should be
- done on the given release branch. E.g. for 1.14.12, check out
- the 1.14 branch via "git checkout origin/1.14 -b 1.14".
-
-1) Ensure that there are no local, uncommitted/unpushed mods.
-
- You're probably in a good state if both "git diff
- HEAD" and "git log master..origin/master" give no output. Also make
- sure you have libglib2.0-doc installed (else you'll get
- excessive gtk-doc cross reference warnings in the next step).
-
-2) Verify that the code passes "make distcheck"
-
- First, make sure you have 'nm' and 'readelf' commands in PATH.
- this should be OK with any Linux distro.
-
- Running "make distcheck" should result in no warnings or
- errors and end with a message of the form:
-
- =============================================
- cairo-X.Y.Z archives ready for distribution:
- cairo-X.Y.Z.tar.gz
- =============================================
-
- (But the tar file isn't actually ready yet, as we still have
- some more steps to follow).
-
- Note that it's allowed (and perhaps recommended) to run the
- "make distcheck" step against an all-software X server such as
- Xvfb to avoid getting tripped up by any X-server-driver-specific
- bugs. See test/README for details
-
- If you get errors about local PLT entries, you get the list of
- cairo entries with the error. For each of these, a call to
- slim_hidden_def and slim_hidden_proto is needed in the cairo
- implementation in the style of other similar calls.
-
- In the unfortunate case that you have to push a snapshot out
- (note, I said snapshot, not release) without the entire test
- suite passing, here's the magic env vars to set when doing
- 'make distcheck' and 'make release-publish' that will let you
- get away with it. At any cost, never ever release without
- (implied) distchecking. Every time we got around it, it turned
- out to be a disaster. Anyway, here's the pass code:
-
- DISPLAY= CAIRO_TEST_TARGET=" "
-
-3) Decide what the new version number for the release will be.
-
- Cairo uses even numbers for official releases, and odd numbers
- for development snapshots. Thus, for a Minor release it would
- be:
-
- LAST_RELEASE="X.Y.Z" # e.g. 1.12.0
- THIS_RELEASE="X.Y+2.0" # e.g. 1.14.0
-
- While for a Micro release the version numbers should be:
-
- LAST_RELEASE="X.Y.Z" # e.g. 1.14.0
- THIS_RELEASE="X.Y.Z+2" # e.g. 1.14.2
-
- Snapshots are similar but have odd minor versions. Also, the
- first snapshot release in a new series will be .2 rather than
- .0, e.g.:
-
- LAST_RELEASE="X.Y.Z" # e.g. 1.14.0
- THIS_RELEASE="X.Y+1.0" # e.g. 1.15.2
-
- and subsequent snapshots in that series are just normal micro
- releases:
-
- LAST_RELEASE="X.Y.Z" # e.g. 1.15.2
- THIS_RELEASE="X.Y.Z+2" # e.g. 1.15.4
-
-4) Fill out an entry in the NEWS file
-
- Sift through the logs since the last release. This is most
- easily done with a command such as:
-
- git log --stat ${LAST_RELEASE}..
-
- Summarize major changes briefly in a style similar to other
- entries in NEWS. Take special care to note any additions in
- the API. These should be easy to find by noting modifications
- to .h files in the log command above. And more specifically,
- the following command will show each patch that has changed a
- public header file since the given version:
-
- find src/ -name '*.h' ! -name '*-private.h' \
- ! -name 'cairoint.h' ! -name 'cairo-*features*.h' | \
- xargs git diff ${LAST_RELEASE}.. --
-
- Include a link to the incremental ChangeLog for this release,
- which we'll be uploading in a later step:
-
- https://cairographics.org/releases/ChangeLog.cairo-${THIS_RELEASE}
-
-4) Increment cairo_version_{minor|micro} in src/cairo-version.h:
-
- If there are backward-incompatible changes in the API, stop
- now and don't release. Go back and fix the API instead. Cairo
- is intended to remain backwards-compatible as far as API.
-
- So cairo_version_major will not be incremented unless we come
- up with a new versioning scheme to take advantage of it.
-
- If there are API additions, then increment cairo_version_minor
- and reset cairo_version_micro to 0. NOTE: The minor version is
- only incremented for releases, not for snapshots.
-
- Otherwise, (i.e. there are only bug fixes), increment
- cairo_version_micro to the next larger (even) number.
-
-5) For Minor releases, add an index entry to doc/public/cairo-docs.xml
-
- Towards the end of the file, add a new section for the stable
- release. It'll look something like:
-
- <index id="index-X.Y" role="X.Y">
- <title>Index of new symbols in X.Y</title>
- </index>
-
-6) Commit the changes to NEWS and src/cairo-version.h
-
- It's especially important to mention the new version number in your
- commit log.
-
-7) Run "make release-publish" which will perform the following steps
- for you:
-
- * Generate ChangeLog files out of git repository
- * Check that ChangeLog files were generated properly
- * Check that the version number ends with an even micro component
- * Check that no release exists with the current version
- * Verify that make distcheck completes successfully
- * Generate the final tar file
- * Generate an sha1sum file
- * Sign the sha1sum using your GPG setup (asks for your GPG password)
- * scp the three files to appear on https://cairographics.org/releases
- * Generate a versioned manual and upload it to appear as both:
- https://cairographics.org/manual-${THIS_RELEASE}
- https://cairographics.org/manual
- * Place local copies of the three files in the releases directory
- * Create a LATEST-package-version file (after deleting any old one)
- * Tag the entire source tree with a ${THIS_RELEASE} tag, and sign
- the tag with your GPG key (asks for your GPG password, and you
- may need to set GIT_COMMITTER_NAME and GIT_COMMITTER_EMAIL to match
- your public-key's setting or this fails.)
- * Provide some text for the release announcement (see below).
- If for some reason you lost this message, "make release-publish-message"
- prints it for you.
-
- Upload the incremental ChangeLog generated by the above. For
- minor stable releases, this is:
-
- scp ChangeLog \
- cairographics.org:/srv/cairo.freedesktop.org/www/releases/ChangeLog.cairo-${THIS_RELEASE}
-
- for micro and snapshot releases, the command is:
-
- scp ChangeLog.cache-${LAST_RELEASE}.. \
- cairographics.org:/srv/cairo.freedesktop.org/www/releases/ChangeLog.cairo-${THIS_RELEASE}
-
- To undo a release-publish, before you've sent any emails or
- pushed changes to master, delete the locally created tag (git
- tag -d ${THIS_RELEASE}); then log into the webserver, repoint
- the manual and LATEST-cairo-${THIS_RELEASE} symlinks to the
- previous versions, remove manual-${THIS_RELEASE} and
- release/cairo-${THIS_RELEASE}.
-
-8) Push the new tag out to the central tree with a command like:
-
- git push origin master ${THIS_RELEASE}
-
-9) Update master (or the stable branch) version number.
-
- For Micro releases (X.Y.Z+2), increment cairo_version_micro to
- the next larger (odd) number in src/cairo-version.h, commit, and
- push.
-
- DEVEL_VERSION="X.Y.Z+1" # e.g. 1.15.10 -> 1.15.11
-
- For Minor releases (X.Y.0), increment cairo_version_minor to the
- next larger (odd) number, and set cairo_version_micro to 1. Then
- commit and push.
-
- DEVEL_VERSION="X.Y.Z+1" # e.g. 1.16.0 -> 1.17.1
-
- git commit src/cairo-version.h -m "Bump version for ${DEVEL_VERSION}"
-
-10) Send out an announcement message.
-
- Send a message to cairo-announce@cairographics.org and CC
- cairo@cairographics.org, gnome-announce-list@gnome.org and
- ftp-release@lists.freedesktop.org (pr@lwn.net as well for major
- releases) to announce the new release using the text provided from
- "make release-publish", adding the excerpt from NEWS and
- the shortlog of all changes since last release, generated by:
-
- git shortlog ${LAST_RELEASE}...
-
-11) Add the announcement to the website as a new entry in the news/
- dir. It will automatically get indexed onto the homepage when the
- site refreshes.
diff --git a/acinclude.m4 b/acinclude.m4
deleted file mode 100644
index ffff235f7..000000000
--- a/acinclude.m4
+++ /dev/null
@@ -1,55 +0,0 @@
-dnl -*- mode: autoconf -*-
-
-dnl [m4_newline] didn't appear until autoconf 2.62
-m4_ifdef([m4_newline],,[m4_define([m4_newline],[
-])])
-
-dnl These are not available in autoconf 2.59
-
-m4_ifdef([m4_foreach_w],,[m4_define([m4_foreach_w],
-[m4_foreach([$1], m4_split(m4_normalize([$2]), [ ]), [$3])])])
-
-m4_ifdef([AS_CASE],,[
-m4_define([_AS_CASE],
-[m4_if([$#], 0, [m4_fatal([$0: too few arguments: $#])],
- [$#], 1, [ *) $1 ;;],
- [$#], 2, [ $1) m4_default([$2], [:]) ;;],
- [ $1) m4_default([$2], [:]) ;;
-$0(m4_shift2($@))])dnl
-])
-m4_defun([AS_CASE],
-[m4_ifval([$2$3],
-[case $1 in
-_AS_CASE(m4_shift($@))
-esac
-])dnl
-])# AS_CASE
-])
-
-m4_ifdef([m4_shift2],, [m4_define([m4_shift2], [m4_shift(m4_shift($@))])])
-
-
-dnl ==========================================================================
-
-dnl This has to be in acinclude.m4 as it includes other files
-
-dnl Parse Version.mk and declare m4 variables out of it
-m4_define([CAIRO_PARSE_VERSION],dnl
- m4_translit(dnl
- m4_bpatsubst(m4_include(src/cairo-version.h),
- [^.define \([a-zA-Z0-9_]*\) *\([0-9][0-9]*\)],
- [[m4_define(\1, \2)]]),
- [A-Z], [a-z])dnl
-)dnl
-
-dnl ==========================================================================
-
-m4_pattern_forbid([^cr_])
-
-dnl AC_AUTOCONF_VERSION was introduced in 2.62, so its definition works as
-dnl a conditional on version >= 2.62. Older versions did not call
-dnl m4_pattern_allow from AC_DEFINE and friends. To avoid lots of warnings we
-dnl only forbid CAIRO_ if autoconf is recent enough.
-m4_ifdef([AC_AUTOCONF_VERSION],
-[m4_pattern_forbid([CAIRO])],
-[m4_pattern_forbid([_CAIRO])])
diff --git a/autogen.sh b/autogen.sh
deleted file mode 100755
index 4b10251db..000000000
--- a/autogen.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/sh
-# Run this to generate all the initial makefiles, etc.
-
-test -n "$srcdir" || srcdir=`dirname "$0"`
-test -n "$srcdir" || srcdir=.
-
-ORIGDIR=`pwd`
-cd $srcdir
-
-AUTORECONF=`which autoreconf`
-if test -z $AUTORECONF; then
- echo "*** No autoreconf found, please install it ***"
- exit 1
-fi
-
-GTKDOCIZE=`which gtkdocize`
-if test -z $GTKDOCIZE; then
- echo "*** No GTK-Doc found, documentation won't be generated ***"
-else
- gtkdocize || exit $?
-fi
-
-# create dummy */Makefile.am.features and ChangeLog to make automake happy
-> boilerplate/Makefile.am.features
-> src/Makefile.am.features
-touch ChangeLog
-
-autoreconf --install --verbose || exit $?
-
-cd $ORIGDIR
-test -n "$NOCONFIGURE" || "$srcdir/configure" "$@"
diff --git a/boilerplate/Makefile.am b/boilerplate/Makefile.am
deleted file mode 100644
index 57fec733c..000000000
--- a/boilerplate/Makefile.am
+++ /dev/null
@@ -1,56 +0,0 @@
-# Note: All source files are listed in Makefile.sources.
-
-include $(top_srcdir)/build/Makefile.am.common
-include $(srcdir)/Makefile.am.features
-
-EXTRA_DIST += Makefile.win32 Makefile.win32.features
-#MAINTAINERCLEANFILES += $(srcdir)/Makefile.win32.features
-
-AM_CPPFLAGS = \
- -I$(srcdir) \
- -I$(top_builddir)/src \
- -I$(top_srcdir)/src \
- $(CAIRO_CFLAGS) \
- $(NULL)
-AM_LDFLAGS = $(CAIRO_LDFLAGS)
-
-EXTRA_LTLIBRARIES += libcairoboilerplate.la
-
-
-libcairoboilerplate_la_SOURCES = \
- $(enabled_cairo_boilerplate_headers) \
- $(enabled_cairo_boilerplate_private) \
- $(enabled_cairo_boilerplate_sources) \
- cairo-boilerplate-constructors.c \
- $(NULL)
-libcairoboilerplate_la_LIBADD = $(top_builddir)/src/libcairo.la \
- $(CAIRO_LIBS) \
- $(CAIROBOILERPLATE_LIBS) \
- $(NULL)
-libcairoboilerplate_la_DEPENDENCIES = \
- $(NULL)
-
-if CAIRO_HAS_DL
-libcairoboilerplate_la_LIBADD += -ldl
-endif
-
-if CAIRO_HAS_WIN32_SURFACE
-libcairoboilerplate_la_LIBADD += -lwinspool
-endif
-
-cairo-boilerplate-constructors.c: Makefile $(enabled_cairo_boilerplate_sources) make-cairo-boilerplate-constructors.sh
- (cd $(srcdir) && sh ./make-cairo-boilerplate-constructors.sh $(enabled_cairo_boilerplate_sources)) > $@
-
-BUILT_SOURCES += cairo-boilerplate-constructors.c
-EXTRA_DIST += $(BUILT_SOURCES) make-cairo-boilerplate-constructors.sh
-CLEANFILES += $(BUILT_SOURCES)
-
-test: check
-
-if CROSS_COMPILING
-else
-TESTS += check-link$(EXEEXT)
-endif
-
-check_PROGRAMS += check-link
-check_link_LDADD = libcairoboilerplate.la
diff --git a/boilerplate/Makefile.sources b/boilerplate/Makefile.sources
deleted file mode 100644
index a9bc20ccb..000000000
--- a/boilerplate/Makefile.sources
+++ /dev/null
@@ -1,34 +0,0 @@
-# Makefile.sources
-#
-# This file is pretty similar to $(top_srcdir)/src/Makefile.sources,
-# but for boilerplate. Unlike that file, there are no special headers.
-#
-
-cairo_boilerplate_headers = \
- cairo-boilerplate-getopt.h \
- cairo-boilerplate-scaled-font.h \
- cairo-boilerplate-system.h \
- cairo-boilerplate.h \
- $(NULL)
-cairo_boilerplate_sources = \
- cairo-boilerplate-getopt.c \
- cairo-boilerplate-system.c \
- cairo-boilerplate.c \
- $(NULL)
-cairo_boilerplate_private = \
- cairo-boilerplate-private.h \
- $(NULL)
-
-cairo_boilerplate_glx_sources = cairo-boilerplate-glx.c
-cairo_boilerplate_wgl_sources = cairo-boilerplate-wgl.c
-cairo_boilerplate_egl_sources = cairo-boilerplate-egl.c
-cairo_boilerplate_pdf_sources = cairo-boilerplate-pdf.c
-cairo_boilerplate_ps_sources = cairo-boilerplate-ps.c
-cairo_boilerplate_quartz_sources = cairo-boilerplate-quartz.c
-cairo_boilerplate_script_sources = cairo-boilerplate-script.c
-cairo_boilerplate_svg_sources = cairo-boilerplate-svg.c
-cairo_boilerplate_test_surfaces_sources = cairo-boilerplate-test-surfaces.c
-cairo_boilerplate_win32_sources = cairo-boilerplate-win32.c cairo-boilerplate-win32-printing.c
-cairo_boilerplate_xcb_sources = cairo-boilerplate-xcb.c
-cairo_boilerplate_xlib_headers = cairo-boilerplate-xlib.h
-cairo_boilerplate_xlib_sources = cairo-boilerplate-xlib.c
diff --git a/boilerplate/Makefile.win32 b/boilerplate/Makefile.win32
deleted file mode 100644
index 29df5cf79..000000000
--- a/boilerplate/Makefile.win32
+++ /dev/null
@@ -1,24 +0,0 @@
-top_srcdir = ..
-include $(top_srcdir)/build/Makefile.win32.common
-include Makefile.win32.features
-
-HEADERS = \
- $(enabled_cairo_boilerplate_headers) \
- $(enabled_cairo_boilerplate_private) \
- $(NULL)
-
-SOURCES = \
- $(enabled_cairo_boilerplate_sources) \
- cairo-boilerplate-constructors.c \
- $(NULL)
-
-OBJECTS = $(patsubst %.c, $(CFG)/%-static.obj, $(SOURCES))
-
-cairo-boilerplate-constructors.c: Makefile.sources Makefile.win32 $(enabled_cairo_boilerplate_sources) make-cairo-boilerplate-constructors.sh
- sh ./make-cairo-boilerplate-constructors.sh $(enabled_cairo_boilerplate_sources) > $@
-
-all: $(CFG)/boiler.lib
-
-
-$(CFG)/boiler.lib: $(OBJECTS)
- @$(AR) $(CAIRO_ARFLAGS) -OUT:$@ $(OBJECTS)
diff --git a/boilerplate/Makefile.win32.features b/boilerplate/Makefile.win32.features
deleted file mode 100644
index c2415afae..000000000
--- a/boilerplate/Makefile.win32.features
+++ /dev/null
@@ -1,353 +0,0 @@
-# Generated by configure. Do not edit.
-
-ifeq ($(top_srcdir),)
-include Makefile.sources
-else
-include $(top_srcdir)/boilerplate/Makefile.sources
-endif
-
-supported_cairo_boilerplate_headers = $(cairo_boilerplate_headers)
-unsupported_cairo_boilerplate_headers =
-all_cairo_boilerplate_headers = $(cairo_boilerplate_headers)
-all_cairo_boilerplate_private = $(cairo_boilerplate_private)
-all_cairo_boilerplate_sources = $(cairo_boilerplate_sources)
-
-enabled_cairo_boilerplate_headers = $(cairo_boilerplate_headers)
-enabled_cairo_boilerplate_private = $(cairo_boilerplate_private)
-enabled_cairo_boilerplate_sources = $(cairo_boilerplate_sources)
-
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_xlib_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_xlib_sources)
-ifeq ($(CAIRO_HAS_XLIB_SURFACE),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_xlib_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xlib_sources)
-endif
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_xrender_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_xrender_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_xlib_xrender_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_xlib_xrender_sources)
-ifeq ($(CAIRO_HAS_XLIB_XRENDER_SURFACE),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_xrender_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_xlib_xrender_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xlib_xrender_sources)
-endif
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_xcb_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_xcb_sources)
-ifeq ($(CAIRO_HAS_XCB_SURFACE),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_xcb_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xcb_sources)
-endif
-
-unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_xcb_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_xcb_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_xlib_xcb_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_xlib_xcb_sources)
-ifeq ($(CAIRO_HAS_XLIB_XCB_FUNCTIONS),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_xcb_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_xlib_xcb_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xlib_xcb_sources)
-endif
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_shm_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_shm_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_xcb_shm_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_xcb_shm_sources)
-ifeq ($(CAIRO_HAS_XCB_SHM_FUNCTIONS),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_shm_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_xcb_shm_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xcb_shm_sources)
-endif
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_quartz_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_quartz_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_quartz_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_quartz_sources)
-ifeq ($(CAIRO_HAS_QUARTZ_SURFACE),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_quartz_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_quartz_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_quartz_sources)
-endif
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_quartz_font_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_quartz_font_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_quartz_font_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_quartz_font_sources)
-ifeq ($(CAIRO_HAS_QUARTZ_FONT),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_quartz_font_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_quartz_font_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_quartz_font_sources)
-endif
-
-unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_quartz_image_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_quartz_image_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_quartz_image_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_quartz_image_sources)
-ifeq ($(CAIRO_HAS_QUARTZ_IMAGE_SURFACE),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_quartz_image_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_quartz_image_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_quartz_image_sources)
-endif
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_win32_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_win32_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_win32_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_win32_sources)
-ifeq ($(CAIRO_HAS_WIN32_SURFACE),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_win32_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_win32_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_win32_sources)
-endif
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_win32_font_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_win32_font_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_win32_font_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_win32_font_sources)
-ifeq ($(CAIRO_HAS_WIN32_FONT),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_win32_font_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_win32_font_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_win32_font_sources)
-endif
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_png_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_png_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_png_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_png_sources)
-ifeq ($(CAIRO_HAS_PNG_FUNCTIONS),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_png_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_png_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_png_sources)
-endif
-
-unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_gl_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_gl_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_gl_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_gl_sources)
-ifeq ($(CAIRO_HAS_GL_SURFACE),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_gl_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_gl_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_gl_sources)
-endif
-
-unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_glesv2_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_glesv2_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_glesv2_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_glesv2_sources)
-ifeq ($(CAIRO_HAS_GLESV2_SURFACE),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_glesv2_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_glesv2_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_glesv2_sources)
-endif
-
-unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_glesv3_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_glesv3_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_glesv3_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_glesv3_sources)
-ifeq ($(CAIRO_HAS_GLESV3_SURFACE),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_glesv3_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_glesv3_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_glesv3_sources)
-endif
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_egl_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_egl_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_egl_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_egl_sources)
-ifeq ($(CAIRO_HAS_EGL_FUNCTIONS),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_egl_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_egl_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_egl_sources)
-endif
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_glx_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_glx_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_glx_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_glx_sources)
-ifeq ($(CAIRO_HAS_GLX_FUNCTIONS),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_glx_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_glx_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_glx_sources)
-endif
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_wgl_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_wgl_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_wgl_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_wgl_sources)
-ifeq ($(CAIRO_HAS_WGL_FUNCTIONS),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_wgl_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_wgl_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_wgl_sources)
-endif
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_script_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_script_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_script_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_script_sources)
-ifeq ($(CAIRO_HAS_SCRIPT_SURFACE),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_script_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_script_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_script_sources)
-endif
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_ft_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_ft_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_ft_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_ft_sources)
-ifeq ($(CAIRO_HAS_FT_FONT),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_ft_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_ft_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_ft_sources)
-endif
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_fc_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_fc_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_fc_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_fc_sources)
-ifeq ($(CAIRO_HAS_FC_FONT),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_fc_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_fc_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_fc_sources)
-endif
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_ps_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_ps_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_ps_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_ps_sources)
-ifeq ($(CAIRO_HAS_PS_SURFACE),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_ps_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_ps_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_ps_sources)
-endif
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_pdf_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_pdf_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_pdf_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_pdf_sources)
-ifeq ($(CAIRO_HAS_PDF_SURFACE),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_pdf_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_pdf_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_pdf_sources)
-endif
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_svg_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_svg_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_svg_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_svg_sources)
-ifeq ($(CAIRO_HAS_SVG_SURFACE),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_svg_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_svg_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_svg_sources)
-endif
-
-all_cairo_boilerplate_private += $(cairo_boilerplate_test_surfaces_private) $(cairo_boilerplate_test_surfaces_headers)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_test_surfaces_sources)
-ifeq ($(CAIRO_HAS_TEST_SURFACES),1)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_test_surfaces_private) $(cairo_boilerplate_test_surfaces_headers)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_test_surfaces_sources)
-endif
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_image_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_image_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_image_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_image_sources)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_image_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_image_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_image_sources)
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_mime_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_mime_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_mime_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_mime_sources)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_mime_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_mime_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_mime_sources)
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_recording_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_recording_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_recording_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_recording_sources)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_recording_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_recording_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_recording_sources)
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_observer_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_observer_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_observer_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_observer_sources)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_observer_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_observer_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_observer_sources)
-
-unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_tee_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_tee_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_tee_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_tee_sources)
-ifeq ($(CAIRO_HAS_TEE_SURFACE),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_tee_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_tee_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_tee_sources)
-endif
-
-unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_xml_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_xml_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_xml_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_xml_sources)
-ifeq ($(CAIRO_HAS_XML_SURFACE),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_xml_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_xml_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xml_sources)
-endif
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_user_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_user_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_user_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_user_sources)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_user_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_user_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_user_sources)
-
-all_cairo_boilerplate_private += $(cairo_boilerplate_pthread_private) $(cairo_boilerplate_pthread_headers)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_pthread_sources)
-ifeq ($(CAIRO_HAS_PTHREAD),1)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_pthread_private) $(cairo_boilerplate_pthread_headers)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_pthread_sources)
-endif
-
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_gobject_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_gobject_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_gobject_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_gobject_sources)
-ifeq ($(CAIRO_HAS_GOBJECT_FUNCTIONS),1)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_gobject_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_gobject_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_gobject_sources)
-endif
-
-all_cairo_boilerplate_private += $(cairo_boilerplate_trace_private) $(cairo_boilerplate_trace_headers)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_trace_sources)
-ifeq ($(CAIRO_HAS_TRACE),1)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_trace_private) $(cairo_boilerplate_trace_headers)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_trace_sources)
-endif
-
-all_cairo_boilerplate_private += $(cairo_boilerplate_interpreter_private) $(cairo_boilerplate_interpreter_headers)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_interpreter_sources)
-ifeq ($(CAIRO_HAS_INTERPRETER),1)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_interpreter_private) $(cairo_boilerplate_interpreter_headers)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_interpreter_sources)
-endif
-
-all_cairo_boilerplate_private += $(cairo_boilerplate_symbol_lookup_private) $(cairo_boilerplate_symbol_lookup_headers)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_symbol_lookup_sources)
-ifeq ($(CAIRO_HAS_SYMBOL_LOOKUP),1)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_symbol_lookup_private) $(cairo_boilerplate_symbol_lookup_headers)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_symbol_lookup_sources)
-endif
diff --git a/boilerplate/cairo-boilerplate-egl.c b/boilerplate/cairo-boilerplate-egl.c
deleted file mode 100644
index 8196b1ffd..000000000
--- a/boilerplate/cairo-boilerplate-egl.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/* Cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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.
- */
-
-#include "cairo-boilerplate-private.h"
-
-#include <cairo-gl.h>
-#if CAIRO_HAS_GLESV3_SURFACE
-#include <GLES3/gl3.h>
-#include <EGL/eglext.h>
-#elif CAIRO_HAS_GLESV2_SURFACE
-#include <GLES2/gl2.h>
-#elif CAIRO_HAS_GL_SURFACE
-#include <GL/gl.h>
-#endif
-
-typedef struct _egl_target_closure {
- EGLDisplay dpy;
- EGLContext ctx;
-
- cairo_device_t *device;
- cairo_surface_t *surface;
-} egl_target_closure_t;
-
-static void
-_cairo_boilerplate_egl_cleanup (void *closure)
-{
- egl_target_closure_t *gltc = closure;
-
- cairo_device_finish (gltc->device);
- cairo_device_destroy (gltc->device);
-
- eglDestroyContext (gltc->dpy, gltc->ctx);
- eglMakeCurrent (gltc->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- eglTerminate (gltc->dpy);
-
- free (gltc);
-}
-
-static cairo_surface_t *
-_cairo_boilerplate_egl_create_surface (const char *name,
- cairo_content_t content,
- double width,
- double height,
- double max_width,
- double max_height,
- cairo_boilerplate_mode_t mode,
- void **closure)
-{
- egl_target_closure_t *gltc;
- cairo_surface_t *surface;
- int major, minor;
- EGLConfig config;
- EGLint numConfigs;
- EGLint config_attribs[] = {
- EGL_RED_SIZE, 8,
- EGL_GREEN_SIZE, 8,
- EGL_BLUE_SIZE, 8,
- EGL_ALPHA_SIZE, 8,
- EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
-#if CAIRO_HAS_GLESV3_SURFACE
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
-#elif CAIRO_HAS_GLESV2_SURFACE
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-#elif CAIRO_HAS_GL_SURFACE
- EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
-#endif
- EGL_NONE
- };
- const EGLint ctx_attribs[] = {
-#if CAIRO_HAS_GLESV3_SURFACE
- EGL_CONTEXT_CLIENT_VERSION, 3,
-#elif CAIRO_HAS_GLESV2_SURFACE
- EGL_CONTEXT_CLIENT_VERSION, 2,
-#endif
- EGL_NONE
- };
-
- gltc = xcalloc (1, sizeof (egl_target_closure_t));
- *closure = gltc;
-
- gltc->dpy = eglGetDisplay (EGL_DEFAULT_DISPLAY);
-
- if (! eglInitialize (gltc->dpy, &major, &minor)) {
- free (gltc);
- return NULL;
- }
-
- eglChooseConfig (gltc->dpy, config_attribs, &config, 1, &numConfigs);
-#if CAIRO_HAS_GLESV3_SURFACE && CAIRO_HAS_GLESV2_SURFACE
- if (numConfigs == 0) {
- /* retry with ES2_BIT */
- config_attribs[11] = ES2_BIT; /* FIXME: Ick */
- eglChooseConfig (gltc->dpy, config_attribs, &config, 1, &numConfigs);
- }
-#endif
- if (numConfigs == 0) {
- free (gltc);
- return NULL;
- }
-
-#if CAIRO_HAS_GLESV3_SURFACE || CAIRO_HAS_GLESV2_SURFACE
- eglBindAPI (EGL_OPENGL_ES_API);
-#elif CAIRO_HAS_GL_SURFACE
- eglBindAPI (EGL_OPENGL_API);
-#endif
-
- gltc->ctx = eglCreateContext (gltc->dpy, config, EGL_NO_CONTEXT,
- ctx_attribs);
- if (gltc->ctx == EGL_NO_CONTEXT) {
- eglTerminate (gltc->dpy);
- free (gltc);
- return NULL;
- }
-
- gltc->device = cairo_egl_device_create (gltc->dpy, gltc->ctx);
- if (mode == CAIRO_BOILERPLATE_MODE_PERF)
- cairo_gl_device_set_thread_aware(gltc->device, FALSE);
-
- if (width < 1)
- width = 1;
- if (height < 1)
- height = 1;
-
- gltc->surface = surface = cairo_gl_surface_create (gltc->device,
- content,
- ceil (width),
- ceil (height));
- if (cairo_surface_status (surface))
- _cairo_boilerplate_egl_cleanup (gltc);
-
- return surface;
-}
-
-static void
-_cairo_boilerplate_egl_synchronize (void *closure)
-{
- egl_target_closure_t *gltc = closure;
-
- if (cairo_device_acquire (gltc->device))
- return;
-
- glFinish ();
-
- cairo_device_release (gltc->device);
-}
-
-static const cairo_boilerplate_target_t targets[] = {
- {
- "egl", "gl", NULL, NULL,
- CAIRO_SURFACE_TYPE_GL, CAIRO_CONTENT_COLOR_ALPHA, 1,
- "cairo_egl_device_create",
- _cairo_boilerplate_egl_create_surface,
- cairo_surface_create_similar,
- NULL, NULL,
- _cairo_boilerplate_get_image_surface,
- cairo_surface_write_to_png,
- _cairo_boilerplate_egl_cleanup,
- _cairo_boilerplate_egl_synchronize,
- NULL,
- TRUE, FALSE, FALSE
- }
-};
-CAIRO_BOILERPLATE (egl, targets)
diff --git a/boilerplate/cairo-boilerplate-glx.c b/boilerplate/cairo-boilerplate-glx.c
deleted file mode 100644
index 7701d908f..000000000
--- a/boilerplate/cairo-boilerplate-glx.c
+++ /dev/null
@@ -1,457 +0,0 @@
-/* Cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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.
- */
-
-#include "cairo-boilerplate-private.h"
-
-#include <cairo-gl.h>
-
-#include <X11/X.h>
-#include <X11/Xutil.h> /* for XDestroyImage */
-
-static const cairo_user_data_key_t gl_closure_key;
-
-typedef struct _gl_target_closure {
- Display *dpy;
- int screen;
- Window drawable;
-
- GLXContext ctx;
- cairo_device_t *device;
- cairo_surface_t *surface;
-} gl_target_closure_t;
-
-static void
-_cairo_boilerplate_gl_cleanup (void *closure)
-{
- gl_target_closure_t *gltc = closure;
-
- cairo_device_finish (gltc->device);
- cairo_device_destroy (gltc->device);
-
- glXDestroyContext (gltc->dpy, gltc->ctx);
-
- if (gltc->drawable)
- XDestroyWindow (gltc->dpy, gltc->drawable);
- XCloseDisplay (gltc->dpy);
-
- free (gltc);
-}
-
-static cairo_surface_t *
-_cairo_boilerplate_gl_create_surface (const char *name,
- cairo_content_t content,
- double width,
- double height,
- double max_width,
- double max_height,
- cairo_boilerplate_mode_t mode,
- void **closure)
-{
- int rgba_attribs[] = { GLX_RGBA,
- GLX_RED_SIZE, 1,
- GLX_GREEN_SIZE, 1,
- GLX_BLUE_SIZE, 1,
- GLX_ALPHA_SIZE, 1,
- GLX_DOUBLEBUFFER,
- None };
- int rgb_attribs[] = { GLX_RGBA,
- GLX_RED_SIZE, 1,
- GLX_GREEN_SIZE, 1,
- GLX_BLUE_SIZE, 1,
- GLX_DOUBLEBUFFER,
- None };
- XVisualInfo *visinfo;
- GLXContext ctx;
- gl_target_closure_t *gltc;
- cairo_surface_t *surface;
- Display *dpy;
-
- gltc = calloc (1, sizeof (gl_target_closure_t));
- *closure = gltc;
-
- width = ceil (width);
- height = ceil (height);
-
- if (width == 0)
- width = 1;
- if (height == 0)
- height = 1;
-
- dpy = XOpenDisplay (NULL);
- gltc->dpy = dpy;
- if (!gltc->dpy) {
- fprintf (stderr, "Failed to open display: %s\n", XDisplayName(0));
- free (gltc);
- return NULL;
- }
-
- if (mode == CAIRO_BOILERPLATE_MODE_TEST)
- XSynchronize (gltc->dpy, 1);
-
- if (content == CAIRO_CONTENT_COLOR)
- visinfo = glXChooseVisual (dpy, DefaultScreen (dpy), rgb_attribs);
- else
- visinfo = glXChooseVisual (dpy, DefaultScreen (dpy), rgba_attribs);
-
- if (visinfo == NULL) {
- fprintf (stderr, "Failed to create RGB, double-buffered visual\n");
- XCloseDisplay (dpy);
- free (gltc);
- return NULL;
- }
-
- ctx = glXCreateContext (dpy, visinfo, NULL, True);
- XFree (visinfo);
-
- gltc->ctx = ctx;
- gltc->device = cairo_glx_device_create (dpy, ctx);
-
- if (mode == CAIRO_BOILERPLATE_MODE_PERF)
- cairo_gl_device_set_thread_aware(gltc->device, FALSE);
-
- gltc->surface = surface = cairo_gl_surface_create (gltc->device,
- content, width, height);
- if (cairo_surface_status (surface))
- _cairo_boilerplate_gl_cleanup (gltc);
-
- return surface;
-}
-
-static cairo_surface_t *
-_cairo_boilerplate_gl_create_window_common (int rgba_attribs[],
- cairo_content_t content,
- double width,
- double height,
- double max_width,
- double max_height,
- cairo_boilerplate_mode_t mode,
- gl_target_closure_t *gltc)
-{
- XVisualInfo *vi;
- GLXContext ctx;
- cairo_surface_t *surface;
- Display *dpy;
- XSetWindowAttributes attr;
-
- width = ceil (width);
- height = ceil (height);
-
- if (width == 0)
- width = 1;
- if (height == 0)
- height = 1;
-
- dpy = XOpenDisplay (NULL);
- gltc->dpy = dpy;
- if (!gltc->dpy) {
- fprintf (stderr, "Failed to open display: %s\n", XDisplayName(0));
- free (gltc);
- return NULL;
- }
-
- if (mode == CAIRO_BOILERPLATE_MODE_TEST)
- XSynchronize (gltc->dpy, 1);
-
- vi = glXChooseVisual (dpy, DefaultScreen (dpy), rgba_attribs);
- if (vi == NULL) {
- fprintf (stderr, "Failed to create RGBA, double-buffered visual\n");
- XCloseDisplay (dpy);
- free (gltc);
- return NULL;
- }
-
- attr.colormap = XCreateColormap (dpy,
- RootWindow (dpy, vi->screen),
- vi->visual,
- AllocNone);
- attr.border_pixel = 0;
- attr.override_redirect = True;
- gltc->drawable = XCreateWindow (dpy, DefaultRootWindow (dpy), 0, 0,
- width, height, 0, vi->depth,
- InputOutput, vi->visual,
- CWOverrideRedirect | CWBorderPixel | CWColormap,
- &attr);
- XMapWindow (dpy, gltc->drawable);
-
- ctx = glXCreateContext (dpy, vi, NULL, True);
- XFree (vi);
-
- gltc->ctx = ctx;
- gltc->device = cairo_glx_device_create (dpy, ctx);
-
- gltc->surface = surface = cairo_gl_surface_create_for_window (gltc->device,
- gltc->drawable,
- width, height);
- if (cairo_surface_status (surface)) {
- _cairo_boilerplate_gl_cleanup (gltc);
- return NULL;
- }
- return surface;
-}
-
-static cairo_surface_t *
-_cairo_boilerplate_gl_create_window (const char *name,
- cairo_content_t content,
- double width,
- double height,
- double max_width,
- double max_height,
- cairo_boilerplate_mode_t mode,
- void **closure)
-{
- gl_target_closure_t *gltc;
-
- int rgba_attribs[] = { GLX_RGBA,
- GLX_RED_SIZE, 1,
- GLX_GREEN_SIZE, 1,
- GLX_BLUE_SIZE, 1,
- GLX_ALPHA_SIZE, 1,
- GLX_DOUBLEBUFFER,
- GLX_NONE };
-
- gltc = calloc (1, sizeof (gl_target_closure_t));
- *closure = gltc;
-
- return _cairo_boilerplate_gl_create_window_common (rgba_attribs, content,
- width, height,
- max_width, max_height,
- mode, gltc);
-}
-
-static cairo_surface_t *
-_cairo_boilerplate_gl_create_window_msaa (const char *name,
- cairo_content_t content,
- double width,
- double height,
- double max_width,
- double max_height,
- cairo_boilerplate_mode_t mode,
- void **closure)
-{
- gl_target_closure_t *gltc;
-
- int rgba_attribs[] = { GLX_RGBA,
- GLX_RED_SIZE, 1,
- GLX_GREEN_SIZE, 1,
- GLX_BLUE_SIZE, 1,
- GLX_ALPHA_SIZE, 1,
- GLX_STENCIL_SIZE, 1,
- GLX_SAMPLES, 4,
- GLX_SAMPLE_BUFFERS, 1,
- GLX_DOUBLEBUFFER,
- GLX_NONE };
-
- gltc = calloc (1, sizeof (gl_target_closure_t));
- *closure = gltc;
- return _cairo_boilerplate_gl_create_window_common (rgba_attribs, content,
- width, height,
- max_width, max_height,
- mode, gltc);
-
-}
-
-static cairo_surface_t *
-_cairo_boilerplate_gl_create_window_db (const char *name,
- cairo_content_t content,
- double width,
- double height,
- double max_width,
- double max_height,
- cairo_boilerplate_mode_t mode,
- void **closure)
-{
- cairo_status_t status;
- cairo_surface_t *surface;
- gl_target_closure_t *gltc;
-
- int rgba_attribs[] = { GLX_RGBA,
- GLX_RED_SIZE, 1,
- GLX_GREEN_SIZE, 1,
- GLX_BLUE_SIZE, 1,
- GLX_ALPHA_SIZE, 1,
- GLX_DOUBLEBUFFER,
- GLX_NONE };
-
- gltc = calloc (1, sizeof (gl_target_closure_t));
- *closure = gltc;
-
- surface = _cairo_boilerplate_gl_create_window_common (rgba_attribs, content,
- width, height,
- max_width, max_height,
- mode, gltc);
-
- if (! surface)
- return NULL;
-
- surface = cairo_surface_create_similar (gltc->surface, content, width, height);
- status = cairo_surface_set_user_data (surface, &gl_closure_key, gltc, NULL);
- if (status == CAIRO_STATUS_SUCCESS)
- return surface;
-
- cairo_surface_destroy (surface);
- _cairo_boilerplate_gl_cleanup (gltc);
- return cairo_boilerplate_surface_create_in_error (status);
-}
-
-static cairo_status_t
-_cairo_boilerplate_gl_finish_window (cairo_surface_t *surface)
-{
- gl_target_closure_t *gltc = cairo_surface_get_user_data (surface,
- &gl_closure_key);
-
- if (gltc != NULL && gltc->surface != NULL) {
- cairo_t *cr;
-
- cr = cairo_create (gltc->surface);
- cairo_surface_set_device_offset (surface, 0, 0);
- cairo_set_source_surface (cr, surface, 0, 0);
- cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
- cairo_paint (cr);
- cairo_destroy (cr);
-
- surface = gltc->surface;
- }
-
- cairo_gl_surface_swapbuffers (surface);
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_boilerplate_gl_synchronize (void *closure)
-{
- gl_target_closure_t *gltc = closure;
-
- if (cairo_device_acquire (gltc->device))
- return;
-
- glFinish ();
-
- cairo_device_release (gltc->device);
-}
-
-static char *
-_cairo_boilerplate_gl_describe (void *closure)
-{
- gl_target_closure_t *gltc = closure;
- char *s;
- const GLubyte *vendor, *renderer, *version;
-
- if (cairo_device_acquire (gltc->device))
- return NULL;
-
- vendor = glGetString (GL_VENDOR);
- renderer = glGetString (GL_RENDERER);
- version = glGetString (GL_VERSION);
-
- xasprintf (&s, "%s %s %s", vendor, renderer, version);
-
- cairo_device_release (gltc->device);
-
- return s;
-}
-
-static const cairo_boilerplate_target_t targets[] = {
- {
- "gl", "gl", NULL, NULL,
- CAIRO_SURFACE_TYPE_GL, CAIRO_CONTENT_COLOR_ALPHA, 1,
- "cairo_gl_surface_create",
- _cairo_boilerplate_gl_create_surface,
- cairo_surface_create_similar,
- NULL, NULL,
- _cairo_boilerplate_get_image_surface,
- cairo_surface_write_to_png,
- _cairo_boilerplate_gl_cleanup,
- _cairo_boilerplate_gl_synchronize,
- _cairo_boilerplate_gl_describe,
- TRUE, FALSE, FALSE
- },
- {
- "gl", "gl", NULL, NULL,
- CAIRO_SURFACE_TYPE_GL, CAIRO_CONTENT_COLOR, 1,
- "cairo_gl_surface_create",
- _cairo_boilerplate_gl_create_surface,
- cairo_surface_create_similar,
- NULL, NULL,
- _cairo_boilerplate_get_image_surface,
- cairo_surface_write_to_png,
- _cairo_boilerplate_gl_cleanup,
- _cairo_boilerplate_gl_synchronize,
- _cairo_boilerplate_gl_describe,
- FALSE, FALSE, FALSE
- },
- {
- "gl-window", "gl", NULL, NULL,
- CAIRO_SURFACE_TYPE_GL, CAIRO_CONTENT_COLOR_ALPHA, 1,
- "cairo_gl_surface_create_for_window",
- _cairo_boilerplate_gl_create_window,
- cairo_surface_create_similar,
- NULL,
- _cairo_boilerplate_gl_finish_window,
- _cairo_boilerplate_get_image_surface,
- cairo_surface_write_to_png,
- _cairo_boilerplate_gl_cleanup,
- _cairo_boilerplate_gl_synchronize,
- _cairo_boilerplate_gl_describe,
- FALSE, FALSE, FALSE
- },
- {
- "gl-window-msaa", "gl", NULL, NULL,
- CAIRO_SURFACE_TYPE_GL, CAIRO_CONTENT_COLOR_ALPHA, 1,
- "cairo_gl_surface_create_for_window",
- _cairo_boilerplate_gl_create_window_msaa,
- cairo_surface_create_similar,
- NULL,
- _cairo_boilerplate_gl_finish_window,
- _cairo_boilerplate_get_image_surface,
- cairo_surface_write_to_png,
- _cairo_boilerplate_gl_cleanup,
- _cairo_boilerplate_gl_synchronize,
- _cairo_boilerplate_gl_describe,
- FALSE, FALSE, FALSE
- },
- {
- "gl-window&", "gl", NULL, NULL,
- CAIRO_SURFACE_TYPE_GL, CAIRO_CONTENT_COLOR_ALPHA, 1,
- "cairo_gl_surface_create_for_window",
- _cairo_boilerplate_gl_create_window_db,
- cairo_surface_create_similar,
- NULL,
- _cairo_boilerplate_gl_finish_window,
- _cairo_boilerplate_get_image_surface,
- cairo_surface_write_to_png,
- _cairo_boilerplate_gl_cleanup,
- _cairo_boilerplate_gl_synchronize,
- _cairo_boilerplate_gl_describe,
- FALSE, FALSE, FALSE
- },
-};
-CAIRO_BOILERPLATE (gl, targets)
diff --git a/boilerplate/cairo-boilerplate-quartz.c b/boilerplate/cairo-boilerplate-quartz.c
index d4ca35383..1a1417c75 100644
--- a/boilerplate/cairo-boilerplate-quartz.c
+++ b/boilerplate/cairo-boilerplate-quartz.c
@@ -26,7 +26,7 @@
#include "cairo-boilerplate-private.h"
-#include <cairo-quartz.h>
+#include <cairo-quartz-private.h>
static cairo_surface_t *
_cairo_boilerplate_quartz_create_surface (const char *name,
@@ -56,7 +56,7 @@ static const cairo_boilerplate_target_t targets[] = {
cairo_surface_create_similar,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
- cairo_surface_write_to_png,
+ _cairo_quartz_surface_to_png,
NULL, NULL, NULL,
TRUE, FALSE, FALSE
},
@@ -68,7 +68,7 @@ static const cairo_boilerplate_target_t targets[] = {
cairo_surface_create_similar,
NULL, NULL,
_cairo_boilerplate_get_image_surface,
- cairo_surface_write_to_png,
+ _cairo_quartz_surface_to_png,
NULL, NULL, NULL,
FALSE, FALSE, FALSE
},
diff --git a/boilerplate/cairo-boilerplate-wgl.c b/boilerplate/cairo-boilerplate-wgl.c
deleted file mode 100644
index 908817788..000000000
--- a/boilerplate/cairo-boilerplate-wgl.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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):
- * Zoxc <zoxc32@gmail.com>
- */
-
-#include "cairo-boilerplate-private.h"
-
-#include <cairo-gl.h>
-
-static const cairo_user_data_key_t gl_closure_key;
-
-typedef struct _wgl_target_closure {
- HWND wnd;
- HDC dc;
- HGLRC rc;
- cairo_device_t *device;
- cairo_surface_t *surface;
-} wgl_target_closure_t;
-
-static void
-_cairo_boilerplate_wgl_cleanup (void *closure)
-{
- wgl_target_closure_t *wgltc = closure;
-
- cairo_device_finish (wgltc->device);
- cairo_device_destroy (wgltc->device);
-
- wglDeleteContext(wgltc->rc);
-
- ReleaseDC(wgltc->wnd, wgltc->dc);
- DestroyWindow (wgltc->wnd);
-
- free (wgltc);
-}
-
-static void
-_cairo_boilerplate_wgl_create_window (int width,
- int height,
- wgl_target_closure_t *wgltc)
-{
- WNDCLASSEXA wincl;
- PIXELFORMATDESCRIPTOR pfd;
- int format;
- cairo_surface_t *surface;
-
- ZeroMemory (&wincl, sizeof (WNDCLASSEXA));
- wincl.cbSize = sizeof (WNDCLASSEXA);
- wincl.hInstance = GetModuleHandle (0);
- wincl.lpszClassName = "cairo_boilerplate_wgl_dummy";
- wincl.lpfnWndProc = DefWindowProcA;
- wincl.style = CS_OWNDC;
-
- RegisterClassExA (&wincl);
-
- wgltc->wnd = CreateWindow ("cairo_boilerplate_wgl_dummy", 0, WS_POPUP, 0, 0, width, height, 0, 0, 0, 0);
- wgltc->dc = GetDC (wgltc->wnd);
-
- ZeroMemory (&pfd, sizeof (PIXELFORMATDESCRIPTOR));
- pfd.nSize = sizeof (PIXELFORMATDESCRIPTOR);
- pfd.nVersion = 1;
- pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
- pfd.iPixelType = PFD_TYPE_RGBA;
- pfd.cColorBits = 24;
- pfd.cDepthBits = 16;
- pfd.iLayerType = PFD_MAIN_PLANE;
-
- format = ChoosePixelFormat (wgltc->dc, &pfd);
- SetPixelFormat (wgltc->dc, format, &pfd);
-
- wgltc->rc = wglCreateContext (wgltc->dc);
- wgltc->device = cairo_wgl_device_create (wgltc->rc);
-}
-
-static cairo_surface_t *
-_cairo_boilerplate_wgl_create_surface (const char *name,
- cairo_content_t content,
- double width,
- double height,
- double max_width,
- double max_height,
- cairo_boilerplate_mode_t mode,
- void **closure)
-{
- wgl_target_closure_t *wgltc;
- cairo_surface_t *surface;
-
- wgltc = calloc (1, sizeof (wgl_target_closure_t));
-
- *closure = wgltc;
-
- _cairo_boilerplate_wgl_create_window(0, 0, wgltc);
-
- if (width == 0)
- width = 1;
- if (height == 0)
- height = 1;
-
- wgltc->surface = surface = cairo_gl_surface_create (wgltc->device,
- content,
- ceil (width),
- ceil (height));
- if (cairo_surface_status (surface)) {
- _cairo_boilerplate_wgl_cleanup (wgltc);
- return NULL;
- }
-
- return surface;
-}
-
-static cairo_surface_t *
-_cairo_boilerplate_wgl_for_create_window (const char *name,
- cairo_content_t content,
- double width,
- double height,
- double max_width,
- double max_height,
- cairo_boilerplate_mode_t mode,
- void **closure)
-{
- wgl_target_closure_t *wgltc;
- cairo_surface_t *surface;
-
- wgltc = calloc (1, sizeof (wgl_target_closure_t));
-
- *closure = wgltc;
-
- _cairo_boilerplate_wgl_create_window(width, height, wgltc);
-
- wgltc->surface = surface = cairo_gl_surface_create_for_dc (wgltc->device,
- wgltc->dc,
- ceil (width),
- ceil (height));
-
- if (cairo_surface_status (surface)) {
- _cairo_boilerplate_wgl_cleanup (wgltc);
- return NULL;
- }
-
- return surface;
-}
-
-static cairo_status_t
-_cairo_boilerplate_wgl_finish_window (cairo_surface_t *surface)
-{
- wgl_target_closure_t *wgltc = cairo_surface_get_user_data (surface,
- &gl_closure_key);
-
- if (wgltc != NULL && wgltc->surface != NULL) {
- cairo_t *cr;
-
- cr = cairo_create (wgltc->surface);
- cairo_surface_set_device_offset (surface, 0, 0);
- cairo_set_source_surface (cr, surface, 0, 0);
- cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
- cairo_paint (cr);
- cairo_destroy (cr);
-
- surface = wgltc->surface;
- }
-
- cairo_gl_surface_swapbuffers (surface);
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_boilerplate_wgl_synchronize (void *closure)
-{
- wgl_target_closure_t *wgltc = closure;
-
- if (cairo_device_acquire (wgltc->device))
- return;
-
- glFinish ();
-
- cairo_device_release (wgltc->device);
-}
-
-static const cairo_boilerplate_target_t targets[] = {
- {
- "gl", "gl", NULL, NULL,
- CAIRO_SURFACE_TYPE_GL, CAIRO_CONTENT_COLOR_ALPHA, 1,
- "cairo_gl_surface_create",
- _cairo_boilerplate_wgl_create_surface,
- cairo_surface_create_similar,
- NULL, NULL,
- _cairo_boilerplate_get_image_surface,
- cairo_surface_write_to_png,
- _cairo_boilerplate_wgl_cleanup,
- _cairo_boilerplate_wgl_synchronize,
- NULL,
- TRUE, FALSE, FALSE
- },
- {
- "gl-dc", "gl", NULL, NULL,
- CAIRO_SURFACE_TYPE_GL, CAIRO_CONTENT_COLOR_ALPHA, 1,
- "cairo_gl_surface_create_for_dc",
- _cairo_boilerplate_wgl_for_create_window,
- NULL,
- _cairo_boilerplate_wgl_finish_window,
- _cairo_boilerplate_get_image_surface,
- cairo_surface_write_to_png,
- _cairo_boilerplate_wgl_cleanup,
- _cairo_boilerplate_wgl_synchronize,
- NULL,
- FALSE, FALSE, FALSE
- },
-};
-
-CAIRO_BOILERPLATE (wgl, targets)
diff --git a/boilerplate/cairo-boilerplate-win32-printing.c b/boilerplate/cairo-boilerplate-win32-printing.c
index 3d815167f..e8fcdcef5 100644
--- a/boilerplate/cairo-boilerplate-win32-printing.c
+++ b/boilerplate/cairo-boilerplate-win32-printing.c
@@ -26,14 +26,6 @@
* Adrian Johnson <ajohnson@redneon.com>
*/
-/* We require Windows 2000 features such as GetDefaultPrinter() */
-#if !defined(WINVER) || (WINVER < 0x0500)
-# define WINVER 0x0500
-#endif
-#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
-# define _WIN32_WINNT 0x0500
-#endif
-
#include "cairo-boilerplate-private.h"
#include "cairo-malloc-private.h"
diff --git a/boilerplate/meson.build b/boilerplate/meson.build
index 7f663c273..450eabf3e 100644
--- a/boilerplate/meson.build
+++ b/boilerplate/meson.build
@@ -13,10 +13,6 @@ cairo_boilerplate_feature_sources = {
'cairo-ps': ['cairo-boilerplate-ps.c'],
'cairo-svg': ['cairo-boilerplate-svg.c'],
'cairo-script': ['cairo-boilerplate-script.c'],
- # All tests crash with FPE
- # 'cairo-egl': ['cairo-boilerplate-egl.c'],
- # cairo-glx: ['cairo-boilerplate-glx.c'],
- 'cairo-wgl': ['cairo-boilerplate-wgl.c'],
}
foreach feature: built_features
diff --git a/build/.gitignore b/build/.gitignore
deleted file mode 100644
index 2f0183557..000000000
--- a/build/.gitignore
+++ /dev/null
@@ -1,16 +0,0 @@
-ar-lib
-compile
-config.guess
-config.sub
-depcomp
-install-sh
-ltmain.sh
-missing
-mkinstalldirs
-#Makefile.win32.features
-#Makefile.win32.features-h
-libtool.m4
-lt*.m4
-gtk-doc.m4
-test-driver
-
diff --git a/build/Makefile.am.analysis b/build/Makefile.am.analysis
deleted file mode 100644
index a44077ab4..000000000
--- a/build/Makefile.am.analysis
+++ /dev/null
@@ -1,37 +0,0 @@
-if CAIRO_HAS_LCOV
-# use recursive makes in order to ignore errors during check/perf
-lcov:
- -$(MAKE) $(AM_MAKEFLAGS) check
- $(MAKE) $(AM_MAKEFLAGS) genlcov
-lcov-perf:
- -$(MAKE) $(AM_MAKEFLAGS) perf
- $(MAKE) $(AM_MAKEFLAGS) genlcov
-
-# we have to massage the lcov.info file slightly to hide the effect of libtool
-# placing the objects files in the .libs/ directory separate from the *.c
-genlcov:
- $(LTP) --directory $(top_builddir) --path $(top_builddir) --capture --output-file cairo-lcov.info --test-name CAIRO_TEST --no-checksum
- $(SED) -e 's#.libs/##' \
- -e 's#boilerplate/src#src#' \
- -e 's#$(shell pwd)#$(shell cd $(top_srcdir) && pwd)#' \
- < cairo-lcov.info > cairo-lcov.info.tmp
- LANG=C $(LTP_GENHTML) --prefix $(top_builddir) --output-directory cairo-lcov --title "Cairo Code Coverage" --show-details cairo-lcov.info.tmp
- $(RM) cairo-lcov.info.tmp
-
-html-local: lcov
-else
-lcov lcov-perf genlcov:
- @echo You need to configure Cairo with support for gcov enabled.
- @echo e.g, ./configure --enable-gcov
-endif
-
-lcov-clean:
-if CAIRO_HAS_LCOV
- -$(LTP) --directory $(top_builddir) -z
-endif
- -$(RM) -r cairo-lcov.info cairo-lcov
- -$(FIND) -name '*.gcda' -print | $(XARGS) $(RM)
-
-distclean-local: lcov-clean
-
-.PHONY: lcov lcov-perf genlcov lcov-clean
diff --git a/build/Makefile.am.changelog b/build/Makefile.am.changelog
deleted file mode 100644
index 07e603695..000000000
--- a/build/Makefile.am.changelog
+++ /dev/null
@@ -1,82 +0,0 @@
-# Creating ChangeLog files from git log:
-
-# We always create a ChangeLog that contains the most recent changes, and
-# multiple others for changes between major releases (other than the last such
-# segment that we put in 'ChangeLog'. The old ones are named
-# ChangeLog.pre-X.Y where X.Y is the version number of the major release.
-
-CURR_CHANGELOG_VERSION=$(CAIRO_VERSION_MAJOR).$$(echo "($(CAIRO_VERSION_MINOR)+1)/2*2" | bc)
-# examines $version
-PREV_CHANGELOG_VERSION=$$(if test "x$$(echo "($$version-0.1)*2/2"|bc)" = "x$$(echo "$$version*2/2"|bc)"; \
- then echo "$$version-$$(echo "$$version" | sed 's/[0-9]/0/g;s/[0-9]$$/2/')"; \
- else echo "$$version-1.0"; \
- fi | bc | sed 's/[.]0*/./;s/^0[.]\?$$/initial/;s/[.]$$/.0/')
-
-CHANGELOGS = ChangeLog \
- `version=$(CURR_CHANGELOG_VERSION); \
- version=$(PREV_CHANGELOG_VERSION); \
- while test "x$$version" != xinitial; do \
- echo ChangeLog.pre-$$version; \
- version=$(PREV_CHANGELOG_VERSION); \
- done`
-
-MAINTAINERCLEANFILES += $(srcdir)/ChangeLog $(srcdir)/ChangeLog.pre-*
-DISTCLEANFILES += $(srcdir)/ChangeLog.cache-*
-
-changelogs:
- @$(MAKE) $(AM_MAKEFLAGS) $(CHANGELOGS)
-
-dist-hook: changelogs
- changelogs="$(CHANGELOGS)"; \
- for changelog in $$changelogs; do \
- cp $(srcdir)/$$changelog $(distdir)/ 2>/dev/null || \
- cp $$changelog $(distdir)/; \
- done
-
-$(srcdir)/ChangeLog:
- @if test -d "$(srcdir)/.git"; then \
- version=$(CURR_CHANGELOG_VERSION); \
- prev=$(PREV_CHANGELOG_VERSION).0; \
- nearest_tag=`git describe | sed 's/-.*//'`; \
- before=$(srcdir)/ChangeLog.cache-$$prev..$$nearest_tag; \
- after=$(srcdir)/ChangeLog.cache-$$nearest_tag..; \
- $(MAKE) $(AM_MAKEFLAGS) $$before $$after && \
- echo Creating $@ && \
- { echo '# Generated by configure. Do not edit.'; echo; \
- cat $$after; echo; cat $$before; } > $@; \
- else \
- test -f $@ || \
- (echo A git checkout is required to generate $@ >&2 && \
- echo A git checkout is required to generate this file >> $@); \
- fi
-
-DISTCLEANFILES += ChangeLog.cache-*
-
-ChangeLog.cache-*..: .git
-
-ChangeLog%: $(srcdir)/ChangeLog%
-
-$(srcdir)/ChangeLog.cache-% $(srcdir)/ChangeLog.pre-%:
- @echo Creating $@
- @if test -d "$(srcdir)/.git"; then \
- (cd "$(srcdir)" && \
- version=$$(echo "$@" | sed 's/.*ChangeLog\([.].*-\)\?//'); \
- if echo "$@" | grep -q '^ChangeLog[.]cache'; then \
- spec=$$version; \
- else \
- to=$$version; \
- test "x$$version" = x && version=$(CURR_CHANGELOG_VERSION); \
- from=$(PREV_CHANGELOG_VERSION); \
- test "x$$to" = x || to=$$to.0; \
- test "x$$from" = xinitial || from=$$from.0; \
- spec=$$from..$$to; \
- fi; \
- $(top_srcdir)/build/missing --run git log --stat "$$spec") > $@.tmp \
- && mv -f $@.tmp $@ \
- || ($(RM) $@.tmp; \
- echo Failed to generate $@, your $@ may be outdated >&2); \
- else \
- echo A git checkout is required to generate $@ >&2; \
- fi
-
-.PHONY: changelogs ChangeLog $(srcdir)/ChangeLog
diff --git a/build/Makefile.am.common b/build/Makefile.am.common
deleted file mode 100644
index b955af58f..000000000
--- a/build/Makefile.am.common
+++ /dev/null
@@ -1,14 +0,0 @@
-BUILT_SOURCES =
-CLEANFILES =
-DISTCLEANFILES =
-EXTRA_DIST =
-EXTRA_LTLIBRARIES =
-EXTRA_PROGRAMS =
-MAINTAINERCLEANFILES =
-TESTS =
-check_PROGRAMS =
-
-CLEANFILES += *.i *.s *.gch
-CLEANFILES += $(EXTRA_LTLIBRARIES) $(EXTRA_PROGRAMS) $(check_PROGRAMS)
-DISTCLEANFILES += $(BUILT_SOURCES)
-MAINTAINERCLEANFILES += Makefile.in
diff --git a/build/Makefile.am.gtk-doc b/build/Makefile.am.gtk-doc
deleted file mode 100644
index 56aa4957d..000000000
--- a/build/Makefile.am.gtk-doc
+++ /dev/null
@@ -1,173 +0,0 @@
-# BEFORE MODIFYING THIS FILE:
-#
-# This file is a descendant of an old copy of gtk-doc.make, modified for cairo minimally:
-#
-# - Moved to build/
-# - Made it append to EXTRA_DIST and CLEANFILES
-# - Instead of all-local, make "doc" build docs, and err if gtk-doc not enabled
-# - Some other changed introduced in 7f114b781f5c530d57530e5f76402e41cdabac6b
-#
-# Before changing it, check to see if a newer gtk-doc.make has fixed the issue you are facing.
-# From time to time, it would be nice to update this to the latest copy of gtk-doc.make, but
-# please do review all the differences and port our modifications forward.
-#
-
-# -*- mode: makefile -*-
-
-####################################
-# Everything below here is generic #
-####################################
-
-if GTK_DOC_USE_LIBTOOL
-GTKDOC_CC = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
-GTKDOC_LD = $(LIBTOOL) --tag=CC --mode=link $(CC) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS)
-else
-GTKDOC_CC = $(CC) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
-GTKDOC_LD = $(CC) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS)
-endif
-
-# We set GPATH here; this gives us semantics for GNU make
-# which are more like other make's VPATH, when it comes to
-# whether a source that is a target of one rule is then
-# searched for in VPATH/GPATH.
-#
-GPATH = $(srcdir)
-
-TARGET_DIR=$(HTML_DIR)/$(DOC_MODULE)
-
-EXTRA_DIST += \
- $(content_files) \
- $(HTML_IMAGES) \
- $(DOC_MAIN_SGML_FILE) \
- $(DOC_MODULE)-sections.txt \
- $(DOC_MODULE)-overrides.txt
-
-DOC_STAMPS=scan-build.stamp sgml-build.stamp html-build.stamp \
- $(srcdir)/sgml.stamp $(srcdir)/html.stamp
-
-SCANOBJ_FILES = \
- $(DOC_MODULE).args \
- $(DOC_MODULE).hierarchy \
- $(DOC_MODULE).interfaces \
- $(DOC_MODULE).prerequisites \
- $(DOC_MODULE).signals
-
-REPORT_FILES = \
- $(DOC_MODULE)-undocumented.txt \
- $(DOC_MODULE)-undeclared.txt \
- $(DOC_MODULE)-unused.txt
-
-CLEANFILES += $(SCANOBJ_FILES) $(REPORT_FILES) $(DOC_STAMPS)
-
-if ENABLE_GTK_DOC
-doc: html-build.stamp
-else
-doc:
- @echo "*** gtk-doc must be installed (and --enable-gtk-doc) in order to make doc"
- @false
-endif
-
-docs: html-build.stamp
-
-#### scan ####
-
-scan-build.stamp: $(HFILE_GLOB) $(CFILE_GLOB) $(EXTRA_HFILES)
- @echo 'gtk-doc: Scanning header files'
- @-chmod -R u+w $(srcdir)
- gtkdoc-scan --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --ignore-headers="$(IGNORE_HFILES)" $(SCAN_OPTIONS) $(EXTRA_HFILES) --output-dir=$(srcdir)
- if grep -l '^..*$$' $(srcdir)/$(DOC_MODULE).types > /dev/null 2>&1 ; then \
- CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" CFLAGS="$(GTKDOC_CFLAGS)" LDFLAGS="$(GTKDOC_LIBS)" gtkdoc-scangobj $(SCANGOBJ_OPTIONS) --module=$(DOC_MODULE) --output-dir=$(srcdir) ; \
- else \
- cd $(srcdir) ; \
- for i in $(SCANOBJ_FILES) ; do \
- test -f $$i || touch $$i ; \
- done \
- fi
- touch scan-build.stamp
-
-$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt: scan-build.stamp
- @true
-
-#### xml ####
-
-# gtkdoc-mkdb is broken and requires a --root-dir=$(srcdir) option
-# The _srcdir diversion is fragile but works for make check; make distcheck
-sgml-build.stamp: $(HFILE_GLOB) $(CFILE_GLOB) $(DOC_MODULE)-sections.txt $(expand_content_files)
- @echo 'gtk-doc: Building XML'
- @-chmod -R u+w $(srcdir)
- _srcdir="`pwd`/$(DOC_SOURCE_DIR)"; \
- cd $(srcdir) && gtkdoc-mkdb --module=$(DOC_MODULE) --source-dir=$$_srcdir --output-format=xml --expand-content-files="$(expand_content_files)" --main-sgml-file=$(DOC_MAIN_SGML_FILE) $(MKDB_OPTIONS)
- touch sgml-build.stamp
-
-sgml.stamp: sgml-build.stamp
- @true
-
-#### html ####
-
-html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files)
- @echo 'gtk-doc: Building HTML'
- @-chmod -R u+w $(srcdir)
- rm -rf $(srcdir)/html
- mkdir $(srcdir)/html
- cd $(srcdir)/html && gtkdoc-mkhtml $(DOC_MODULE) ../$(DOC_MAIN_SGML_FILE)
- test "x$(HTML_IMAGES)" = "x" || ( cd $(srcdir) && cp $(HTML_IMAGES) html )
- @echo 'gtk-doc: Fixing cross-references'
- cd $(srcdir) && gtkdoc-fixxref --module=$(DOC_MODULE) --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS)
- touch html-build.stamp
-
-##############
-
-clean-local:
- rm -f *~ *.bak
- rm -rf .libs
-
-distclean-local:
- cd $(srcdir) && \
- rm -rf xml $(REPORT_FILES) \
- $(DOC_MODULE)-decl-list.txt $(DOC_MODULE)-decl.txt
-
-maintainer-clean-local: clean
- cd $(srcdir) && rm -rf xml html
-
-install-data-local:
- -installfiles=`echo $(srcdir)/html/*`; \
- if test "$$installfiles" = '$(srcdir)/html/*'; \
- then echo '-- Nothing to install' ; \
- else \
- $(mkinstalldirs) $(DESTDIR)$(TARGET_DIR); \
- for i in $$installfiles; do \
- echo '-- Installing '$$i ; \
- $(INSTALL_DATA) $$i $(DESTDIR)$(TARGET_DIR); \
- done; \
- echo '-- Installing $(srcdir)/html/index.sgml' ; \
- $(INSTALL_DATA) $(srcdir)/html/index.sgml $(DESTDIR)$(TARGET_DIR) || :; \
- which gtkdoc-rebase >/dev/null && \
- gtkdoc-rebase --relative --dest-dir=$(DESTDIR) --html-dir=$(DESTDIR)$(TARGET_DIR) ; \
- fi
-
-
-uninstall-local:
- rm -f $(DESTDIR)$(TARGET_DIR)/*
-
-#
-# Require gtk-doc when making dist
-#
-if ENABLE_GTK_DOC
-dist-check-gtkdoc:
-else
-dist-check-gtkdoc:
- @echo "*** gtk-doc must be installed (and --enable-gtk-doc) in order to make dist"
- @false
-endif
-
-dist-hook: dist-check-gtkdoc dist-hook-local
- mkdir $(distdir)/xml
- mkdir $(distdir)/html
- -cp $(srcdir)/xml/*.xml $(distdir)/xml
- cp $(srcdir)/html/* $(distdir)/html
- -cp $(srcdir)/$(DOC_MODULE).types $(distdir)/
- -cp $(srcdir)/$(DOC_MODULE)-sections.txt $(distdir)/
- cd $(distdir) && rm -f $(DISTCLEANFILES)
- -gtkdoc-rebase --online --relative --html-dir=$(distdir)/html
-
-.PHONY : dist-hook-local docs
diff --git a/build/Makefile.am.releasing b/build/Makefile.am.releasing
deleted file mode 100644
index e985e983c..000000000
--- a/build/Makefile.am.releasing
+++ /dev/null
@@ -1,194 +0,0 @@
-# Some custom targets to make it easier to release things.
-#
-# To make real stable releases or devel snapshots, use either:
-# make release-check
-# or make release-publish
-#
-# To make a quick properly named (date and git hash stamped) tarball:
-# make snapshot
-
-
-TAR_OPTIONS = --owner=0 --group=0
-
-dist-hook: dist-clear-sticky-bits
-
-# Clean up any sticky bits we may inherit from parent dir
-dist-clear-sticky-bits:
- chmod -R a-s $(distdir)
-
-
-snapshot:
- distdir="$(distdir)-`date '+%Y%m%d'`"; \
- test -d "$(srcdir)/.git" && distdir=$$distdir-`cd "$(srcdir)" && git rev-parse HEAD | cut -c 1-6`; \
- TAR_OPTIONS="$(TAR_OPTIONS)" $(MAKE) $(AM_MAKEFLAGS) distdir="$$distdir" snapshot-dist
-
-snapshot-dist: dist
- @(echo "$(distdir) archives ready for distribution: "; \
- list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
- sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
-
-RELEASE_OR_SNAPSHOT = $$(if test "x$(CAIRO_VERSION_MINOR)" = "x$$(echo "$(CAIRO_VERSION_MINOR)/2*2" | bc)" ; then echo release; else echo snapshot; fi)
-RELEASE_UPLOAD_HOST = cairo.freedesktop.org
-RELEASE_UPLOAD_BASE = /srv/cairo.freedesktop.org/www
-RELEASE_UPLOAD_DIR = $(RELEASE_UPLOAD_BASE)/$(RELEASE_OR_SNAPSHOT)s
-RELEASE_URL_BASE = https://cairographics.org/$(RELEASE_OR_SNAPSHOT)s
-RELEASE_ANNOUNCE_LIST = cairo-announce@cairographics.org (and CC gnome-announce-list@gnome.org)
-
-MANUAL_VERSIONED = manual-$(VERSION)
-MANUAL_TAR_FILE = $(MANUAL_VERSIONED).tar.gz
-MANUAL_UPLOAD_DIR = $(RELEASE_UPLOAD_BASE)
-
-tar_file = $(PACKAGE)-$(VERSION).tar.xz
-sha1_file = $(tar_file).sha1
-gpg_file = $(sha1_file).asc
-
-$(sha1_file): $(tar_file)
- sha1sum $^ > $@
-
-$(gpg_file): $(sha1_file)
- @echo "Please enter your GPG password to sign the checksum."
- gpg --armor --sign $^
-
-release-verify-sane-changelogs: changelogs
- @echo -n "Checking that the ChangeLog files are sane..."
- @if grep -q "is required to generate" $(CHANGELOGS); then \
- (echo "Ouch." && echo "Some of the ChangeLogs are not generated correctly." \
- && echo "Remove ChangeLog* and make changelogs" \
- && false); else :; fi
- @echo "Good."
-
-release-verify-sane-tests:
- @echo "Checking that the test suite is sane..."
- @cd test && $(MAKE) $(AM_MAKEFLAGS) release-verify-sane-tests
-
-release-verify-even-micro:
- @echo -n "Checking that $(VERSION) has an even micro component..."
- @test "$(CAIRO_VERSION_MICRO)" = "`echo $(CAIRO_VERSION_MICRO)/2*2 | bc`" \
- || (echo "Ouch." && echo "The version micro component '$(CAIRO_VERSION_MICRO)' is not an even number." \
- && echo "The version in configure.in must be incremented before a new release." \
- && false)
- @echo "Good."
-
-release-verify-newer:
- @echo -n "Checking that no $(VERSION) release already exists..."
- @if curl --head --fail --silent "$(RELEASE_URL_BASE)/LATEST-$(PACKAGE)-$(VERSION)" >/dev/null; then \
- (echo "Ouch." && echo "Found: $(RELEASE_URL_BASE)/LATEST-$(PACKAGE)-$(VERSION)" \
- && echo "Are you sure you have an updated checkout?" \
- && echo "This should never happen." \
- && false); else :; fi
- @echo "Good."
-
-release-remove-old:
- $(RM) $(tar_file) $(sha1_file) $(gpg_file)
-
-
-# Strict ordering enforced for parallel make to work
-release-check: \
- release-verify-even-micro \
- release-verify-sane-changelogs \
- release-verify-sane-tests \
- release-verify-newer \
- $(NULL)
- $(MAKE) $(AM_MAKEFLAGS) release-remove-old
- TAR_OPTIONS="$(TAR_OPTIONS)" $(MAKE) $(AM_MAKEFLAGS) distcheck
-
-release-upload: $(tar_file) $(sha1_file) $(gpg_file)
- mkdir -p releases
- scp $(tar_file) $(sha1_file) $(gpg_file) $(RELEASE_UPLOAD_HOST):$(RELEASE_UPLOAD_DIR)
- mv $(tar_file) $(sha1_file) $(gpg_file) releases
- ssh $(RELEASE_UPLOAD_HOST) "rm -f $(RELEASE_UPLOAD_DIR)/LATEST-$(PACKAGE)-[0-9]* && ln -s $(tar_file) $(RELEASE_UPLOAD_DIR)/LATEST-$(PACKAGE)-$(VERSION)"
- git tag -s -m "cairo $(CAIRO_VERSION_MAJOR).$(CAIRO_VERSION_MINOR).$(CAIRO_VERSION_MICRO) release" $(CAIRO_VERSION_MAJOR).$(CAIRO_VERSION_MINOR).$(CAIRO_VERSION_MICRO)
-
-release-publish-message: releases/$(sha1_file)
- @echo "Please follow the instructions in RELEASING to push stuff out and"
- @echo "send out the announcement mails. Here is the excerpt you need:"
- @echo ""
- @echo "Subject: $(PACKAGE) $(RELEASE_OR_SNAPSHOT) $(VERSION) now available"
- @echo ""
- @echo "============================== CUT HERE =============================="
- @echo "A new $(PACKAGE) $(RELEASE_OR_SNAPSHOT) $(VERSION) is now available from:"
- @echo ""
- @echo " $(RELEASE_URL_BASE)/$(tar_file)"
- @echo ""
- @echo " which can be verified with:"
- @echo ""
- @echo " $(RELEASE_URL_BASE)/$(sha1_file)"
- @echo -n " "
- @cat releases/$(sha1_file)
- @echo ""
- @echo " $(RELEASE_URL_BASE)/$(gpg_file)"
- @echo " (signed by `getent passwd "$$USER" | cut -d: -f 5 | cut -d, -f 1`)"
- @echo ""
- @echo " Additionally, a git clone of the source tree:"
- @echo ""
- @echo " git clone git://git.cairographics.org/git/cairo"
- @echo ""
- @echo " will include a signed $(VERSION) tag which points to a commit named:"
- @echo " `git cat-file tag $(VERSION) | grep ^object | sed -e 's,object ,,'`"
- @echo ""
- @echo " which can be verified with:"
- @echo " git verify-tag $(VERSION)"
- @echo ""
- @echo " and can be checked out with a command such as:"
- @echo " git checkout -b build $(VERSION)"
- @echo ""
- @echo "============================== CUT HERE =============================="
-
-doc-publish-versioned: doc
- rm -rf ./$(MANUAL_VERSIONED)
- cp -a doc/public/html $(MANUAL_VERSIONED)
- tar czf $(MANUAL_TAR_FILE) $(MANUAL_VERSIONED)
- scp $(MANUAL_TAR_FILE) $(RELEASE_UPLOAD_HOST):$(MANUAL_UPLOAD_DIR)
- ssh $(RELEASE_UPLOAD_HOST) "cd $(MANUAL_UPLOAD_DIR) && tar xzf $(MANUAL_TAR_FILE) && ln -sf $(MANUAL_TAR_FILE) cairo-$(MANUAL_TAR_FILE)"
-
-doc-publish-symlinks:
- ssh $(RELEASE_UPLOAD_HOST) "cd $(MANUAL_UPLOAD_DIR) && rm -f manual && ln -s $(MANUAL_VERSIONED) manual && ln -sf $(MANUAL_TAR_FILE) cairo-manual.tar.gz"
-
-doc-publish:
- $(MAKE) $(AM_MAKEFLAGS) doc-publish-versioned
- @if test "$(RELEASE_OR_SNAPSHOT)" = release; then $(MAKE) $(AM_MAKEFLAGS) doc-publish-symlinks; fi
-
-# Strict ordering enforced for parallel make to work
-release-publish: release-check
- $(MAKE) $(AM_MAKEFLAGS) release-upload
- $(MAKE) $(AM_MAKEFLAGS) doc-publish
- $(MAKE) $(AM_MAKEFLAGS) release-publish-message
-
-if OS_WIN32
-
-# Win32 package zipfiles
-runtime_zip_file = $(PACKAGE)-$(VERSION).zip
-developer_zip_file = $(PACKAGE)-dev-$(VERSION).zip
-
-$(runtime_zip_file): install
- -$(RM) $@
- pwd=`pwd`; cd $(prefix); \
- zip "$$pwd"/$@ bin/libcairo-$(CAIRO_VERSION_SONUM).dll
-
-$(developer_zip_file): install
- -$(RM) $@
- pwd=`pwd`; cd $(prefix); \
- zip -r "$$pwd"/$@ include/cairo lib/libcairo.dll.a lib/cairo.lib lib/pkgconfig/cairo.pc lib/pkgconfig/cairo-*.pc share/gtk-doc/html/cairo
-
-zips: $(runtime_zip_file) $(developer_zip_file)
-
-endif
-
-
-.PHONY: \
- dist-clear-sticky-bits \
- doc-publish \
- doc-publish-symlinks \
- doc-publish-versioned \
- release-check \
- release-publish \
- release-publish-message \
- release-remove-old \
- release-upload \
- release-verify-even-micro \
- release-verify-newer \
- release-verify-sane-changelogs \
- release-verify-sane-tests \
- snapshot \
- snapshot-dist \
- $(NULL)
diff --git a/build/Makefile.win32.common b/build/Makefile.win32.common
deleted file mode 100644
index 7d7e9735f..000000000
--- a/build/Makefile.win32.common
+++ /dev/null
@@ -1,74 +0,0 @@
-default: all
-
-#
-# Edit build/Makefile.win32.features to enable features to build
-#
-include $(top_srcdir)/build/Makefile.win32.inform
-include $(top_srcdir)/build/Makefile.win32.features
-include $(top_srcdir)/build/Makefile.win32.features-h
-
-ifeq ($(top_builddir),)
-top_builddir = $(top_srcdir)
-endif
-
-CC := cl
-LD := link
-AR := lib
-
-ifeq ($(CFG),debug)
-CFG_CFLAGS := -MDd -Od -Zi
-CFG_LDFLAGS := -DEBUG
-else
-CFG_CFLAGS := -MD -O2
-CFG_LDFLAGS :=
-endif
-
-ifeq ($(PIXMAN_PATH),)
-PIXMAN_PATH := $(top_builddir)/../pixman
-endif
-PIXMAN_CFLAGS := -I$(PIXMAN_PATH)/pixman/
-PIXMAN_LIBS := $(PIXMAN_PATH)/pixman/$(CFG)/pixman-1.lib
-
-CAIRO_LIBS = gdi32.lib msimg32.lib user32.lib
-
-ifeq ($(CAIRO_HAS_PNG_FUNCTIONS),1)
-ifeq ($(LIBPNG_PATH),)
-LIBPNG_PATH := $(top_builddir)/../libpng
-endif
-LIBPNG_CFLAGS += -I$(LIBPNG_PATH)/
-CAIRO_LIBS += $(LIBPNG_PATH)/libpng.lib
-endif
-
-ifeq ($(CAIRO_HAS_PS_SURFACE)$(CAIRO_HAS_PDF_SURFACE),00)
-else
-ifeq ($(ZLIB_PATH),)
-ZLIB_PATH := $(top_builddir)/../zlib
-endif
-ZLIB_CFLAGS += -I$(ZLIB_PATH)/
-CAIRO_LIBS += $(ZLIB_PATH)/zdll.lib
-endif
-
-DEFAULT_CFLAGS = -nologo $(CFG_CFLAGS)
-DEFAULT_CFLAGS += -I. -I$(top_srcdir) -I$(top_srcdir)/src
-DEFAULT_CFLAGS += $(PIXMAN_CFLAGS) $(LIBPNG_CFLAGS) $(ZLIB_CFLAGS)
-
-CAIRO_CFLAGS = $(DEFAULT_CFLAGS) $(CFLAGS)
-
-DEFAULT_LDFLAGS = -nologo $(CFG_LDFLAGS)
-DEFAULT_ARFLAGS = -nologo
-
-CAIRO_LDFLAGS = $(DEFAULT_LDFLAGS) $(LDFLAGS)
-CAIRO_ARFLAGS = $(DEFAULT_ARFLAGS) $(LDFLAGS)
-
-# Some generic rules
-
-$(CFG)/%.obj: %.c $(top_srcdir)/src/cairo-features.h
- @mkdir -p $(CFG)/`dirname $<`
- @$(CC) $(CAIRO_CFLAGS) -c -Fo"$@" $<
-
-$(CFG)/%-static.obj: %.c $(top_srcdir)/src/cairo-features.h
- @mkdir -p $(CFG)/`dirname $<`
- @$(CC) $(CAIRO_CFLAGS) -c -DCAIRO_WIN32_STATIC_BUILD=1 -Fo"$@" $<
-
-clean:
- @rm -f $(CFG)/*.obj $(CFG)/*.dll $(CFG)/*.lib $(CFG)/*.pdb $(CFG)/*.ilk || exit 0
diff --git a/build/Makefile.win32.features b/build/Makefile.win32.features
deleted file mode 100644
index b2cc2e562..000000000
--- a/build/Makefile.win32.features
+++ /dev/null
@@ -1,33 +0,0 @@
-# Generated by configure. Modify to customize.
-
-CAIRO_HAS_XLIB_SURFACE=0
-CAIRO_HAS_XLIB_XRENDER_SURFACE=0
-CAIRO_HAS_XCB_SURFACE=0
-CAIRO_HAS_XLIB_XCB_FUNCTIONS=0
-CAIRO_HAS_XCB_SHM_FUNCTIONS=0
-CAIRO_HAS_QUARTZ_SURFACE=0
-CAIRO_HAS_QUARTZ_FONT=0
-CAIRO_HAS_QUARTZ_IMAGE_SURFACE=0
-CAIRO_HAS_WIN32_SURFACE=1
-CAIRO_HAS_WIN32_FONT=1
-CAIRO_HAS_PNG_FUNCTIONS=1
-CAIRO_HAS_GL_SURFACE=0
-CAIRO_HAS_GLESV2_SURFACE=0
-CAIRO_HAS_GLESV3_SURFACE=0
-CAIRO_HAS_EGL_FUNCTIONS=0
-CAIRO_HAS_GLX_FUNCTIONS=0
-CAIRO_HAS_WGL_FUNCTIONS=0
-CAIRO_HAS_SCRIPT_SURFACE=1
-CAIRO_HAS_FT_FONT=0
-CAIRO_HAS_FC_FONT=0
-CAIRO_HAS_PS_SURFACE=1
-CAIRO_HAS_PDF_SURFACE=1
-CAIRO_HAS_SVG_SURFACE=1
-CAIRO_HAS_TEST_SURFACES=0
-CAIRO_HAS_TEE_SURFACE=0
-CAIRO_HAS_XML_SURFACE=0
-CAIRO_HAS_PTHREAD=0
-CAIRO_HAS_GOBJECT_FUNCTIONS=0
-CAIRO_HAS_TRACE=0
-CAIRO_HAS_INTERPRETER=1
-CAIRO_HAS_SYMBOL_LOOKUP=0
diff --git a/build/Makefile.win32.features-h b/build/Makefile.win32.features-h
deleted file mode 100644
index 0211a01f8..000000000
--- a/build/Makefile.win32.features-h
+++ /dev/null
@@ -1,106 +0,0 @@
-# Generated by configure. Do not edit.
-
-$(top_srcdir)/src/cairo-features.h: $(top_srcdir)/build/Makefile.win32.features
- @echo "Generating src/cairo-features.h"
- @echo "/* Generated by Makefile.win32.features-h. Do not edit. */" > $(top_srcdir)/src/cairo-features.h
- @echo "#ifndef CAIRO_FEATURES_H" >> $(top_srcdir)/src/cairo-features.h
- @echo "#define CAIRO_FEATURES_H 1" >> $(top_srcdir)/src/cairo-features.h
-ifeq ($(CAIRO_HAS_XLIB_SURFACE),1)
- @echo "#define CAIRO_HAS_XLIB_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_XLIB_XRENDER_SURFACE),1)
- @echo "#define CAIRO_HAS_XLIB_XRENDER_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_XCB_SURFACE),1)
- @echo "#define CAIRO_HAS_XCB_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_XLIB_XCB_FUNCTIONS),1)
- @echo "#define CAIRO_HAS_XLIB_XCB_FUNCTIONS 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_XCB_SHM_FUNCTIONS),1)
- @echo "#define CAIRO_HAS_XCB_SHM_FUNCTIONS 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_QUARTZ_SURFACE),1)
- @echo "#define CAIRO_HAS_QUARTZ_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_QUARTZ_FONT),1)
- @echo "#define CAIRO_HAS_QUARTZ_FONT 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_QUARTZ_IMAGE_SURFACE),1)
- @echo "#define CAIRO_HAS_QUARTZ_IMAGE_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_WIN32_SURFACE),1)
- @echo "#define CAIRO_HAS_WIN32_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_WIN32_FONT),1)
- @echo "#define CAIRO_HAS_WIN32_FONT 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_PNG_FUNCTIONS),1)
- @echo "#define CAIRO_HAS_PNG_FUNCTIONS 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_GL_SURFACE),1)
- @echo "#define CAIRO_HAS_GL_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_GLESV2_SURFACE),1)
- @echo "#define CAIRO_HAS_GLESV2_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_GLESV3_SURFACE),1)
- @echo "#define CAIRO_HAS_GLESV3_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_EGL_FUNCTIONS),1)
- @echo "#define CAIRO_HAS_EGL_FUNCTIONS 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_GLX_FUNCTIONS),1)
- @echo "#define CAIRO_HAS_GLX_FUNCTIONS 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_WGL_FUNCTIONS),1)
- @echo "#define CAIRO_HAS_WGL_FUNCTIONS 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_SCRIPT_SURFACE),1)
- @echo "#define CAIRO_HAS_SCRIPT_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_FT_FONT),1)
- @echo "#define CAIRO_HAS_FT_FONT 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_FC_FONT),1)
- @echo "#define CAIRO_HAS_FC_FONT 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_PS_SURFACE),1)
- @echo "#define CAIRO_HAS_PS_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_PDF_SURFACE),1)
- @echo "#define CAIRO_HAS_PDF_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_SVG_SURFACE),1)
- @echo "#define CAIRO_HAS_SVG_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_TEST_SURFACES),1)
- @echo "#define CAIRO_HAS_TEST_SURFACES 1" >> $(top_srcdir)/src/cairo-features.h
-endif
- @echo "#define CAIRO_HAS_IMAGE_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
- @echo "#define CAIRO_HAS_MIME_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
- @echo "#define CAIRO_HAS_RECORDING_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
- @echo "#define CAIRO_HAS_OBSERVER_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
-ifeq ($(CAIRO_HAS_TEE_SURFACE),1)
- @echo "#define CAIRO_HAS_TEE_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_XML_SURFACE),1)
- @echo "#define CAIRO_HAS_XML_SURFACE 1" >> $(top_srcdir)/src/cairo-features.h
-endif
- @echo "#define CAIRO_HAS_USER_FONT 1" >> $(top_srcdir)/src/cairo-features.h
-ifeq ($(CAIRO_HAS_PTHREAD),1)
- @echo "#define CAIRO_HAS_PTHREAD 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_GOBJECT_FUNCTIONS),1)
- @echo "#define CAIRO_HAS_GOBJECT_FUNCTIONS 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_TRACE),1)
- @echo "#define CAIRO_HAS_TRACE 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_INTERPRETER),1)
- @echo "#define CAIRO_HAS_INTERPRETER 1" >> $(top_srcdir)/src/cairo-features.h
-endif
-ifeq ($(CAIRO_HAS_SYMBOL_LOOKUP),1)
- @echo "#define CAIRO_HAS_SYMBOL_LOOKUP 1" >> $(top_srcdir)/src/cairo-features.h
-endif
- @echo "#endif" >> $(top_srcdir)/src/cairo-features.h
diff --git a/build/Makefile.win32.inform b/build/Makefile.win32.inform
deleted file mode 100644
index ba1116505..000000000
--- a/build/Makefile.win32.inform
+++ /dev/null
@@ -1,13 +0,0 @@
-inform:
- @echo
-ifneq ($(CFG),release)
-ifneq ($(CFG),debug)
- @echo "Invalid configuration "$(CFG)" specified."
- @echo -n "You must specify a configuration when "
- @echo "running make, e.g. make CFG=debug"
- @echo
- @echo -n "Possible choices for configuration are "
- @echo "'release' and 'debug'"
- @exit 1
-endif
-endif
diff --git a/build/aclocal.cairo.m4 b/build/aclocal.cairo.m4
deleted file mode 100644
index 9fa8f5ca3..000000000
--- a/build/aclocal.cairo.m4
+++ /dev/null
@@ -1,228 +0,0 @@
-dnl ==========================================================================
-dnl
-dnl Cairo-specific macros
-dnl
-
-dnl ==========================================================================
-
-dnl Usage:
-dnl CAIRO_BIGENDIAN
-dnl
-AC_DEFUN([CAIRO_BIGENDIAN],
-[dnl
- case $host_os in
- darwin*)
- AH_VERBATIM([X_BYTE_ORDER],
-[
-/* Deal with multiple architecture compiles on Mac OS X */
-#ifdef __APPLE_CC__
-#ifdef __BIG_ENDIAN__
-#define WORDS_BIGENDIAN 1
-#define FLOAT_WORDS_BIGENDIAN 1
-#else
-#undef WORDS_BIGENDIAN
-#undef FLOAT_WORDS_BIGENDIAN
-#endif
-#endif
-])
- ;;
- *)
- AC_C_BIGENDIAN
- AX_C_FLOAT_WORDS_BIGENDIAN
- ;;
- esac
-])
-
-dnl CAIRO_CHECK_FUNCS_WITH_FLAGS(FUNCTION..., CFLAGS, LIBS
-dnl [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
-dnl Like AC_CHECK_FUNCS but with additional CFLAGS and LIBS
-dnl --------------------------------------------------------------------
-AC_DEFUN([CAIRO_CHECK_FUNCS_WITH_FLAGS],
-[dnl
- _save_cflags="$CFLAGS"
- _save_libs="$LIBS"
- CFLAGS="$CFLAGS $2"
- LIBS="$LIBS $3"
- AC_CHECK_FUNCS($1, $4, $5)
- CFLAGS="$_save_cflags"
- LIBS="$_save_libs"
-])
-
-dnl CAIRO_CONFIG_COMMANDS is like AC_CONFIG_COMMANDS, except that:
-dnl
-dnl 1) It redirects the stdout of the command to the file.
-dnl 2) It does not recreate the file if contents didn't change.
-dnl
-AC_DEFUN([CAIRO_CONFIG_COMMANDS],
-[dnl
- AC_CONFIG_COMMANDS($1,
- [
- _config_file=$1
- _tmp_file=cairoconf.tmp
- AC_MSG_NOTICE([creating $_config_file])
- {
- $2
- } >> "$_tmp_file" ||
- AC_MSG_ERROR([failed to write to $_tmp_file])
-
- if cmp -s "$_tmp_file" "$_config_file"; then
- AC_MSG_NOTICE([$_config_file is unchanged])
- rm -f "$_tmp_file"
- else
- mv "$_tmp_file" "$_config_file" ||
- AC_MSG_ERROR([failed to update $_config_file])
- fi
- ], $3)
-])
-
-dnl CAIRO_CC_TRY_LINK_WITH_ENV_SILENT(env-setup, program,
-dnl true-action, false-action)
-dnl
-dnl Compile and link the program with the given environment setup.
-dnl The global cairo_cc_flag is set to "yes" or "no" according as
-dnl the link succeeded or not. The link step must complete without
-dnl warnings or errors to stderr.
-dnl
-dnl Perform true-action on success and false-action on failure.
-dnl The values of CFLAGS, LIBS, LDFLAGS are saved before env-setup
-dnl is executed and restored right before the end of the macro.
-AC_DEFUN([CAIRO_CC_TRY_LINK_WITH_ENV_SILENT],[dnl
- # AC_LANG_PROGRAM() produces a main() w/o args,
- # but -Wold-style-definition doesn't like that.
- # We need _some_ program so that we don't get
- # warnings about empty compilation units, so always
- # append a reasonable main().
- _compile_program="$2"'
- int main(int c, char **v) { (void)c; (void)v; return 0; }'
-
- _save_cflags="$CFLAGS"
- _save_ldflags="$LDFLAGS"
- _save_libs="$LIBS"
- $1
- AC_LINK_IFELSE(
- [AC_LANG_SOURCE([[$_compile_program]])],
- [cairo_cc_stderr=`test -f conftest.err && cat conftest.err`
- cairo_cc_flag=yes],
- [cairo_cc_stderr=`test -f conftest.err && cat conftest.err`
- cairo_cc_flag=no])
-
- if test "x$cairo_cc_stderr" != "x"; then
- cairo_cc_flag=no
- fi
-
- if test "x$cairo_cc_flag" = "xyes"; then
- ifelse([$3], , :, [$3])
- else
- ifelse([$4], , :, [$4])
- fi
- CFLAGS="$_save_cflags"
- LDFLAGS="$_save_ldflags"
- LIBS="$_save_libs"
-])
-
-dnl check compiler flags with a program and no muttering.
-AC_DEFUN([CAIRO_CC_TRY_FLAG_SILENT],
-[dnl (flags..., optional program, true-action, false-action)
- CAIRO_CC_TRY_LINK_WITH_ENV_SILENT([CFLAGS="$CFLAGS $1"],
- [$2], [$3], [$4])
-])
-
-dnl find a -Werror equivalent
-AC_DEFUN([CAIRO_CC_CHECK_WERROR],
-[dnl
- _test_WERROR=${WERROR+set}
- if test "z$_test_WERROR" != zset; then
- WERROR=""
- for _werror in -Werror -errwarn; do
- AC_MSG_CHECKING([whether $CC supports $_werror])
- CAIRO_CC_TRY_FLAG_SILENT(
- [$_werror],,
- [WERROR="$WERROR $_werror"],
- [:])
- AC_MSG_RESULT($cairo_cc_flag)
- done
- fi
-])
-
-dnl check compiler flags possibly using -Werror if available.
-AC_DEFUN([CAIRO_CC_TRY_FLAG],
-[dnl (flags..., optional program, true-action, false-action)
- CAIRO_CC_CHECK_WERROR
- AC_MSG_CHECKING([whether $CC supports $1])
- CAIRO_CC_TRY_FLAG_SILENT([$WERROR $1], [$2], [$3], [$4])
- AC_MSG_RESULT([$cairo_cc_flag])
-])
-
-dnl Usage:
-dnl CAIRO_CHECK_NATIVE_ATOMIC_PRIMITIVES
-AC_DEFUN([CAIRO_CHECK_NATIVE_ATOMIC_PRIMITIVES],
-[dnl
- AC_CACHE_CHECK([for native atomic primitives], cairo_cv_atomic_primitives,
- [
- cairo_cv_atomic_primitives="none"
-
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[
-int atomic_add(int i) { return __sync_fetch_and_add (&i, 1); }
-int atomic_cmpxchg(int i, int j, int k) { return __sync_val_compare_and_swap (&i, j, k); }
-]], [[]])],
- [ cairo_cv_atomic_primitives="gcc-legacy" ], []
- )
-
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[
-int atomic_add(int i) { return __atomic_fetch_add(&i, 1, __ATOMIC_SEQ_CST); }
-int atomic_cmpxchg(int i, int j, int k) { return __atomic_compare_exchange_n(&i, &j, k, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }
-]], [[]])],
- [ cairo_cv_atomic_primitives="cxx11" ], []
- )
-
- if test "x$cairo_cv_atomic_primitives" = "xnone"; then
- AC_CHECK_HEADER([atomic_ops.h],
- cairo_cv_atomic_primitives="libatomic-ops")
- fi
-
- if test "x$cairo_cv_atomic_primitives" = "xnone"; then
- AC_CHECK_HEADER([libkern/OSAtomic.h],
- cairo_cv_atomic_primitives="OSAtomic")
- fi
- ])
- if test "x$cairo_cv_atomic_primitives" = xcxx11; then
- AC_DEFINE(HAVE_CXX11_ATOMIC_PRIMITIVES, 1,
- [Enable if your compiler supports the GCC __atomic_* atomic primitives])
- fi
-
- if test "x$cairo_cv_atomic_primitives" = xgcc-legacy; then
- AC_DEFINE(HAVE_GCC_LEGACY_ATOMICS, 1,
- [Enable if your compiler supports the legacy GCC __sync_* atomic primitives])
- fi
-
- if test "x$cairo_cv_atomic_primitives" = "xlibatomic-ops"; then
- AC_DEFINE(HAVE_LIB_ATOMIC_OPS, 1,
- [Enable if you have libatomic-ops-dev installed])
- fi
-
- if test "x$cairo_cv_atomic_primitives" = xOSAtomic; then
- AC_DEFINE(HAVE_OS_ATOMIC_OPS, 1,
- [Enable if you have MacOS X atomic operations])
- fi
-])
-
-dnl Usage:
-dnl CAIRO_CHECK_ATOMIC_OP_NEEDS_MEMORY_BARRIER
-AC_DEFUN([CAIRO_CHECK_ATOMIC_OP_NEEDS_MEMORY_BARRIER],
-[dnl
- AC_CACHE_CHECK([whether atomic ops require a memory barrier], cairo_cv_atomic_op_needs_memory_barrier,
- [
- case $host_cpu in
- i?86) cairo_cv_atomic_op_needs_memory_barrier="no" ;;
- x86_64) cairo_cv_atomic_op_needs_memory_barrier="no" ;;
- arm*) cairo_cv_atomic_op_needs_memory_barrier="yes" ;;
- *) cairo_cv_atomic_op_needs_memory_barrier="yes" ;;
- esac
- ])
- if test "x$cairo_cv_atomic_op_needs_memory_barrier" = "xyes"; then
- AC_DEFINE_UNQUOTED(ATOMIC_OP_NEEDS_MEMORY_BARRIER, 1,
- [whether memory barriers are needed around atomic operations])
- fi
-])
-
-AC_DEFUN([CAIRO_TEXT_WRAP], [m4_text_wrap([$1], [$2],, 78)])
diff --git a/build/aclocal.compare.m4 b/build/aclocal.compare.m4
deleted file mode 100644
index bd6c51b28..000000000
--- a/build/aclocal.compare.m4
+++ /dev/null
@@ -1,162 +0,0 @@
-dnl @synopsis AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
-dnl
-dnl This macro compares two version strings. It is used heavily in the
-dnl macro _AX_PATH_BDB for library checking. Due to the various number
-dnl of minor-version numbers that can exist, and the fact that string
-dnl comparisons are not compatible with numeric comparisons, this is
-dnl not necessarily trivial to do in a autoconf script. This macro
-dnl makes doing these comparisons easy.
-dnl
-dnl The six basic comparisons are available, as well as checking
-dnl equality limited to a certain number of minor-version levels.
-dnl
-dnl The operator OP determines what type of comparison to do, and can
-dnl be one of:
-dnl
-dnl eq - equal (test A == B)
-dnl ne - not equal (test A != B)
-dnl le - less than or equal (test A <= B)
-dnl ge - greater than or equal (test A >= B)
-dnl lt - less than (test A < B)
-dnl gt - greater than (test A > B)
-dnl
-dnl Additionally, the eq and ne operator can have a number after it to
-dnl limit the test to that number of minor versions.
-dnl
-dnl eq0 - equal up to the length of the shorter version
-dnl ne0 - not equal up to the length of the shorter version
-dnl eqN - equal up to N sub-version levels
-dnl neN - not equal up to N sub-version levels
-dnl
-dnl When the condition is true, shell commands ACTION-IF-TRUE are run,
-dnl otherwise shell commands ACTION-IF-FALSE are run. The environment
-dnl variable 'ax_compare_version' is always set to either 'true' or
-dnl 'false' as well.
-dnl
-dnl Examples:
-dnl
-dnl AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8])
-dnl AX_COMPARE_VERSION([3.15],[lt],[3.15.8])
-dnl
-dnl would both be true.
-dnl
-dnl AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8])
-dnl AX_COMPARE_VERSION([3.15],[gt],[3.15.8])
-dnl
-dnl would both be false.
-dnl
-dnl AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8])
-dnl
-dnl would be true because it is only comparing two minor versions.
-dnl
-dnl AX_COMPARE_VERSION([3.15.7],[eq0],[3.15])
-dnl
-dnl would be true because it is only comparing the lesser number of
-dnl minor versions of the two values.
-dnl
-dnl Note: The characters that separate the version numbers do not
-dnl matter. An empty string is the same as version 0. OP is evaluated
-dnl by autoconf, not configure, so must be a string, not a variable.
-dnl
-dnl The author would like to acknowledge Guido Draheim whose advice
-dnl about the m4_case and m4_ifvaln functions make this macro only
-dnl include the portions necessary to perform the specific comparison
-dnl specified by the OP argument in the final configure script.
-dnl
-dnl @category Misc
-dnl @author Tim Toolan <toolan@ele.uri.edu>
-dnl @version 2004-03-01
-dnl @license GPLWithACException
-
-dnl #########################################################################
-AC_DEFUN([AX_COMPARE_VERSION], [
- # Used to indicate true or false condition
- ax_compare_version=false
-
- # Convert the two version strings to be compared into a format that
- # allows a simple string comparison. The end result is that a version
- # string of the form 1.12.5-r617 will be converted to the form
- # 0001001200050617. In other words, each number is zero padded to four
- # digits, and non digits are removed.
- AS_VAR_PUSHDEF([A],[ax_compare_version_A])
- A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \
- -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \
- -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \
- -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \
- -e 's/[[^0-9]]//g'`
-
- AS_VAR_PUSHDEF([B],[ax_compare_version_B])
- B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \
- -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \
- -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \
- -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \
- -e 's/[[^0-9]]//g'`
-
- dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary
- dnl # then the first line is used to determine if the condition is true.
- dnl # The sed right after the echo is to remove any indented white space.
- m4_case(m4_tolower($2),
- [lt],[
- ax_compare_version=`echo "x$A
-x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"`
- ],
- [gt],[
- ax_compare_version=`echo "x$A
-x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"`
- ],
- [le],[
- ax_compare_version=`echo "x$A
-x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"`
- ],
- [ge],[
- ax_compare_version=`echo "x$A
-x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"`
- ],[
- dnl Split the operator from the subversion count if present.
- m4_bmatch(m4_substr($2,2),
- [0],[
- # A count of zero means use the length of the shorter version.
- # Determine the number of characters in A and B.
- ax_compare_version_len_A=`echo "$A" | awk '{print(length)}'`
- ax_compare_version_len_B=`echo "$B" | awk '{print(length)}'`
-
- # Set A to no more than B's length and B to no more than A's length.
- A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"`
- B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"`
- ],
- [[0-9]+],[
- # A count greater than zero means use only that many subversions
- A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"`
- B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"`
- ],
- [.+],[
- AC_WARNING(
- [illegal OP numeric parameter: $2])
- ],[])
-
- # Pad zeros at end of numbers to make same length.
- ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`"
- B="$B`echo $A | sed 's/./0/g'`"
- A="$ax_compare_version_tmp_A"
-
- # Check for equality or inequality as necessary.
- m4_case(m4_tolower(m4_substr($2,0,2)),
- [eq],[
- test "x$A" = "x$B" && ax_compare_version=true
- ],
- [ne],[
- test "x$A" != "x$B" && ax_compare_version=true
- ],[
- AC_WARNING([illegal OP parameter: $2])
- ])
- ])
-
- AS_VAR_POPDEF([A])dnl
- AS_VAR_POPDEF([B])dnl
-
- dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE.
- if test "$ax_compare_version" = "true" ; then
- m4_ifvaln([$4],[$4],[:])dnl
- m4_ifvaln([$5],[else $5])dnl
- fi
-]) dnl AX_COMPARE_VERSION
diff --git a/build/aclocal.enable.m4 b/build/aclocal.enable.m4
deleted file mode 100644
index f3522b983..000000000
--- a/build/aclocal.enable.m4
+++ /dev/null
@@ -1,409 +0,0 @@
-dnl
-dnl These are the facilities for enable/disabling various features,
-dnl and for collecting CFLAGS/LIBS and generating per feature .pc
-dnl files, assembling list of source files to compile, creating
-dnl cairo-features.h and other generated files, etc...
-dnl
-
-dnl ===========================================================================
-
-dnl
-dnl Define a macro to enable features
-dnl - Macro: _CAIRO_ENABLE (ID, NAME, WHAT, DEFAULT, COMMANDS)
-dnl
-dnl where:
-dnl
-dnl ID is the sub-namespace in function names, eg. "ft" for cairo_ft_...
-dnl NAME is the human-readable name of the feature, eg. "FreeType font"
-dnl WHAT is the type of feature:
-dnl "surface" for surface backends
-dnl "font" for font backends
-dnl "functions" for set of functions
-dnl "" for private configurations
-dnl DEFAULT is the default state of the feature:
-dnl "no" for experimental features, eg. your favorite new backend
-dnl "yes" for recommended features, eg. png functions
-dnl "auto" for other supported features, eg. xlib surface backend
-dnl "always" for mandatory features (can't be disabled), eg. image surface backend
-dnl COMMANDS are run to check whether the feature can be enabled.
-dnl They should set use_$(ID) to something other than yes if the
-dnl feature cannot be built, eg. "no (requires SomeThing)". It then
-dnl should also set $(ID)_REQUIRES/CFLAGS/LIBS/...
-dnl appropriately. Look at the macro definition for more details,
-dnl or ask if in doubt.
-dnl
-AC_DEFUN([_CAIRO_ENABLE],
-[dnl
- dnl Sanity check ID
- m4_if(
- [$1],
- m4_tolower(AS_TR_SH([$1])),
- ,
- [m4_fatal([invalid feature name `$1'])]
- )dnl
- m4_pushdef([cr_feature], [$1])dnl
- m4_pushdef([cr_feature_name], m4_normalize([$2]))dnl
- m4_pushdef([cr_feature_what], m4_normalize([$3]))dnl
- m4_pushdef([cr_feature_default], m4_normalize([$4]))dnl
- m4_pushdef([cr_feature_commands], [$5])dnl
- dnl
- m4_pushdef([cr_feature_arg], m4_translit([$1],_,-))dnl
- dnl
- dnl Sanity check default
- m4_case(
- cr_feature_default,
- [no],,
- [yes],,
- [auto],,
- [always],,
- [m4_fatal([Invalid default value `]cr_feature_default[' for feature `]cr_feature['])]
- )dnl
- dnl
- m4_if(cr_feature_default, [always],
- [dnl
- enable_$1=yes
- ],[dnl
- AC_ARG_ENABLE(cr_feature_arg,
- AS_HELP_STRING([--enable-]cr_feature_arg[=@<:@no/auto/yes@:>@],
- [Enable cairo's ]cr_feature_name[ feature @<:@default=]cr_feature_default[@:>@]),
- enable_$1=$enableval, enable_$1=cr_feature_default)
- ])dnl
- dnl
- AS_CASE([$enable_$1],
- [no],[dnl
- use_$1="no (disabled, use --enable-cr_feature_arg to enable)"
- ],dnl
- [yes|auto],[dnl
- AC_MSG_CHECKING([for cairo's ]cr_feature_name[ feature])
- echo
-
- use_[]$1=yes
- CAIRO_FEATURE_VARS_FOREACH(cr_var, [cr_feature[_]cr_var[=]_CAIRO_SH_ESCAPE_UNQUOTED(m4_do([cr_var_default_]cr_var[_value]))]m4_newline)
-
- cr_feature_commands
-
- AC_MSG_CHECKING([whether cairo's ]cr_feature_name[ feature could be enabled])
- AC_MSG_RESULT([$use_$1])
-
- AS_IF([test "x$enable_$1" = "xyes" -a "x$use_$1" != xyes],
- [dnl
- AC_MSG_ERROR(
- m4_case(cr_feature_default,
- [always], [mandatory],
- [yes], [recommended],
- , [requested]
- ) cr_feature_name[ feature could not be enabled])
- ])dnl
- ],dnl
- [dnl
- AC_MSG_ERROR([invalid argument passed to --enable-]cr_feature_arg[: `$use_$1', should be one of @<:@no/auto/yes@:>@])
- ])dnl
-
- AS_IF([test "x$use_$1" = "xyes"],
- [dnl
- CAIRO_ACCUMULATED_FEATURE_VARS_FOREACH([cr_var],
- [dnl
- CAIRO_ACCUMULATE_UNQUOTED_BEFORE(cr_var, [$]cr_feature[_]cr_var)
- ])dnl
- ],[dnl
- dnl If not enabled, empty the vars so no one accidentally uses them.
- CAIRO_FEATURE_VARS_FOREACH([cr_var], [unset cr_feature[_]cr_var]m4_newline)
- ])dnl
-
- _CAIRO_FEATURE_HOOKS(cr_feature, cr_feature_name, cr_feature_default, cr_feature_what)dnl
-
- m4_popdef([cr_feature])dnl
- m4_popdef([cr_feature_name])dnl
- m4_popdef([cr_feature_what])dnl
- m4_popdef([cr_feature_default])dnl
- m4_popdef([cr_feature_commands])dnl
- m4_popdef([cr_feature_arg])dnl
-])
-
-
-dnl ===========================================================================
-
-m4_define([_CAIRO_FEATURE_VARS])
-
-dnl
-dnl CAIRO_FEATURE_VARS_REGISTER(VARS, DEFAULT-VALUE=[])
-dnl
-dnl Registers variables to be collected from feature-enabling code segments.
-dnl VARS should be a whitespace-separate list of variable names.
-dnl
-dnl DEFAULT-VALUE is m4 macros to set default value of VARS
-dnl
-AC_DEFUN([CAIRO_FEATURE_VARS_REGISTER],
-[dnl
- m4_foreach_w([cr_var], [$1],
- [m4_append_uniq([_CAIRO_FEATURE_VARS], cr_var, [ ],,
- [m4_fatal([Feature variable `]cr_var[' already registered])])])dnl
- m4_foreach_w([cr_var], [$1],
- [dnl
- m4_define([cr_var_default_]cr_var[_value], m4_default([$2],[[$ac_env_[]]cr_feature[[]_]]cr_var[[_value]]))dnl
- ])dnl
-])
-
-dnl
-dnl CAIRO_FEATURE_VARS_FOREACH(VAR, COMMANDS)
-dnl
-dnl Run COMMANDS for each registered feature variable.
-dnl Defines VAR to the variable being processed.
-dnl
-AC_DEFUN([CAIRO_FEATURE_VARS_FOREACH],
-[dnl
- m4_foreach_w([$1], _CAIRO_FEATURE_VARS, [$2])dnl
-])
-
-
-dnl ===========================================================================
-
-m4_define([_CAIRO_ACCUMULATORS])dnl
-
-m4_define([_CAIRO_ACCUMULATORS_REGISTER],
-[dnl
- m4_foreach_w([cr_var], [$1],
- [m4_append_uniq([_CAIRO_ACCUMULATORS], cr_var, [ ],,
- [m4_fatal([Accumulator `]cr_var[' already registered])])])dnl
- m4_foreach_w([cr_var], [$1], [m4_define([cr_acc_]cr_var[_sep], [$2])])dnl
- m4_foreach_w([cr_var], [$1], [[CAIRO_]cr_var[=$3]]m4_newline)dnl
- m4_foreach_w([cr_var], [$1], [m4_pattern_allow([CAIRO_]cr_var)])dnl
-])dnl
-
-m4_define([_CAIRO_SH_ESCAPE],['m4_bpatsubst([$1],['],[\\'])'])dnl
-m4_define([_CAIRO_SH_ESCAPE_UNQUOTED],["m4_bpatsubst([$1],["],[\\"])"])dnl
-
-dnl
-dnl CAIRO_ACCUMULATORS_REGISTER(VARS, SEPARATOR=[], INITIAL-VALUE=[])
-dnl
-dnl Registers accumulators. An accumulator is a shell variable that can
-dnl be accumulated to. The macros take care of adding a SEPARATOR between
-dnl accumulated values.
-dnl
-dnl VARS should be a whitespace-separate list of variable names. The actual
-dnl shell variable resulting for each variable is prefixed with CAIRO_.
-dnl
-AC_DEFUN([CAIRO_ACCUMULATORS_REGISTER],
-[dnl
- _CAIRO_ACCUMULATORS_REGISTER([$1],[$2],_CAIRO_SH_ESCAPE([$3]))dnl
-])dnl
-
-dnl
-dnl Like CAIRO_ACCUMULATORS_REGISTER but INITIAL-VALUE is left unquoted,
-dnl so it can reference other shell variables for example.
-dnl
-AC_DEFUN([CAIRO_ACCUMULATORS_REGISTER_UNQUOTED],
-[dnl
- _CAIRO_ACCUMULATORS_REGISTER([$1],[$2],_CAIRO_SH_ESCAPE_UNQUOTED([$3]))dnl
-])dnl
-
-m4_define([_CAIRO_ACCUMULATOR_CHECK],
-[dnl
- m4_ifdef([cr_acc_$1_sep],,[m4_fatal([Accumulator `]$1[' not defined.])])dnl
-])dnl
-
-m4_define([_CAIRO_ACCUMULATE],
-[dnl
- _CAIRO_ACCUMULATOR_CHECK([$1])dnl
- m4_ifval([$2], [$3]m4_newline)dnl
-])dnl
-
-dnl
-dnl CAIRO_ACCUMULATE(VAR, VALUE)
-dnl
-dnl Appends VALUE to accumulator VAR
-dnl
-AC_DEFUN([CAIRO_ACCUMULATE],
-[dnl
- _CAIRO_ACCUMULATE([$1], [$2], [CAIRO_$1="${CAIRO_$1}]m4_do([cr_acc_$1_sep])["_CAIRO_SH_ESCAPE([$2])])dnl
-])dnl
-
-dnl
-dnl CAIRO_ACCUMULATE_BEFORE(VAR, VALUE)
-dnl
-dnl Prepends VALUE to accumulator VAR
-dnl
-AC_DEFUN([CAIRO_ACCUMULATE_BEFORE],
-[dnl
- _CAIRO_ACCUMULATE([$1], [$2], [CAIRO_$1=_CAIRO_SH_ESCAPE([$2])"]m4_do([cr_acc_$1_sep])[${CAIRO_$1}"])dnl
-])dnl
-
-m4_define([_CAIRO_ACCUMULATE_UNQUOTED],
-[dnl
- _CAIRO_ACCUMULATOR_CHECK([$1])dnl
- m4_ifval([$2], [m4_bmatch([$2],[[$]],[test -n "$2" &&]) $3]m4_newline)dnl
-])dnl
-
-dnl
-dnl CAIRO_ACCUMULATE_UNQUOTED(VAR, VALUE)
-dnl
-dnl Like CAIRO_ACCUMULATE but VALUE is left unquoted,
-dnl so it can reference other shell variables for example.
-dnl
-AC_DEFUN([CAIRO_ACCUMULATE_UNQUOTED],
-[dnl
- _CAIRO_ACCUMULATE_UNQUOTED([$1], [$2], [CAIRO_$1="${CAIRO_$1}]m4_do([cr_acc_$1_sep])["]_CAIRO_SH_ESCAPE_UNQUOTED([$2]))dnl
-])dnl
-
-dnl
-dnl CAIRO_ACCUMULATE_UNQUOTED_BEFORE(VAR, VALUE)
-dnl
-dnl Like CAIRO_ACCUMULATE_BEFORE but VALUE is left unquoted,
-dnl so it can reference other shell variables for example.
-dnl
-AC_DEFUN([CAIRO_ACCUMULATE_UNQUOTED_BEFORE],
-[dnl
- _CAIRO_ACCUMULATE_UNQUOTED([$1], [$2], [CAIRO_$1=]_CAIRO_SH_ESCAPE_UNQUOTED([$2])["]m4_do([cr_acc_$1_sep])[${CAIRO_$1}"])dnl
-])dnl
-
-dnl
-dnl CAIRO_ACCUMULATE_UNQUOTED_UNCHECKED(VAR, VALUE)
-dnl
-dnl Like CAIRO_ACCUMULATE_UNQUOTED but VALUE is not tested for emptiness.
-dnl
-AC_DEFUN([CAIRO_ACCUMULATE_UNQUOTED_UNCHECKED],
-[dnl
- _CAIRO_ACCUMULATE([$1], [$2], [CAIRO_$1="${CAIRO_$1}]m4_do([cr_acc_$1_sep])["]_CAIRO_SH_ESCAPE_UNQUOTED([$2]))dnl
-])dnl
-
-dnl
-dnl CAIRO_ACCUMULATE_UNQUOTED_UNCHECKED_BEFORE(VAR, VALUE)
-dnl
-dnl Like CAIRO_ACCUMULATE_UNQUOTED_BEFORE but VALUE is not tested for emptiness.
-dnl
-AC_DEFUN([CAIRO_ACCUMULATE_UNQUOTED_BEFORE],
-[dnl
- _CAIRO_ACCUMULATE([$1], [$2], [CAIRO_$1=]_CAIRO_SH_ESCAPE_UNQUOTED([$2])["]m4_do([cr_acc_$1_sep])[${CAIRO_$1}"])dnl
-])dnl
-
-dnl
-dnl CAIRO_ACCUMULATORS_FOREACH(VAR, COMMANDS)
-dnl
-dnl Run COMMANDS for each registered accumulator.
-dnl Defines VAR to the accumulator being processed.
-dnl
-AC_DEFUN([CAIRO_ACCUMULATORS_FOREACH],
-[dnl
- m4_foreach_w([$1], _CAIRO_ACCUMULATORS, [$2])dnl
-])dnl
-
-
-dnl ===========================================================================
-
-m4_define([_CAIRO_ACCUMULATED_FEATURE_VARS])dnl
-
-dnl
-dnl CAIRO_ACCUMULATED_FEATURE_VARS_REGISTER(VARS, DEFAULT-VALUE=[], SEPARATOR=[], INITIAL-VALUE=[])
-dnl
-dnl Defines VARS as feature variables and accumulators. Also accumulates
-dnl (prepending, not appending) feature values for VARS.
-dnl
-AC_DEFUN([CAIRO_ACCUMULATED_FEATURE_VARS_REGISTER],
-[dnl
- m4_foreach_w([cr_var], [$1],
- [m4_append_uniq([_CAIRO_ACCUMULATED_FEATURE_VARS], cr_var, [ ],,
- [m4_fatal([Accumulated feature variable `]cr_var[' already registered])])])dnl
- CAIRO_FEATURE_VARS_REGISTER([$1],[$2])dnl
- CAIRO_ACCUMULATORS_REGISTER_UNQUOTED([$1],[$3],[$4])dnl
-])dnl
-
-dnl
-dnl CAIRO_ACCUMULATED_FEATURE_VARS_FOREACH(VAR, COMMANDS)
-dnl
-dnl Run COMMANDS for each registered accumulated feature variable.
-dnl Defines VAR to the variable being processed.
-dnl
-AC_DEFUN([CAIRO_ACCUMULATED_FEATURE_VARS_FOREACH],
-[dnl
- m4_foreach_w([$1], _CAIRO_ACCUMULATED_FEATURE_VARS, [$2])dnl
-])dnl
-
-dnl ===========================================================================
-
-dnl
-dnl CAIRO_FEATURE_IF_ENABLED(FEATURE=cr_feature, COMMANDS)
-dnl
-dnl Run COMMANDS if FEATURE is enabled.
-dnl
-AC_DEFUN([CAIRO_FEATURE_IF_ENABLED],
-[dnl
- AS_IF([test "x$use_]m4_default([$1], cr_feature)[" = xyes], [$2], [$3])dnl
-])dnl
-
-m4_define([_CAIRO_FEATURE_HOOK_MATCH_SH_BOOL],
-[dnl
- m4_case([$1],
- [*], [$3],
- [no], [AS_IF([test "x$2" != xyes], [:m4_newline()$3])],
- [yes], [AS_IF([test "x$2" = xyes], [:m4_newline()$3])],
- [m4_fatal([Invalid ENABLED value `]$1['])])dnl
-])dnl
-
-m4_define([_CAIRO_FEATURE_HOOK_MATCH_M4],
-[dnl
- m4_case([$1],
- [*], [$3],
- [$2], [$3],
- [!$2], ,
- [m4_bmatch([$1], [^!], [$3])])dnl
-])dnl
-
-m4_define([_CAIRO_FEATURE_HOOKS])dnl
-
-dnl
-dnl CAIRO_FEATURE_HOOK_REGISTER(ENABLED, DEFAULT, WHAT, COMMANDS)
-dnl
-dnl ENABLED is the feature enabledness to match
-dnl DEFAULT is the default value of features to match
-dnl WHAT is the type of features to match
-dnl COMMANDS is commands to run for matched features.
-dnl
-dnl Runs COMMANDS for features matching ENABLED, DEFAULT, and WHAT.
-dnl Hooks are run for each feature in the order they are added.
-dnl
-dnl DEFAULT and WHAT are matched like this:
-dnl [*] matches all values
-dnl [val] matches [val]
-dnl [!val] matches anything other than [val]
-dnl
-dnl ENABLED is matched like this:
-dnl [yes] matches enabled features
-dnl [no] matches disabled features
-dnl [*] matches all features
-dnl
-dnl The following macros can be used in COMMANDS:
-dnl
-dnl cr_feature expands to the feature id, eg "ft"
-dnl cr_feature_name expands to the human-readable name of the feature, eg. "FreeType font"
-dnl cr_feature_default expands to the default state of the feature:
-dnl "no" for experimental features, eg. your favorite new backend
-dnl "yes" for recommended features, eg. png functions
-dnl "auto" for other supported features, eg. xlib surface backend
-dnl "always" for mandatory features (can't be disabled), eg. image surface backend
-dnl cr_what expands to the type of feature:
-dnl "surface" for surface backends
-dnl "font" for font backends
-dnl "functions" for set of functions
-dnl "" for private configurations
-dnl
-dnl These four values are also set as $1 to $4. To know if feature was
-dnl enabled from within COMMANDS, use CAIRO_FEATURE_IF_ENABLED:
-dnl
-dnl CAIRO_FEATURE_IF_ENABLED($1, [IF-ENABLED], [IF-DISABLED])
-dnl
-dnl or compare $use_$1 to string "yes". As in:
-dnl
-dnl AS_IF([test "x$use_$1" = "xyes"], [IF-ENABLED], [IF-DISABLED])
-dnl
-AC_DEFUN([CAIRO_FEATURE_HOOK_REGISTER],
-[dnl
- m4_append([_CAIRO_FEATURE_HOOKS],
- [dnl
- _CAIRO_FEATURE_HOOK_MATCH_M4([$2], cr_feature_default,
- [_CAIRO_FEATURE_HOOK_MATCH_M4([$3], cr_feature_what,
- [_CAIRO_FEATURE_HOOK_MATCH_SH_BOOL([$1], [$use_]cr_feature,
- [$4]
- )])])dnl
- ], m4_newline)dnl
-])dnl
-
diff --git a/build/aclocal.float.m4 b/build/aclocal.float.m4
deleted file mode 100644
index d9728c123..000000000
--- a/build/aclocal.float.m4
+++ /dev/null
@@ -1,68 +0,0 @@
-# AX_C_FLOAT_WORDS_BIGENDIAN ([ACTION-IF-TRUE], [ACTION-IF-FALSE],
-# [ACTION-IF-UNKNOWN])
-#
-# Checks the ordering of words within a multi-word float. This check
-# is necessary because on some systems (e.g. certain ARM systems), the
-# float word ordering can be different from the byte ordering. In a
-# multi-word float context, "big-endian" implies that the word containing
-# the sign bit is found in the memory location with the lowest address.
-# This implementation was inspired by the AC_C_BIGENDIAN macro in autoconf.
-# -------------------------------------------------------------------------
-AC_DEFUN([AX_C_FLOAT_WORDS_BIGENDIAN],
- [AC_CACHE_CHECK(whether float word ordering is bigendian,
- ax_cv_c_float_words_bigendian, [
-
-# The endianness is detected by first compiling C code that contains a special
-# double float value, then grepping the resulting object file for certain
-# strings of ascii values. The double is specially crafted to have a
-# binary representation that corresponds with a simple string. In this
-# implementation, the string "noonsees" was selected because the individual
-# word values ("noon" and "sees") are palindromes, thus making this test
-# byte-order agnostic. If grep finds the string "noonsees" in the object
-# file, the target platform stores float words in big-endian order. If grep
-# finds "seesnoon", float words are in little-endian order. If neither value
-# is found, the user is instructed to specify the ordering.
-
-ax_cv_c_float_words_bigendian=unknown
-AC_LINK_IFELSE([AC_LANG_SOURCE([[
-
-double d __attribute__((used)) = 90904234967036810337470478905505011476211692735615632014797120844053488865816695273723469097858056257517020191247487429516932130503560650002327564517570778480236724525140520121371739201496540132640109977779420565776568942592.0;
-int main() { return 0; }
-
-]])], [
-
-# allow users to override default 'strings' with 'llvm-strings'
-# or ${CHOST}-strings.
-AC_CHECK_TOOL(STRINGS, strings)
-if $STRINGS -a conftest$ac_exeext | grep noonsees >/dev/null ; then
- ax_cv_c_float_words_bigendian=yes
-fi
-if $STRINGS -a conftest$ac_exeext | grep seesnoon >/dev/null ; then
- if test "$ax_cv_c_float_words_bigendian" = unknown; then
- ax_cv_c_float_words_bigendian=no
- else
- ax_cv_c_float_words_bigendian=unknown
- fi
-fi
-
-])])
-
-case $ax_cv_c_float_words_bigendian in
- yes)
- m4_default([$1],
- [AC_DEFINE([FLOAT_WORDS_BIGENDIAN], 1,
- [Define to 1 if your system stores words within floats
- with the most significant word first])]) ;;
- no)
- $2 ;;
- *)
- m4_default([$3],
- [AC_MSG_ERROR([
-
-Unknown float word ordering. You need to manually preset
-ax_cv_c_float_words_bigendian=no (or yes) according to your system.
-
- ])]) ;;
-esac
-
-])# AX_C_FLOAT_WORDS_BIGENDIAN
diff --git a/build/aclocal.gtk-doc.m4 b/build/aclocal.gtk-doc.m4
deleted file mode 100644
index bfdfa1da6..000000000
--- a/build/aclocal.gtk-doc.m4
+++ /dev/null
@@ -1,39 +0,0 @@
-dnl -*- mode: autoconf -*-
-
-# serial 1
-
-dnl Usage:
-dnl GTK_DOC_CHECK([minimum-gtk-doc-version])
-AC_DEFUN([GTK_DOC_CHECK],
-[
- AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first
- AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first
- dnl for overriding the documentation installation directory
- AC_ARG_WITH([html-dir],
- AS_HELP_STRING([--with-html-dir=PATH], [path to installed docs]),,
- [with_html_dir='${datadir}/gtk-doc/html'])
- HTML_DIR="$with_html_dir"
- AC_SUBST([HTML_DIR])
-
- dnl enable/disable documentation building
- AC_ARG_ENABLE([gtk-doc],
- AS_HELP_STRING([--enable-gtk-doc],
- [use gtk-doc to build documentation [[default=no]]]),,
- [enable_gtk_doc=no])
-
- if test x$enable_gtk_doc = xyes; then
- ifelse([$1],[],
- [PKG_CHECK_EXISTS([gtk-doc],,
- AC_MSG_ERROR([gtk-doc not installed and --enable-gtk-doc requested]))],
- [PKG_CHECK_EXISTS([gtk-doc >= $1],,
- AC_MSG_ERROR([You need to have gtk-doc >= $1 installed to build gtk-doc]))])
- fi
-
- AC_MSG_CHECKING([whether to build gtk-doc documentation])
- AC_MSG_RESULT($enable_gtk_doc)
-
- AC_PATH_PROGS(GTKDOC_CHECK,gtkdoc-check,)
-
- AM_CONDITIONAL([ENABLE_GTK_DOC], [test x$enable_gtk_doc = xyes])
- AM_CONDITIONAL([GTK_DOC_USE_LIBTOOL], [test -n "$LIBTOOL"])
-])
diff --git a/build/aclocal.makefile.m4 b/build/aclocal.makefile.m4
deleted file mode 100644
index 70777810d..000000000
--- a/build/aclocal.makefile.m4
+++ /dev/null
@@ -1,234 +0,0 @@
-dnl
-dnl These are the facilities for generating Makefile.am.features and
-dnl Makefile.win32.features files.
-dnl
-
-dnl ===========================================================================
-
-dnl
-dnl Define cr_feature_tag ala other cr_feature_* macros
-dnl Expands to CAIRO_HAS_FEATURE_ID
-dnl
-m4_define([_CAIRO_BUILD_FEATURE_TAG_NORMALIZED],
- [CAIRO_HAS_[$1]m4_bmatch([$1],[$2$],,[$2])])dnl
-m4_define([_CAIRO_BUILD_FEATURE_TAG],
- [_CAIRO_BUILD_FEATURE_TAG_NORMALIZED(AS_TR_CPP([$1]),AS_TR_CPP(m4_ifval([$2],[ $2])))])dnl
-m4_define([cr_feature_tag],
- [_CAIRO_BUILD_FEATURE_TAG(cr_feature,cr_feature_what)])dnl
-
-
-dnl ===========================================================================
-dnl
-dnl CAIRO_INIT_MAKEFILES([AUX-DIR])
-dnl
-dnl Sets up automake and win32 conditionals for all features
-dnl
-AC_DEFUN([CAIRO_INIT_MAKEFILES],
-[dnl
- dnl Allow feature tags in the output
- m4_pattern_allow(^CAIRO_HAS_)dnl
-
- dnl Automake conditionals for non-builtin features
- CAIRO_FEATURE_HOOK_REGISTER(*,!always,*,
- [dnl
- AM_CONDITIONAL(cr_feature_tag, [test "x$use_]cr_feature[" = xyes])dnl
- ])dnl
-
- CAIRO_CONFIG_MAKEFILE_PRIVATE_WIN32([_],[$1],[],[[# Generated by configure. Modify to customize.]])dnl
- CAIRO_MAKEFILE_ACCUMULATE_FEATURE([_],*,!always,*,[cr_feature_tag=m4_if(cr_feature_default,[yes],1,[m4_bmatch(cr_feature,[win32],1,0)])])dnl
-])dnl
-
-dnl ===========================================================================
-
-m4_define([_CAIRO_MAKEFILES])dnl
-
-dnl
-dnl CAIRO_CONFIG_MAKEFILE(TAG, DIR, [SUFFIX], [HEADER])
-dnl
-dnl Create DIR/Makefile.{am,win32}.SUFFIX files
-dnl TAG is a TAG used by other CAIRO_MAKEFILE_* macros to append to these
-dnl Makefile's.
-dnl
-dnl HEADER is appended at the top of the Makefile's. If HEADER is not
-dnl set, the generic "Generated by configure. Do not edit." comment
-dnl is added.
-dnl
-AC_DEFUN([CAIRO_CONFIG_MAKEFILE],
-[dnl
- m4_append_uniq([_CAIRO_MAKEFILES], [$1], [ ])dnl
- CAIRO_CONFIG_MAKEFILE_PRIVATE([$1], [$2], [$3], [$4])dnl
-])dnl
-
-dnl Like CAIRO_CONFIG_MAKEFILE but only generate win32 makefile
-AC_DEFUN([CAIRO_CONFIG_MAKEFILE_WIN32],
-[dnl
- m4_append_uniq([_CAIRO_MAKEFILES], [$1], [ ])dnl
- CAIRO_CONFIG_MAKEFILE_PRIVATE_WIN32([$1], [$2], [$3], [$4])dnl
-])dnl
-
-dnl Like CAIRO_CONFIG_MAKEFILE but only generate automake makefile
-AC_DEFUN([CAIRO_CONFIG_MAKEFILE_AMAKE],
-[dnl
- m4_append_uniq([_CAIRO_MAKEFILES], [$1], [ ])dnl
- CAIRO_CONFIG_MAKEFILE_PRIVATE_AMAKE([$1], [$2], [$3], [$4])dnl
-])dnl
-
-dnl
-dnl CAIRO_CONFIG_MAKEFILE_PRIVATE(TAG, DIR, [SUFFIX], [HEADER])
-dnl
-dnl Like CAIRO_CONFIG_MAKEFILE but this makefile tag won't match
-dnl against '*' in makefile accumulators.
-dnl
-AC_DEFUN([CAIRO_CONFIG_MAKEFILE_PRIVATE],
-[dnl
- m4_ifdef([cr_make_$1_dir],
- [m4_fatal([Makefile `$1' already registered])])dnl
- m4_define([cr_make_$1_dir],[$2])dnl
-
- CAIRO_CONFIG_MAKEFILE_PRIVATE_AMAKE([$1], [$2], [$3], [$4])dnl
- CAIRO_CONFIG_MAKEFILE_PRIVATE_WIN32([$1], [$2], [$3], [$4])dnl
-])dnl
-
-dnl Like CAIRO_CONFIG_MAKEFILE_PRIVATE but only generate automake makefile
-AC_DEFUN([CAIRO_CONFIG_MAKEFILE_PRIVATE_AMAKE],
-[dnl
- m4_ifdef([cr_make_$1_dir_amake],
- [m4_fatal([Automake makefile `$1' already registered])])dnl
- m4_define([cr_make_$1_dir_amake],[$2])dnl
- m4_define([cr_make_$1_dir_any],[$2])dnl
-
- dnl Accumulators
- CAIRO_ACCUMULATORS_REGISTER(MAKEFILE_$1_AMAKE, m4_newline, m4_default([$4],[[# Generated by configure. Do not edit.]])m4_newline)dnl
-
- dnl Generate
- CAIRO_CONFIG_COMMANDS([$srcdir/]m4_if([$2],[.],,[$2/])[Makefile.am.]m4_default([$3],[features]),
- [echo "$CAIRO_MAKEFILE_$1_AMAKE"],
- [CAIRO_MAKEFILE_$1_AMAKE='$CAIRO_MAKEFILE_$1_AMAKE'])dnl
-])dnl
-
-dnl Like CAIRO_CONFIG_MAKEFILE_PRIVATE but only generate win32 makefile
-AC_DEFUN([CAIRO_CONFIG_MAKEFILE_PRIVATE_WIN32],
-[dnl
- m4_ifdef([cr_make_$1_dir_win32],
- [m4_fatal([Win32 makefile `$1' already registered])])dnl
- m4_define([cr_make_$1_dir_win32],[$2])dnl
- m4_define([cr_make_$1_dir_any],[$2])dnl
-
- dnl Accumulators
- CAIRO_ACCUMULATORS_REGISTER(MAKEFILE_$1_WIN32, m4_newline, m4_default([$4],[[# Generated by configure. Do not edit.]])m4_newline)dnl
-
- dnl Generate
- CAIRO_CONFIG_COMMANDS([$srcdir/]m4_if([$2],[.],,[$2/])[Makefile.win32.]m4_default([$3],[features]),
- [echo "$CAIRO_MAKEFILE_$1_WIN32"],
- [CAIRO_MAKEFILE_$1_WIN32='$CAIRO_MAKEFILE_$1_WIN32'])dnl
-])dnl
-
-
-m4_define([_CAIRO_MAKEFILE_CHECK],
-[dnl
- m4_ifdef([cr_make_$1_dir_any],,[m4_fatal([Makefile `]$1[' not defined.])])dnl
-])dnl
-
-
-dnl
-dnl CAIRO_MAKEFILE_INCLUDE(TAG, FILE)
-dnl
-dnl Include FILE from Makefile's for TAG. FILE should be placed
-dnl relative to directory for TAG. If TAG is *, FILE is included from
-dnl all Makefile's.
-dnl
-AC_DEFUN([CAIRO_MAKEFILE_INCLUDE],
-[dnl
- m4_if([$1],[*],,[_CAIRO_MAKEFILE_CHECK([$1])])dnl
- m4_foreach_w([cr_makefile], m4_if([$1],[*],_CAIRO_MAKEFILES,[$1]),
- [dnl
- m4_ifdef([cr_make_]cr_makefile[_dir_amake],dnl
- [CAIRO_ACCUMULATE([MAKEFILE_]cr_makefile[_AMAKE],[include $(top_srcdir)/cr_make_]cr_makefile[_dir_amake/$2]m4_newline)]
- )dnl
- m4_ifdef([cr_make_]cr_makefile[_dir_win32],dnl
- [CAIRO_ACCUMULATE([MAKEFILE_]cr_makefile[_WIN32],[ifeq ($(top_srcdir),)]m4_newline[include $2]m4_newline[else]m4_newline[include $(top_srcdir)/cr_make_]cr_makefile[_dir_win32/$2]m4_newline[endif]m4_newline)]
- )dnl
- ])dnl
-])dnl
-
-
-m4_pattern_allow([cr_make_tmp])
-
-dnl
-dnl CAIRO_MAKEFILE_ACCUMULATE(TAG, CONTENT)
-dnl
-dnl Accumulates CONTENT to Makefile's for TAG. If TAG is *,
-dnl CONTENT is added to all Makefile's.
-dnl
-AC_DEFUN([CAIRO_MAKEFILE_ACCUMULATE],
-[dnl
- m4_if([$1],[*],,[_CAIRO_MAKEFILE_CHECK([$1])])dnl
- m4_foreach_w([cr_makefile], m4_if([$1],[*],_CAIRO_MAKEFILES,[$1]),
- [dnl
- m4_pushdef([cr_make_acc_contents],[$2])dnl
- cr_make_tmp=_CAIRO_SH_ESCAPE(cr_make_acc_contents(cr_makefile))
- m4_popdef([cr_make_acc_contents])dnl
- m4_ifdef([cr_make_]cr_makefile[_dir_amake],dnl
- [CAIRO_ACCUMULATE_UNQUOTED_UNCHECKED([MAKEFILE_]cr_makefile[_AMAKE], [$cr_make_tmp])]
- )dnl
- m4_ifdef([cr_make_]cr_makefile[_dir_win32],dnl
- [CAIRO_ACCUMULATE_UNQUOTED_UNCHECKED([MAKEFILE_]cr_makefile[_WIN32], [$cr_make_tmp])]
- )dnl
- ])dnl
-])dnl
-
-m4_define([_CAIRO_MAKEFILE_ACCUMULATE_FEATURE],
-[dnl
- dnl Don't do a conditional for default=always features
- m4_pushdef([cr_mk_acc_feat_enabled],m4_if([$2],[yes],[m4_if(cr_feature_default,[always],[*],[$2])],[$2]))dnl
- m4_case(cr_mk_acc_feat_enabled,
- [*],,
- [yes], [CAIRO_ACCUMULATE([$1], [$3])],
- [no], [CAIRO_ACCUMULATE([$1], [$3]m4_newline[$4])],
- [m4_fatal([Invalid ENABLED value `]$2['])])dnl
- CAIRO_ACCUMULATE_UNQUOTED_UNCHECKED([$1], [$6])dnl
- m4_case(cr_mk_acc_feat_enabled,
- [*],,
- [yes], [CAIRO_ACCUMULATE([$1], [$5])],
- [no], [CAIRO_ACCUMULATE([$1], [$5])],
- [m4_fatal([Invalid ENABLED value `]$2['])])dnl
- m4_popdef([cr_mk_acc_feat_enabled])dnl
-])dnl
-
-dnl
-dnl CAIRO_MAKEFILE_ACCUMULATE_FEATURE(TAG, ENABLED, DEFAULT, WHAT, CONTENT)
-dnl
-dnl Accumulates CONTENT to Makefile's for TAG for each feature matching
-dnl ENABLED, DEFAULT, and WHAT. Those parameters are similar to those
-dnl passed to CAIRO_FEATURE_HOOK_REGISTER.
-dnl If TAG is *, CONTENT is added to all Makefile's.
-dnl
-AC_DEFUN([CAIRO_MAKEFILE_ACCUMULATE_FEATURE],
-[dnl
- m4_if([$1],[*],,[_CAIRO_MAKEFILE_CHECK([$1])])dnl
- m4_append([cr_make_acc_counter],[1],[])dnl
- m4_define([cr_make_acc_contents]m4_len(cr_make_acc_counter), [$5])dnl
- CAIRO_FEATURE_HOOK_REGISTER(*,[$3],[$4],
- [dnl
- m4_foreach_w([cr_makefile], m4_if([$1],[*],_CAIRO_MAKEFILES,[$1]),
- [dnl
- cr_make_tmp=_CAIRO_SH_ESCAPE(cr_make_acc_contents]]m4_len(cr_make_acc_counter)([[cr_makefile,]][$][1],[$][2],[$][3],[$][4])[[)
- m4_ifdef([cr_make_]cr_makefile[_dir_amake],
- [_CAIRO_MAKEFILE_ACCUMULATE_FEATURE(
- [MAKEFILE_]cr_makefile[_AMAKE],
- [$2],
- [if ]cr_feature_tag, [else], [endif],
- [$cr_make_tmp])
- ])dnl
- m4_ifdef([cr_make_]cr_makefile[_dir_win32],
- [_CAIRO_MAKEFILE_ACCUMULATE_FEATURE(
- [MAKEFILE_]cr_makefile[_WIN32],
- [$2],
- [ifeq ($(]cr_feature_tag[),1)], [else], [endif],
- [$cr_make_tmp])dnl
- ])dnl
- ])dnl
- ])dnl
-])dnl
-
-m4_define([cr_make_acc_counter])dnl
diff --git a/build/aclocal.pkg.m4 b/build/aclocal.pkg.m4
deleted file mode 100644
index 8b9fda909..000000000
--- a/build/aclocal.pkg.m4
+++ /dev/null
@@ -1,157 +0,0 @@
-# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
-#
-# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# PKG_PROG_PKG_CONFIG([MIN-VERSION])
-# ----------------------------------
-AC_DEFUN([PKG_PROG_PKG_CONFIG],
-[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
-m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
-AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl
-if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
- AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
-fi
-if test -n "$PKG_CONFIG"; then
- _pkg_min_version=m4_default([$1], [0.9.0])
- AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
- if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- PKG_CONFIG=""
- fi
-
-fi[]dnl
-])# PKG_PROG_PKG_CONFIG
-
-# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
-#
-# Check to see whether a particular set of modules exists. Similar
-# to PKG_CHECK_MODULES(), but does not set variables or print errors.
-#
-#
-# Similar to PKG_CHECK_MODULES, make sure that the first instance of
-# this or PKG_CHECK_MODULES is called, or make sure to call
-# PKG_CHECK_EXISTS manually
-# --------------------------------------------------------------
-AC_DEFUN([PKG_CHECK_EXISTS],
-[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
-if test -n "$PKG_CONFIG" && \
- AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
- m4_ifval([$2], [$2], [:])
-m4_ifvaln([$3], [else
- $3])dnl
-fi])
-
-
-# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
-# ---------------------------------------------
-m4_define([_PKG_CONFIG],
-[if test -n "$$1"; then
- pkg_cv_[]$1="$$1"
- elif test -n "$PKG_CONFIG"; then
- PKG_CHECK_EXISTS([$3],
- [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
- [pkg_failed=yes])
- else
- pkg_failed=untried
-fi[]dnl
-])# _PKG_CONFIG
-
-# _PKG_SHORT_ERRORS_SUPPORTED
-# -----------------------------
-AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
-[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
- _pkg_short_errors_supported=yes
-else
- _pkg_short_errors_supported=no
-fi[]dnl
-])# _PKG_SHORT_ERRORS_SUPPORTED
-
-
-# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
-# [ACTION-IF-NOT-FOUND])
-#
-# ACTION-IF-NOT-FOUND is not allowed to be empty, that trigger PKG_CONFIG_PATH error message.
-# Use : or set a dummy variable to avoid that behavior.
-#
-# Note that if there is a possibility the first call to
-# PKG_CHECK_MODULES might not happen, you should be sure to include an
-# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
-#
-#
-# --------------------------------------------------------------
-AC_DEFUN([PKG_CHECK_MODULES],
-[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
-AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
-AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
-
-pkg_failed=no
-AC_MSG_CHECKING([for $1])
-
-_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
-_PKG_CONFIG([$1][_LIBS], [libs], [$2])
-
-m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
-and $1[]_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details.])
-
-if test $pkg_failed = yes; then
- _PKG_SHORT_ERRORS_SUPPORTED
- if test $_pkg_short_errors_supported = yes; then
- $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "$2" 2>&1`
- else
- $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors "$2" 2>&1`
- fi
- # Put the nasty error message in config.log where it belongs
- echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
-
- ifelse([$4], , [AC_MSG_ERROR(dnl
-[Package requirements ($2) were not met:
-
-$$1_PKG_ERRORS
-
-Consider adjusting the PKG_CONFIG_PATH environment variable if you
-installed software in a non-standard prefix.
-
-_PKG_TEXT
-])],
- [AC_MSG_RESULT([no])
- $4])
-elif test $pkg_failed = untried; then
- ifelse([$4], , [AC_MSG_FAILURE(dnl
-[The pkg-config script could not be found or is too old. Make sure it
-is in your PATH or set the PKG_CONFIG environment variable to the full
-path to pkg-config.
-
-_PKG_TEXT
-
-To get pkg-config, see <https://pkg-config.freedesktop.org/>.])],
- [$4])
-else
- $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
- $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
- AC_MSG_RESULT([yes])
- ifelse([$3], , :, [$3])
-fi[]dnl
-])# PKG_CHECK_MODULES
diff --git a/build/configure.ac.analysis b/build/configure.ac.analysis
deleted file mode 100644
index 11c52e70d..000000000
--- a/build/configure.ac.analysis
+++ /dev/null
@@ -1,106 +0,0 @@
-dnl ===========================================================================
-dnl
-dnl LCOV
-dnl
-cairo_has_lcov=no
-AC_ARG_ENABLE(gcov,
- AS_HELP_STRING([--enable-gcov],
- [Enable gcov]),
- [use_gcov=$enableval], [use_gcov=no])
-
-if test "x$use_gcov" = "xyes"; then
- dnl we need gcc:
- if test "$GCC" != "yes"; then
- AC_MSG_ERROR([GCC is required for --enable-gcov])
- fi
-
- dnl Check if ccache is being used
- AC_CHECK_PROG(SHTOOL, shtool, shtool)
- case `$SHTOOL path $CC` in
- *ccache*[)] gcc_ccache=yes;;
- *[)] gcc_ccache=no;;
- esac
-
- if test "$gcc_ccache" = "yes" && (test -z "$CCACHE_DISABLE" || test "$CCACHE_DISABLE" != "1"); then
- AC_MSG_ERROR([ccache must be disabled when --enable-gcov option is used. You can disable ccache by setting environment variable CCACHE_DISABLE=1.])
- fi
-
- ltp_version_list="1.7 1.6 1.5 1.4"
- AC_CHECK_PROG(LTP, lcov, lcov)
- AC_CHECK_PROG(LTP_GENHTML, genhtml, genhtml)
-
- if test "$LTP"; then
- AC_CACHE_CHECK([for ltp version], cairo_cv_ltp_version, [
- cairo_cv_ltp_version=invalid
- ltp_version=`$LTP -v 2>/dev/null | $SED -e 's/^.* //'`
- for ltp_check_version in $ltp_version_list; do
- if test "$ltp_version" = "$ltp_check_version"; then
- cairo_cv_ltp_version="$ltp_check_version (ok)"
- fi
- done
- ])
- fi
-
- case $cairo_cv_ltp_version in
- ""|invalid[)]
- ;;
- *)
- cairo_has_lcov=yes
- ;;
- esac
-
- if test "x$cairo_has_lcov" != "xyes"; then
- AC_MSG_ERROR([[To enable code coverage reporting you must have one of the following LTP versions installed: $ltp_version_list.
-Please install the Linux Test Project [http://ltp.sourceforge.net/], and try again.]])
- fi
-
- if test -z "$LTP_GENHTML"; then
- AC_MSG_ERROR([[Could not find genhtml from the LTP package.
-Please install the Linux Test Project [http://ltp.sourceforge.net/], and try again.]])
- fi
-
- AC_DEFINE(HAVE_GCOV, 1, [Whether you have gcov])
-dnl PHP_ADD_MAKEFILE_FRAGMENT($abs_srcdir/Makefile.gcov, $abs_srcdir)
-
- dnl Remove all optimization flags from CFLAGS
- changequote({,})
- CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9]*//g'`
- CAIRO_CFLAGS=`echo "$CAIRO_CFLAGS" | $SED -e 's/-O[0-9]*//g'`
- changequote([,])
-
- dnl Add the special gcc flags
- dnl In order to workaround a debian bug in libtool where they strip
- dnl $dependency_libs from the link line and CFLAGS, we need to pass
- dnl --coverage via LDFLAGS.
- CAIRO_CC_TRY_FLAG([--coverage],,
- [
- CAIRO_CFLAGS="$CAIRO_CFLAGS -O0 --coverage"
- CAIRO_LDFLAGS="$CAIRO_LDFLAGS -O0 --coverage"
- ])
-fi
-AM_CONDITIONAL(CAIRO_HAS_LCOV, test "x$cairo_has_lcov" = "xyes")
-
-dnl ===========================================================================
-dnl Check for some custom valgrind modules
-AC_ARG_ENABLE(valgrind,
- AS_HELP_STRING([--disable-valgrind],
- [Disable valgrind support]),
- [use_valgrind=$enableval], [use_valgrind=yes])
-
-if test "x$use_valgrind" = "xyes"; then
- PKG_CHECK_MODULES(VALGRIND, valgrind, [
- _save_CFLAGS="$CFLAGS"
- _save_CPPFLAGS="$CPPFLAGS"
- CFLAGS="$CFLAGS $VALGRIND_CFLAGS"
- CPPFLAGS="$CPPFLAGS $VALGRIND_CFLAGS"
- AC_CHECK_HEADER([valgrind.h], [AC_DEFINE([HAVE_VALGRIND], [1],
- [Define to 1 if you have Valgrind])])
- AC_CHECK_HEADER([lockdep.h], [AC_DEFINE([HAVE_LOCKDEP], [1],
- [Define to 1 if you have the Valgrind lockdep tool])])
- AC_CHECK_HEADER([memfault.h], [AC_DEFINE([HAVE_MEMFAULT], [1],
- [Define to 1 if you have the Valgrind memfault tool])])
- CAIRO_CFLAGS="$VALGRIND_CFLAGS $CAIRO_CFLAGS"
- CFLAGS="$_save_CFLAGS"
- CPPFLAGS="$_save_CPPFLAGS"
- ], AC_MSG_RESULT(no))
-fi
diff --git a/build/configure.ac.features b/build/configure.ac.features
deleted file mode 100644
index 14573143a..000000000
--- a/build/configure.ac.features
+++ /dev/null
@@ -1,416 +0,0 @@
-
-dnl
-dnl Define macros to enable various features.
-dnl - Macro: CAIRO_ENABLE_* (ID, NAME, DEFAULT, COMMANDS)
-dnl
-dnl where:
-dnl
-dnl ID is the feature id, eg. "ft" for cairo_ft_...
-dnl NAME is the human-readable name of the feature, eg. "FreeType"
-dnl DEFAULT is the default state of the feature:
-dnl "no" for experimental backends, eg. your favorite new backend
-dnl "yes" for mandatory backends, eg. png
-dnl "auto" for other supported backends, eg. xlib
-dnl COMMANDS are run to check whether the feature can be enabled. Their
-dnl result may be cached, so user should not count on them being run.
-dnl They should set use_$(ID) to something other than yes if the
-dnl feature cannot be built, eg. "no (requires SomeThing)". It then
-dnl should also set $(ID)_REQUIRES/CFLAGS/LIBS/...
-dnl appropriately. Look at the macro definition for more details,
-dnl or ask if in doubt.
-dnl
-
-AC_DEFUN([CAIRO_ENABLE],
- [_CAIRO_ENABLE([$1], [$2], , [$3],[$4])])dnl
-
-AC_DEFUN([CAIRO_ENABLE_SURFACE_BACKEND],
- [_CAIRO_ENABLE([$1], [$2 surface backend], surface, [$3],[$4])])dnl
-
-AC_DEFUN([CAIRO_ENABLE_FONT_BACKEND],
- [_CAIRO_ENABLE([$1], [$2 font backend], font, [$3],[$4])])dnl
-
-AC_DEFUN([CAIRO_ENABLE_FUNCTIONS],
- [_CAIRO_ENABLE([$1], [$2 functions], functions, [$3],[$4])])dnl
-
-
-dnl
-dnl Define cr_feature_pc and friends ala other cr_feature_* macros
-dnl
-m4_define([cr_pc_modname],
- [[cairo-]m4_translit([$1],_,-)])dnl
-m4_define([cr_feature_pc],
- [cr_pc_modname(cr_feature)[.pc]])dnl
-m4_define([cr_feature_uninstalled_pc],
- [cr_pc_modname(cr_feature)[-uninstalled.pc]])dnl
-
-
-dnl ===========================================================================
-dnl
-dnl Hooks
-dnl
-dnl ===========================================================================
-
-
-dnl ===========================================================================
-dnl
-dnl Generate {src,boilerplate}/Makefile.{am,win32}.config
-dnl
-
-CAIRO_INIT_MAKEFILES([build])
-CAIRO_CONFIG_MAKEFILE([cairo], [src])dnl
-CAIRO_CONFIG_MAKEFILE([cairo_boilerplate], [boilerplate])dnl
-CAIRO_MAKEFILE_INCLUDE(*,[Makefile.sources])dnl
-dnl An empty line per feature for readability
-CAIRO_MAKEFILE_ACCUMULATE_FEATURE(*,*,*,*,[])dnl
-
-
-dnl Collect list of all supported public headers
-CAIRO_MAKEFILE_ACCUMULATE(*,
-[supported_$1_headers = $($1_headers)]dnl
-)dnl
-CAIRO_MAKEFILE_ACCUMULATE_FEATURE(*,*,!no,!,
-[supported_$1_headers += $($1_$2_headers)]dnl
-)dnl
-
-dnl Collect list of all unsupported public headers
-CAIRO_MAKEFILE_ACCUMULATE(*,
-[unsupported_$1_headers =]dnl
-)dnl
-CAIRO_MAKEFILE_ACCUMULATE_FEATURE(*,*,no,!,
-[unsupported_$1_headers += $($1_$2_headers)]dnl
-)dnl
-
-dnl Collect list of source files for all public features
-CAIRO_MAKEFILE_ACCUMULATE(*,
-[dnl
-all_$1_headers = $($1_headers)
-all_$1_private = $($1_private)
-all_$1_sources = $($1_sources)
-])dnl
-CAIRO_MAKEFILE_ACCUMULATE_FEATURE(*,*,*,!,
-[dnl
-all_$1_headers += $($1_$2_headers)
-all_$1_private += $($1_$2_private)
-all_$1_sources += $($1_$2_sources)]dnl
-)dnl
-
-dnl Collect list of source files for enabled public features
-CAIRO_MAKEFILE_ACCUMULATE(*,
-[dnl
-enabled_$1_headers = $($1_headers)
-enabled_$1_private = $($1_private)
-enabled_$1_sources = $($1_sources)
-])dnl
-CAIRO_MAKEFILE_ACCUMULATE_FEATURE(*,yes,*,!,
-[dnl
-enabled_$1_headers += $($1_$2_headers)
-enabled_$1_private += $($1_$2_private)
-enabled_$1_sources += $($1_$2_sources)]dnl
-)dnl
-
-dnl No public headers for private features
-
-dnl Collect list of source files for all private features
-CAIRO_MAKEFILE_ACCUMULATE_FEATURE(*,*,*,,
-[dnl
-all_$1_private += $($1_$2_private) $($1_$2_headers)
-all_$1_sources += $($1_$2_sources)]dnl
-)dnl
-
-dnl Collect list of source files for enabled private features
-CAIRO_MAKEFILE_ACCUMULATE_FEATURE(*,yes,*,,
-[dnl
-enabled_$1_private += $($1_$2_private) $($1_$2_headers)
-enabled_$1_sources += $($1_$2_sources)]dnl
-)dnl
-
-
-dnl ===========================================================================
-dnl
-dnl Generate .pc files
-dnl
-
-dnl All .pc files are generated automatically except for these
-AC_CONFIG_FILES([src/cairo.pc])dnl
-AC_CONFIG_FILES([cairo-uninstalled.pc:src/cairo-uninstalled.pc.in])dnl
-AC_CONFIG_FILES([util/cairo-script/cairo-script-interpreter.pc])dnl
-AC_CONFIG_FILES([util/cairo-script/cairo-script-interpreter-uninstalled.pc:util/cairo-script/cairo-script-interpreter-uninstalled.pc.in])dnl
-
-dnl pkg-config requires, non-pkgconfig cflags and libs, and total cflags and libs
-CAIRO_FEATURE_VARS_REGISTER([BASE],[cairo])dnl
-CAIRO_ACCUMULATED_FEATURE_VARS_REGISTER([REQUIRES],,[ ])dnl
-CAIRO_ACCUMULATED_FEATURE_VARS_REGISTER([CFLAGS NONPKGCONFIG_CFLAGS],,[ ])dnl
-CAIRO_ACCUMULATED_FEATURE_VARS_REGISTER([LIBS NONPKGCONFIG_LIBS],,[ ],[$LIBS])dnl
-CAIRO_FEATURE_VARS_REGISTER([NONPKGCONFIG_EXTRA_LIBS])dnl
-AC_SUBST(CAIRO_REQUIRES)dnl
-AC_SUBST(CAIRO_CFLAGS)dnl
-AC_SUBST(CAIRO_LDFLAGS)dnl
-AC_SUBST(CAIRO_NONPKGCONFIG_CFLAGS)dnl
-AC_SUBST(CAIRO_LIBS)dnl
-AC_SUBST(CAIRO_NONPKGCONFIG_LIBS)dnl
-
-dnl add non-pkgconfig values
-AC_CONFIG_COMMANDS_PRE(
-[dnl
-CAIRO_CFLAGS="$CAIRO_CFLAGS $CAIRO_NONPKGCONFIG_CFLAGS"
-CAIRO_LIBS="$CAIRO_LIBS $CAIRO_NONPKGCONFIG_LIBS"
-])dnl
-
-m4_define([_CAIRO_FEATURE_CONFIG_PKGCONFIG_FILE],
-[dnl
- AC_CONFIG_FILES([$3:$4],
- [dnl
- mv "$3" "$3.tmp" &&
- $SED "dnl
- s%@FEATURE_PC@%]cr_pc_modname([$1])[%g;dnl
- s%@FEATURE_NAME@%$2%g;dnl
- s%@FEATURE_BASE@%$$1_BASE%g;dnl
- s%@FEATURE_REQUIRES@%$$1_REQUIRES%g;dnl
- s%@FEATURE_NONPKGCONFIG_LIBS@%$$1_NONPKGCONFIG_LIBS%g;dnl
- s%@FEATURE_NONPKGCONFIG_EXTRA_LIBS@%$$1_NONPKGCONFIG_EXTRA_LIBS%g;dnl
- s%@FEATURE_NONPKGCONFIG_CFLAGS@%$$1_NONPKGCONFIG_CFLAGS%g;dnl
- " < "$3.tmp" > "$3" && rm -f "$3.tmp" ||
- AC_MSG_ERROR(failed to update $3)
- ],[dnl
- SED='$SED'
- $1_BASE='$$1_BASE'
- $1_REQUIRES='$$1_REQUIRES'
- $1_NONPKGCONFIG_LIBS='$$1_NONPKGCONFIG_LIBS'
- $1_NONPKGCONFIG_EXTRA_LIBS='$$1_NONPKGCONFIG_EXTRA_LIBS'
- $1_NONPKGCONFIG_CFLAGS='$$1_NONPKGCONFIG_CFLAGS'
- ])dnl
-])dnl
-
-dnl Generate .pc files for enabled non-builtin public features
-CAIRO_FEATURE_HOOK_REGISTER(yes,!always,!,
-[dnl
- _CAIRO_FEATURE_CONFIG_PKGCONFIG_FILE(
- [$1],
- cr_feature_name,
- [src/]cr_feature_pc,
- [src/cairo-features.pc.in]
- )dnl
-])dnl
-
-dnl Generate -uninstalled.pc files for enabled non-builtin public features
-CAIRO_FEATURE_HOOK_REGISTER(yes,!always,!,
-[dnl
- _CAIRO_FEATURE_CONFIG_PKGCONFIG_FILE(
- [$1],
- cr_feature_name,
- cr_feature_uninstalled_pc,
- [src/cairo-features-uninstalled.pc.in]
- )dnl
-])dnl
-
-
-dnl Collect list of .pc files for all non-builtin public features
-CAIRO_MAKEFILE_ACCUMULATE(cairo,
-[all_$1_pkgconf = cairo.pc])dnl
-CAIRO_MAKEFILE_ACCUMULATE_FEATURE(cairo,*,!always,!,
-[all_$1_pkgconf += cr_feature_pc])dnl
-
-dnl Collect list of .pc files for enabled non-builtin public features
-CAIRO_MAKEFILE_ACCUMULATE(cairo,
-[enabled_$1_pkgconf = cairo.pc])dnl
-CAIRO_MAKEFILE_ACCUMULATE_FEATURE(cairo,yes,!always,!,
-[enabled_$1_pkgconf += cr_feature_pc])dnl
-
-
-dnl ===========================================================================
-dnl
-dnl Generate src/cairo-features.h, src/cairo-supported-features.h, and
-dnl src/cairo-features-win32.h
-dnl
-
-dnl Collect list of enabled public features
-CAIRO_ACCUMULATORS_REGISTER(FEATURES,[ ])dnl
-CAIRO_FEATURE_HOOK_REGISTER(yes,*,!,dnl
-[dnl
- CAIRO_ACCUMULATE(FEATURES, cr_feature_tag)dnl
-])dnl
-dnl Collect list of all supported public features
-CAIRO_ACCUMULATORS_REGISTER(SUPPORTED_FEATURES,[ ])dnl
-CAIRO_FEATURE_HOOK_REGISTER(*,!no,!,dnl
-[dnl
- CAIRO_ACCUMULATE(SUPPORTED_FEATURES, cr_feature_tag)
-])dnl
-dnl Collect list of all supported disabled public features
-CAIRO_ACCUMULATORS_REGISTER(NO_FEATURES,[ ])dnl
-CAIRO_FEATURE_HOOK_REGISTER(no,*,!,
-[dnl
- CAIRO_ACCUMULATE(NO_FEATURES, cr_feature_tag)
-])dnl
-
-dnl Generate src/cairo-features.h
-CAIRO_CONFIG_COMMANDS([src/cairo-features.h],
-[dnl
- echo '/* Generated by configure. Do not edit. */'
- echo '#ifndef CAIRO_FEATURES_H'
- echo '#define CAIRO_FEATURES_H'
- echo ''
- for FEATURE in $CAIRO_FEATURES; do
- echo "#define $FEATURE 1"
- done | LANG=C sort
- echo ''
- for FEATURE in $CAIRO_NO_FEATURES; do
- echo "/*#undef $FEATURE */"
- done | LANG=C sort
- echo ''
- echo '#endif'
-],[dnl
- CAIRO_FEATURES='$CAIRO_FEATURES'
- CAIRO_NO_FEATURES='$CAIRO_NO_FEATURES'
-])dnl
-dnl Generate src/cairo-supported-features.h
-CAIRO_CONFIG_COMMANDS([src/cairo-supported-features.h],
-[dnl
- echo '/* Generated by configure. Do not edit. */'
- echo '#ifndef CAIRO_SUPPORTED_FEATURES_H'
- echo '#define CAIRO_SUPPORTED_FEATURES_H'
- echo ''
- echo '/* This is a dummy header, to trick gtk-doc only */'
- echo ''
- for FEATURE in $CAIRO_SUPPORTED_FEATURES; do
- echo "#define $FEATURE 1"
- done
- echo ''
- echo '#endif'
-],[dnl
- CAIRO_SUPPORTED_FEATURES='$CAIRO_SUPPORTED_FEATURES'
-])dnl
-
-dnl For enabled private features just define them in config.h. No fanfare!
-CAIRO_FEATURE_HOOK_REGISTER(yes,*,,
-[dnl
- AC_DEFINE(cr_feature_tag, 1, [Define to 1 to enable cairo's ]cr_feature_name[ feature])
-])dnl
-
-
-dnl Generate build/Makefile.win32.features-h that generates src/cairo-features.h
-CAIRO_CONFIG_MAKEFILE_PRIVATE_WIN32([win32_features_h],[build],[features-h])
-dnl
-CAIRO_MAKEFILE_ACCUMULATE([win32_features_h],
-[$(top_srcdir)/src/cairo-features.h: $(top_srcdir)/build/Makefile.win32.features
- @echo "Generating src/cairo-features.h"
- @echo "/* Generated by Makefile.win32.features-h. Do not edit. */" > $(top_srcdir)/src/cairo-features.h
- @echo "[#]ifndef CAIRO_FEATURES_H" >> $(top_srcdir)/src/cairo-features.h
- @echo "[#]define CAIRO_FEATURES_H 1" >> $(top_srcdir)/src/cairo-features.h]dnl
-)
-AC_CONFIG_COMMANDS_PRE(
-[dnl
- CAIRO_MAKEFILE_ACCUMULATE([win32_features_h], [ @echo "[#]endif" >> $(top_srcdir)/src/cairo-features.h])
-])dnl
-CAIRO_MAKEFILE_ACCUMULATE_FEATURE([win32_features_h],yes,*,*,dnl
-[ @echo "[#]define cr_feature_tag 1" >> $(top_srcdir)/src/cairo-features.h]dnl
-)dnl
-
-
-dnl ===========================================================================
-dnl
-dnl Report
-dnl
-
-CAIRO_ACCUMULATORS_REGISTER([WARNING_MESSAGE],m4_newline()m4_newline)dnl
-
-dnl Collect warning message for enabled unsupported public features
-CAIRO_FEATURE_HOOK_REGISTER(yes,no,!,
-[dnl
- CAIRO_ACCUMULATE([WARNING_MESSAGE], CAIRO_TEXT_WRAP([The ]cr_feature_name[ feature is still under active development and is included in this release only as a preview. It does NOT fully work yet and incompatible changes may yet be made to ]cr_feature_name[ specific API.], [--- ]))
-])dnl
-
-dnl Collect warning message for disabled recommended features
-CAIRO_FEATURE_HOOK_REGISTER(no,yes,*,
-[dnl
- CAIRO_ACCUMULATE([WARNING_MESSAGE], CAIRO_TEXT_WRAP([It is strongly recommended that you do NOT disable the ]cr_feature_name[ feature.], [+++ ]))
-])dnl
-
-
-dnl Collect enabled native surface/font backend features
-CAIRO_ACCUMULATORS_REGISTER([NATIVE_SURFACE_BACKENDS])dnl
-CAIRO_ACCUMULATORS_REGISTER([NATIVE_FONT_BACKENDS])dnl
-CAIRO_FEATURE_HOOK_REGISTER(yes,auto,surface,
-[dnl
- CAIRO_ACCUMULATE([NATIVE_SURFACE_BACKENDS], [$1])
-])dnl
-CAIRO_FEATURE_HOOK_REGISTER(yes,auto,font,
-[dnl
- CAIRO_ACCUMULATE([NATIVE_FONT_BACKENDS], [$1])
-])dnl
-
-dnl Collect warning message if no native surface/font backend feature enabled
-AC_CONFIG_COMMANDS_PRE(dnl
-[dnl
- AS_IF([test -z "$CAIRO_NATIVE_SURFACE_BACKENDS"],dnl
- [dnl
- CAIRO_ACCUMULATE([WARNING_MESSAGE], CAIRO_TEXT_WRAP([No native surface backends enabled for your platform. It is strongly recommended that you enable the native surface backend feature for your platform.], [*** ]))
- ])
- AS_IF([test -z "$CAIRO_NATIVE_FONT_BACKENDS"],dnl
- [dnl
- CAIRO_ACCUMULATE([WARNING_MESSAGE], CAIRO_TEXT_WRAP([No native font backends enabled for your platform. It is strongly recommended that you enable the native font backend feature for your platform.], [*** ]))
- ])
-])dnl
-
-
-AC_DEFUN([CAIRO_REPORT],
-[dnl
- V="$CAIRO_VERSION_MAJOR.$CAIRO_VERSION_MINOR.$CAIRO_VERSION_MICRO"
- echo ""
- echo "cairo (version $V [[$CAIRO_RELEASE_STATUS]]) will be compiled with:"
- echo ""
- echo "The following surface backends:"
- echo " Image: yes (always builtin)"
- echo " Recording: yes (always builtin)"
- echo " Observer: yes (always builtin)"
- echo " Mime: yes (always builtin)"
- echo " Tee: $use_tee"
- echo " XML: $use_xml"
- echo " Xlib: $use_xlib"
- echo " Xlib Xrender: $use_xlib_xrender"
- echo " Quartz: $use_quartz"
- echo " Quartz-image: $use_quartz_image"
- echo " XCB: $use_xcb"
- echo " Win32: $use_win32"
- echo " CairoScript: $use_script"
- echo " PostScript: $use_ps"
- echo " PDF: $use_pdf"
- echo " SVG: $use_svg"
- echo " OpenGL: $use_gl"
- echo " OpenGL ES 2.0: $use_glesv2"
- echo " OpenGL ES 3.0: $use_glesv3"
- echo ""
- echo "The following font backends:"
- echo " User: yes (always builtin)"
- echo " FreeType: $use_ft"
- echo " Fontconfig: $use_fc"
- echo " Win32: $use_win32_font"
- echo " Quartz: $use_quartz_font"
- echo ""
- echo "The following functions:"
- echo " PNG functions: $use_png"
- echo " GLX functions: $use_glx"
- echo " WGL functions: $use_wgl"
- echo " EGL functions: $use_egl"
- echo " X11-xcb functions: $use_xlib_xcb"
- echo " XCB-shm functions: $use_xcb_shm"
- echo ""
- echo "The following features and utilities:"
- echo " cairo-trace: $use_trace"
- echo " cairo-script-interpreter: $use_interpreter"
- echo ""
- echo "And the following internal features:"
- echo " pthread: $use_pthread"
- echo " gtk-doc: $enable_gtk_doc"
- echo " gcov support: $use_gcov"
- echo " symbol-lookup: $use_symbol_lookup"
- echo " test surfaces: $use_test_surfaces"
- echo " ps testing: $test_ps"
- echo " pdf testing: $test_pdf"
- echo " svg testing: $test_svg"
- if test x"$use_win32" = "xyes"; then
- echo " win32 printing testing: $test_win32_printing"
- fi
- echo "$CAIRO_WARNING_MESSAGE"
- echo ""
-])dnl
-
diff --git a/build/configure.ac.noversion b/build/configure.ac.noversion
deleted file mode 100644
index 18c4bd5f7..000000000
--- a/build/configure.ac.noversion
+++ /dev/null
@@ -1,23 +0,0 @@
-dnl
-dnl Version stuff
-dnl
-
-dnl Disable autoconf's version macros. We try hard to not rebuild the entire
-dnl library just because version changed. The PACKAGE_VERSION* stuff in
-dnl config.h is negating all the effort.
-dnl
-dnl We're not actually supposed to be doing this, and indeed adding the
-dnl AC_DEFINEs below causes confdefs.h to contain duplicate incompatible
-dnl #defines for the same PACKAGE_* symbols. Those are provoking warnings
-dnl from the compiler, and that throws our CAIRO_TRY_LINK_*_ checks off,
-dnl because they think that there's something wrong with some flag they're
-dnl testing rather than confdefs.h! So let's do the gross thing and puke
-dnl into confdefs.h some #undefs.
-echo '#undef PACKAGE_VERSION' >>confdefs.h
-echo '#undef PACKAGE_STRING' >>confdefs.h
-echo '#undef PACKAGE_NAME' >>confdefs.h
-echo '#undef PACKAGE_TARNAME' >>confdefs.h
-AC_DEFINE(PACKAGE_VERSION, [USE_cairo_version_OR_cairo_version_string_INSTEAD])
-AC_DEFINE(PACKAGE_STRING, [USE_cairo_version_OR_cairo_version_string_INSTEAD])
-AC_DEFINE(PACKAGE_NAME, [USE_cairo_INSTEAD])
-AC_DEFINE(PACKAGE_TARNAME, [USE_cairo_INSTEAD])
diff --git a/build/configure.ac.pthread b/build/configure.ac.pthread
deleted file mode 100644
index 29c930da9..000000000
--- a/build/configure.ac.pthread
+++ /dev/null
@@ -1,253 +0,0 @@
-dnl Defines the macro CAIRO_CONFIGURE_PTHREAD to find a suitable
-dnl pthread implementation. There are two levels of pthread conformance
-dnl we are looking for:
-dnl
-dnl a) A minimal level denoted by -DCAIRO_HAS_PTHREAD=1: This level
-dnl requires mutex and recursive mutexattr support. If possible we try
-dnl to use weakly linked stubs from libc over the real pthread library.
-dnl This level is required by the cairo library proper. If the user
-dnl invokes configure with --enable-pthread=yes or
-dnl --enable-pthread=always then we avoid trying to use weak stubs.
-dnl
-dnl b) A full level denoted by -DCAIRO_HAS_REAL_PTHREAD=1: This level
-dnl requires full support from a real pthread library, including thread
-dnl creation, joins, thread attribtues, etc. This level is required by
-dnl multithreaded applications using cairo, such as the test suite
-dnl binaries and cairo utilities.
-dnl
-dnl Usage:
-dnl CAIRO_ENABLE(pthread, pthread, <default yes|no|auto|always>,
-dnl [CAIRO_CONFIGURE_PTHREAD])
-dnl
-dnl This should be invoked near the end of configure.ac so that
-dnl the pthread specific CFLAGS and LIBS end up at the front
-dnl of CAIRO_CFLAGS and CAIRO_LIBS -- this helps ensure that we
-dnl really do get non-weak symbols from the actual pthread library
-dnl rather than possible stubs in other libraries.
-dnl
-dnl The user can override the choices made by
-dnl CAIRO_CONFIGURE_PTHREAD by using --enable-pthread=yes and
-dnl giving PTHREAD_CFLAGS and PTHREAD_LIBS to configure.
-dnl
-dnl Sets environment variables:
-dnl use_pthread="yes" | "no (<errmsg>)"
-dnl have_pthread="yes" | "no (<errmsg)"
-dnl have_real_pthread="yes" | "no (<errmsg)"
-dnl pthread_{CFLAGS,LIBS,REQUIRES}
-dnl real_pthread_{CFLAGS,LIBS}
-dnl
-dnl Autoconfigured defines in config.h (conditional):
-dnl CAIRO_HAS_PTHREAD
-dnl CAIRO_HAS_REAL_PTHREAD
-dnl
-
-dnl -----------------------------------------------------------------------
-dnl A program to test all the pthread features we need to be able to
-dnl compile libcairo itself. We could test the features independently,
-dnl but we need all of them anyway.
-m4_define([libcairo_pthread_program],[dnl
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE /* for PTHREAD_MUTEX_INITIALIZER under linux */
-#endif
-#include <pthread.h>
-
-pthread_mutex_t test_mutex_initializer = PTHREAD_MUTEX_INITIALIZER;
-int test_mutex (void)
-{
- int x = 0;
- pthread_mutex_t mutex;
- x |= pthread_mutex_init (&mutex, NULL);
- x |= pthread_mutex_lock (&mutex);
- x |= pthread_mutex_unlock (&mutex);
- x |= pthread_mutex_destroy (&mutex);
- return 0;
-}
-
-int test_mutex_attr (void)
-{
- int x = 0;
- pthread_mutexattr_t attr;
- pthread_mutex_t mutex;
- x |= pthread_mutexattr_init (&attr);
- x |= pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
- x |= pthread_mutex_init (&mutex, &attr);
- x |= pthread_mutex_lock (&mutex);
- x |= pthread_mutex_unlock (&mutex);
- x |= pthread_mutex_destroy (&mutex);
- x |= pthread_mutexattr_destroy (&attr);
- return x;
-}])
-
-dnl -----------------------------------------------------------------------
-dnl A program to test all the features we want to be able to run the test
-dnl suite or other thready cairo applications that want real threads.
-m4_define([testsuite_pthread_program],[dnl
-libcairo_pthread_program
-
-pthread_once_t once_control = PTHREAD_ONCE_INIT;
-void test_once_init (void) {}
-int test_once (void)
-{
- return pthread_once (&once_control, test_once_init);
-}
-
-pthread_key_t test_specific_key;
-int test_specific (void)
-{
- int x = 0;
- x |= pthread_key_create (&test_specific_key, NULL);
- x |= pthread_setspecific (test_specific_key, NULL);
- x |= pthread_getspecific (test_specific_key) != NULL;
- return x;
-}
-
-void cleaner (void *arg) { (void)arg; }
-
-void *
-test_thread_main (void *arg)
-{
- pthread_cleanup_push (cleaner, arg);
- pthread_exit (arg);
- pthread_cleanup_pop (1);
- return arg;
-}
-
-int
-test_threads (void)
-{
- int x = 0;
- pthread_t thread;
- pthread_attr_t attr;
- void *arg = NULL;
- x |= pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
- x |= pthread_create (&thread, &attr, test_thread_main, arg);
- x |= pthread_equal (pthread_self(), thread);
- x |= pthread_join (thread, &arg);
- x |= pthread_attr_destroy (&attr);
- return x;
-}])
-
-dnl -----------------------------------------------------------------------
-
-dnl CAIRO_CHECK_PTHREAD(tag, cflags, libs, program, true-action, false-action)
-dnl Set <tag>_{CFLAGS,LIBS} to {<cflags>,<libs>} if we can compile and link
-dnl <program> with the given flags and libs. Execute <true-action> on
-dnl success and <false-action> on failure.
-AC_DEFUN([CAIRO_CHECK_PTHREAD],[dnl
- CAIRO_CC_TRY_LINK_WITH_ENV_SILENT(
- [CFLAGS="$CFLAGS $2";
- LIBS="$LIBS $3"],
- [$4],
- [$1_CFLAGS="$2";
- $1_LIBS="$3";
- $5],
- [$1_CFLAGS="";
- $1_LIBS="";
- $6])
-])
-
-dnl CAIRO_CONFIGURE_PTHREADS(): Look for pthreads.
-dnl
-dnl If the user specifies PTHREAD_CFLAGS and PTHREAD_LIBS then we use
-dnl those. Otherwise we try CFLAGS=-D_REENTRANT and LIBS=-lpthread for
-dnl full pthread support, and look for stubs in libc for the minimal
-dnl pthread support.
-dnl
-dnl CFLAGS=-D_REENTRANT LIBS=-lpthread has been tested to work on:
-dnl
-dnl Solaris 9 (5.9) Sun C 5.8 Patch 121015-04 2007/01/10
-dnl OpenSolaris (5.11) Sun C 5.9 Patch 124868-08 2008/11/25
-dnl OpenSolaris (5.11) clang version 1.1 (trunk 90017)
-dnl Tru64/OSF1 V5.1 Compaq C V6.5-003
-dnl Mac OS X 10.5.5 gcc 4.0.1 (Apple Inc. build 5465)
-dnl Mac OS X 10.6 gcc 4.2.1 (Apple Inc. build 5659)
-dnl FreeBSD 7.2 gcc 4.2
-dnl OpenBSD 4.5 gcc 3.3.5 (propolice)
-dnl Debian Linux (Etch) gcc 4.3
-dnl
-dnl Thread support is also in various libcs directly, so often using no
-dnl flags at all works as well, but unfortunately Solaris 9 has
-dnl practically _all_ of libpthread stubbed out in libc, so we cannot
-dnl distinguish between a working libpthread and a stubbed out one by a
-dnl link-only test.
-dnl
-dnl We also explicitly do not link to pthread-stubs or whatever other
-dnl third-party stubs library, since that forces cairo clients to be
-dnl extra careful when giving both libcairo and libpthread on the
-dnl command line: the user would have to use "-lpthread -lcairo" rather
-dnl than the more common "-lcairo -lpthread" to not accidentally use
-dnl stubs pulled in by libcairo everywhere in the application. We
-dnl might also need to have a way to teach pkg-config about library
-dnl ordering constraints which aren't actual dependencies, and at this
-dnl point it just starts doing my head in.
-dnl
-dnl If your unix-like doesn't work with the secret handshake
-dnl -D_REENTRANT -lpthread and you can actually compile the rest of
-dnl cairo just fine otherwise, please take a moment complain loudly
-dnl to the cairo mailing list!
-dnl
-AC_DEFUN([CAIRO_CONFIGURE_PTHREAD],[dnl
- dnl Try to use the user's PTHREAD_LIBS/CFLAGS
- dnl if they're available.
- if test "x$PTHREAD_CFLAGS" = "x"; then
- PTHREAD_CFLAGS="-D_REENTRANT"
- fi
- if test "x$PTHREAD_LIBS" = "x"; then
- PTHREAD_LIBS="-lpthread"
- fi
-
- dnl First try to find the real pthreads.
- CAIRO_CHECK_PTHREAD(
- [real_pthread], [$PTHREAD_CFLAGS], [$PTHREAD_LIBS],
- [testsuite_pthread_program],
- [have_real_pthread=yes],
- [have_real_pthread=no])
- if test "x$have_real_pthread" != "xyes"; then
- dnl Give -pthread a go.
- CAIRO_CHECK_PTHREAD(
- [real_pthread], [-pthread], [],
- [testsuite_pthread_program],
- [have_real_pthread=yes],
- [have_real_pthread="no (can't link with -lpthread or -pthread)"])
- fi
- PTHREAD_CFLAGS=
- PTHREAD_LIBS=
-
- dnl Check if we can use libc's stubs in libcairo.
- dnl Only do this if the user hasn't explicitly enabled
- dnl pthreads, but is relying on automatic configuration.
- have_pthread="no"
- if test "x$enable_pthread" != "xyes"; then
- CAIRO_CHECK_PTHREAD(
- [pthread], [-D_REENTRANT], [],
- [libcairo_pthread_program],
- [have_pthread=yes],
- [])
- fi
-
- dnl Default to using the real pthreads for libcairo.
- if test "x$have_pthread" != "xyes"; then
- have_pthread="$have_real_pthread";
- pthread_CFLAGS="$real_pthread_CFLAGS";
- pthread_LIBS="$real_pthread_LIBS";
- fi
-
- dnl Tell autoconf about the results.
- if test "x$have_real_pthread" = "xyes"; then
- AC_DEFINE([CAIRO_HAS_REAL_PTHREAD], 1,
- [Define to 1 if we have full pthread support])
- fi
- if test "x$have_pthread" = "xyes"; then
- AC_DEFINE([CAIRO_HAS_PTHREAD], 1,
- [Define to 1 f we have minimal pthread support])
- fi
-
- dnl Make sure we scored some pthreads.
- if test "x$enable_pthread" = "xyes" -a "x$have_pthread" != "xyes"; then
- AC_MSG_ERROR([pthread requested but not found])
- fi
-
- dnl Set the output variables for CAIRO_ENABLE.
- use_pthread="$have_pthread"
- pthread_REQUIRES=""
-])
diff --git a/build/configure.ac.system b/build/configure.ac.system
deleted file mode 100644
index d6fb14ebe..000000000
--- a/build/configure.ac.system
+++ /dev/null
@@ -1,170 +0,0 @@
-
-dnl Non-failing checks for functions, headers, libraries, etc go here
-
-
-dnl ====================================================================
-dnl Feature checks
-dnl ====================================================================
-
-AM_CONDITIONAL(CROSS_COMPILING, test "x$cross_compiling" = "xyes")
-CAIRO_BIGENDIAN
-AC_ARG_ENABLE(atomic,
- [AS_HELP_STRING([--disable-atomic],
- [disable use of native atomic operations])],
- [use_atomic=$enableval], [use_atomic=yes])
-AS_IF([test "x$use_atomic" = "xyes"], [
- CAIRO_CHECK_NATIVE_ATOMIC_PRIMITIVES
- CAIRO_CHECK_ATOMIC_OP_NEEDS_MEMORY_BARRIER
-])
-AC_CHECK_SIZEOF(void *)
-AC_CHECK_SIZEOF(int)
-AC_CHECK_SIZEOF(long)
-AC_CHECK_SIZEOF(long long)
-AC_CHECK_SIZEOF(size_t)
-
-AC_MSG_CHECKING([for native Win32])
-case "$host" in
- *-*-mingw*)
- cairo_os_win32=yes
- ;;
- *)
- cairo_os_win32=no
- ;;
-esac
-AC_MSG_RESULT([$cairo_os_win32])
-AM_CONDITIONAL(OS_WIN32, test "$cairo_os_win32" = "yes")
-
-AC_MSG_CHECKING([for Sun Solaris (non-POSIX ctime_r)])
-case "$host" in
- *-*-solaris*)
- CFLAGS="$CFLAGS -D_POSIX_PTHREAD_SEMANTICS"
- solaris_posix_pthread=yes
- ;;
- *)
- solaris_posix_pthread=no
- ;;
-esac
-AC_MSG_RESULT([$solaris_posix_pthread])
-
-dnl ====================================================================
-dnl Library checks
-dnl ====================================================================
-
-LT_LIB_M
-LIBS="$LIBS $LIBM"
-
-AC_CHECK_LIB(rt, sched_yield)
-
-has_shm_open=
-AC_CHECK_LIB(rt, shm_open, [
- SHM_LIBS=-lrt
- has_shm_open=yes
- ], [SHM_LIBS=])
-AM_CONDITIONAL(HAVE_SHM, test "x$has_shm_open" = "xyes")
-AC_SUBST(SHM_LIBS)
-
-AC_CHECK_LIB(socket, connect, [SOCKET_LIBS=-lsocket], [SOCKET_LIBS=])
-CAIROBOILERPLATE_LIBS=$SOCKET_LIBS
-AC_SUBST(CAIROBOILERPLATE_LIBS)
-
-dnl ====================================================================
-dnl Header/function checks
-dnl ====================================================================
-
-dnl check if we have a __builtin_return_address for the cairo-trace
-dnl utility.
-AC_MSG_CHECKING([for __builtin_return_address(0)])
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[__builtin_return_address(0);]])],[have_builtin_return_address=yes],[have_builtin_return_address=no])
-AC_MSG_RESULT($have_builtin_return_address)
-if test "x$have_builtin_return_address" = "xyes"; then
- AC_DEFINE(HAVE_BUILTIN_RETURN_ADDRESS, 1,
- [Define to 1 if your compiler supports the __builtin_return_address() intrinsic.])
-fi
-
-dnl Checks for precise integer types
-AC_CHECK_HEADERS([stdint.h inttypes.h sys/int_types.h])
-AC_CHECK_TYPES([uint64_t, uint128_t, __uint128_t])
-
-dnl Check for socket support for any2ppm daemon
-AC_CHECK_HEADERS([fcntl.h unistd.h signal.h poll.h sys/stat.h sys/socket.h sys/poll.h sys/un.h])
-
-dnl Check for infinite loops
-AC_CHECK_FUNCS([alarm])
-
-dnl check for CPU affinity support
-AC_CHECK_HEADERS([sched.h], [AC_CHECK_FUNCS([sched_getaffinity])])
-
-dnl check for mmap support
-AC_CHECK_HEADERS([sys/mman.h], [AC_CHECK_FUNCS([mmap])])
-
-dnl check for clock_gettime() support
-AC_CHECK_HEADERS([time.h], [AC_CHECK_FUNCS([clock_gettime])])
-
-dnl check for GNU-extensions to fenv
-AC_CHECK_HEADER(fenv.h,
- [AC_CHECK_FUNCS(feenableexcept fedisableexcept feclearexcept)])
-
-dnl check for misc headers and functions
-AC_CHECK_HEADERS([libgen.h byteswap.h signal.h setjmp.h fenv.h sys/wait.h])
-AC_CHECK_FUNCS([ctime_r localtime_r gmtime_r drand48 flockfile funlockfile getline link strndup])
-
-dnl Check if the runtime platform is a native Win32 host.
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[
-#ifdef _WIN32
- choke me
-#endif
-]])], [have_windows=no], [have_windows=yes])
-
-dnl Possible headers for mkdir
-AC_CHECK_HEADERS([sys/stat.h io.h])
-AC_CHECK_FUNC(mkdir,
- [AC_MSG_CHECKING([mkdir variant])
- mkdir_variant="unknown"
- save_CFLAGS="$CFLAGS"
- CFLAGS=$WARN_CFLAGS
- AC_COMPILE_IFELSE(
- [
- AC_LANG_PROGRAM([[
- #ifdef HAVE_SYS_STAT_H
- #include <sys/stat.h>
- #endif
- #ifdef HAVE_IO_H
- #include <io.h>
- #endif
- ]],
- [[mkdir ("hello.world", 0777)]])
- ],
- [mkdir_variant="mkdir(path, mode)"],
- [
- AC_COMPILE_IFELSE(
- [AC_LANG_PROGRAM([[
- #ifdef HAVE_SYS_STAT_H
- #include <sys/stat.h>
- #endif
- #ifdef HAVE_IO_H
- #include <io.h>
- #endif
- ]],
- [[mkdir ("hello.world")]])
- ],
- mkdir_variant="mkdir(path)")
- ])
-
- AC_MSG_RESULT($mkdir_variant)
- CFLAGS="$save_CFLAGS"
- if test "x$mkdir_variant" = "xmkdir(path, mode)"; then
- AC_DEFINE(HAVE_MKDIR, 2,
- [Define to non-zero if your system has mkdir, and to 2 if your version of mkdir requires a mode parameter])
- else
- AC_DEFINE(HAVE_MKDIR, 1,
- [Define to non-zero if your system has mkdir, and to 2 if your version of mkdir requires a mode parameter])
- fi
- ])
-
-dnl ===========================================================================
-
-dnl Test for the tools required for building one big test binary
-
-
-AC_CHECK_FUNCS(fork waitpid raise)
-
diff --git a/build/configure.ac.tools b/build/configure.ac.tools
deleted file mode 100644
index 7c11f0c9b..000000000
--- a/build/configure.ac.tools
+++ /dev/null
@@ -1,24 +0,0 @@
-
-AC_PATH_PROG(FIND, find)
-AC_PATH_PROG(XARGS, xargs)
-
-AC_PROG_CC
-AC_PROG_CPP
-AM_PROG_CC_C_O
-AC_C_INLINE
-
-dnl ===========================================================================
-
-PKG_PROG_PKG_CONFIG()
-if test "x$PKG_CONFIG" = x; then
- AC_MSG_ERROR([pkg-config >= $PKGCONFIG_REQUIRED required but not found (https://pkgconfig.freedesktop.org/)])
-fi
-
-dnl Check for recent pkg-config which supports Requires.private
-case `$PKG_CONFIG --version` in
-[0.?|0.?.?|0.1[0-7]|0.1[0-7].?]) PKGCONFIG_REQUIRES="Requires"; ;;
-*) PKGCONFIG_REQUIRES="Requires.private"; ;;
-esac
-
-AC_SUBST(PKGCONFIG_REQUIRES)
-
diff --git a/build/configure.ac.version b/build/configure.ac.version
deleted file mode 100644
index a91cee39e..000000000
--- a/build/configure.ac.version
+++ /dev/null
@@ -1,42 +0,0 @@
-dnl
-dnl Version stuff
-dnl
-
-dnl This macro expands to one of 'git', 'snapshot', or 'release'
-m4_define([cairo_release_status],
- [m4_if(m4_eval(cairo_version_micro % 2), [1], [git],
- [m4_if(m4_eval(cairo_version_minor % 2), [1], [snapshot],
- [release])])])
-
-dnl This is the .so/dll number. 2 for cairo-1.x.x
-m4_define([cairo_version_sonum], m4_eval(cairo_version_major + 1))
-
-dnl The libtool shared library version stuff
-m4_define([cairo_version],
- m4_eval(cairo_version_major*10000 + cairo_version_minor*100 + cairo_version_micro))
-m4_if(m4_eval(cairo_version_minor % 2), [1],
- [
- dnl for unstable releases
- m4_define([cairo_libtool_revision], 0)
- ],
- [
- dnl for stable releases
- m4_define([cairo_libtool_revision], cairo_version_micro)
- ])
-m4_define([cairo_libtool_current],
- m4_eval(cairo_version_sonum + cairo_version - cairo_libtool_revision))
-m4_define([cairo_libtool_age],
- m4_eval(cairo_libtool_current - cairo_version_sonum))
-
-CAIRO_VERSION_MAJOR=cairo_version_major
-CAIRO_VERSION_MINOR=cairo_version_minor
-CAIRO_VERSION_MICRO=cairo_version_micro
-CAIRO_VERSION_SONUM=cairo_version_sonum
-CAIRO_RELEASE_STATUS=cairo_release_status
-CAIRO_LIBTOOL_VERSION_INFO=cairo_libtool_current:cairo_libtool_revision:cairo_libtool_age
-AC_SUBST(CAIRO_VERSION_MAJOR)
-AC_SUBST(CAIRO_VERSION_MINOR)
-AC_SUBST(CAIRO_VERSION_MICRO)
-AC_SUBST(CAIRO_VERSION_SONUM)
-AC_SUBST(CAIRO_RELEASE_STATUS)
-AC_SUBST(CAIRO_LIBTOOL_VERSION_INFO)
diff --git a/build/configure.ac.warnings b/build/configure.ac.warnings
deleted file mode 100644
index 85bc3878a..000000000
--- a/build/configure.ac.warnings
+++ /dev/null
@@ -1,99 +0,0 @@
-dnl Use lots of warning flags with with gcc and compatible compilers
-
-dnl Note: if you change the following variable, the cache is automatically
-dnl skipped and all flags rechecked. So there's no need to do anything
-dnl else. If for any reason you need to force a recheck, just change
-dnl MAYBE_WARN in an ignorable way (like adding whitespace)
-
-# -Wcast-align generates lots of false positive reports we need to
-# cast image data from uint8_t to uin32_t.
-
-# -Wlogical-op causes too much noise from strcmp("literal", str)
-
-MAYBE_WARN="-Wall -Wextra \
--Wmissing-declarations -Werror-implicit-function-declaration \
--Wpointer-arith -Wwrite-strings -Wsign-compare -Wpacked \
--Wswitch-enum -Wmissing-format-attribute -Wvolatile-register-var \
--Wstrict-aliasing=2 -Winit-self -Wunsafe-loop-optimizations \
--Wno-missing-field-initializers -Wno-unused-parameter \
--Wno-attributes -Wno-long-long -Winline"
-
-MAYBE_C_SPECIFIC_WARN="-Wold-style-definition \
--Wdeclaration-after-statement -Wstrict-prototypes \
--Wmissing-prototypes -Wbad-function-cast -Wnested-externs"
-
-# New -Wno options should be added here
-# gcc-4.4 and later accept every -Wno- option but may complain later that this
-# option is unknown each time another warning happens.
-# -Wunused-but-set-variable is too noisy at present
-NO_WARN="unused-but-set-variable"
-
-dnl Sun Studio 12 likes to rag at us for abusing enums like
-dnl having cairo_status_t variables hold cairo_int_status_t
-dnl values. It's bad, we know. Now please be quiet.
-MAYBE_WARN="$MAYBE_WARN -erroff=E_ENUM_TYPE_MISMATCH_ARG \
- -erroff=E_ENUM_TYPE_MISMATCH_OP"
-
-dnl We also abuse the warning-flag facility to enable other compiler
-dnl options. Namely, the following:
-MAYBE_WARN="$MAYBE_WARN -fno-strict-aliasing -fno-common"
-
-dnl Also to turn various gcc/glibc-specific preprocessor checks
-MAYBE_WARN="$MAYBE_WARN -Wp,-D_FORTIFY_SOURCE=2"
-
-# invalidate cached value if MAYBE_WARN has changed
-if test "x$cairo_cv_warn_maybe" != "x$MAYBE_WARN"; then
- unset cairo_cv_warn_cflags
-fi
-AC_CACHE_CHECK([for supported warning flags], cairo_cv_warn_cflags, [
- echo
- WARN_CFLAGS=""
-
- # Some warning options are not supported by all versions of
- # gcc, so test all desired options against the current
- # compiler.
- #
- # Note that there are some order dependencies
- # here. Specifically, an option that disables a warning will
- # have no net effect if a later option then enables that
- # warnings, (perhaps implicitly). So we put some grouped
- # options (-Wall and -Wextra) up front and the -Wno options
- # last.
-
- for W in $MAYBE_WARN; do
- CAIRO_CC_TRY_FLAG([$W],, [WARN_CFLAGS="$WARN_CFLAGS $W"])
- done
- for W in $NO_WARN; do
- CAIRO_CC_TRY_FLAG([-W$W -Wno-$W],, [WARN_CFLAGS="$WARN_CFLAGS -Wno-$W"])
- done
- cairo_cv_warn_cflags=$WARN_CFLAGS
- cairo_cv_warn_maybe="$MAYBE_WARN $MAYBE_C_SPECIFIC_WARN"
-
- AC_MSG_CHECKING([which warning flags were supported])
-])
-WARN_CFLAGS="$cairo_cv_warn_cflags"
-CAIRO_CFLAGS="$CAIRO_CFLAGS $WARN_CFLAGS"
-
-# We only wish to enable attribute(warn_unused_result) if we can prevent
-# gcc from generating thousands of warnings about the misapplication of the
-# attribute to void functions and variables.
-AC_CACHE_CHECK([how to enable unused result warnings], cairo_cv_warn_unused_result, [
- AC_REQUIRE([AC_PROG_GREP])
- cairo_cv_warn_unused_result=""
- if echo $WARN_CFLAGS | $GREP -e '-Wno-attributes' >/dev/null; then
- CAIRO_CC_TRY_FLAG_SILENT(
- [-Wno-attributes],
- [__attribute__((__warn_unused_result__)) void f (void) {}
- __attribute__((__warn_unused_result__)) int g;],
- [cairo_cv_warn_unused_result="__attribute__((__warn_unused_result__))"])
- fi
-])
-AC_DEFINE_UNQUOTED([WARN_UNUSED_RESULT], [$cairo_cv_warn_unused_result],
- [Define to the value your compiler uses to support the warn-unused-result attribute])
-
-dnl check linker flags
-AC_CACHE_CHECK([how to allow undefined symbols in shared libraries used by test suite], cairo_cv_test_undefined_ldflags,
- [CAIRO_CC_TRY_FLAG_SILENT([-Wl,--allow-shlib-undefined], [],
- [cairo_cv_test_undefined_ldflags="-Wl,--allow-shlib-undefined]")])
-CAIRO_TEST_UNDEFINED_LDFLAGS="$cairo_cv_test_undefined_ldflags"
-AC_SUBST(CAIRO_TEST_UNDEFINED_LDFLAGS)
diff --git a/configure.ac b/configure.ac
deleted file mode 100644
index c30ce0916..000000000
--- a/configure.ac
+++ /dev/null
@@ -1,816 +0,0 @@
-AC_PREREQ([2.63])
-CAIRO_PARSE_VERSION
-AC_INIT([cairo],
- [cairo_version_major.cairo_version_minor.cairo_version_micro],
- [https://gitlab.freedesktop.org/cairo/cairo/-/issues],
- [cairo],
- [https://cairographics.org/])
-AC_CONFIG_AUX_DIR(build)
-AC_CONFIG_MACRO_DIR(build)
-AC_USE_SYSTEM_EXTENSIONS
-AC_CONFIG_SRCDIR(src/cairo.h)
-AC_CONFIG_HEADERS(config.h)
-
-AC_CHECK_HEADERS([unistd.h sys/ioctl.h])
-AC_C_TYPEOF
-
-AM_INIT_AUTOMAKE([1.11 foreign -Wall no-define no-dist-gzip dist-xz serial-tests subdir-objects])
-AM_SILENT_RULES([yes])
-m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) dnl Workaround for Automake 1.12
-
-# Initialize libtool
-LT_PREREQ([2.2])
-LT_INIT([win32-dll])
-
-# Api documentation
-GTK_DOC_CHECK([1.15],[--flavour no-tmpl])
-
-AC_SYS_LARGEFILE
-
-dnl ===========================================================================
-dnl
-dnl The order of the includes here is rather important
-dnl
-m4_include(build/configure.ac.version) dnl macros setting up various version declares
-m4_include(build/configure.ac.tools) dnl checks for tools we use
-m4_include(build/configure.ac.features) dnl macros for backend/feature handling
-m4_include(build/configure.ac.warnings) dnl checks for compiler warning
-m4_include(build/configure.ac.system) dnl checks for system functions, headers, libs
-m4_include(build/configure.ac.analysis) dnl checks for analysis tools (lcov, etc)
-m4_include(build/configure.ac.noversion) dnl disable builtin libtool versioning
-m4_include(build/configure.ac.pthread) dnl checks for pthreads
-AC_CACHE_SAVE
-
-dnl ===========================================================================
-
-AC_CHECK_LIB(z, compress,
- [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/)"])
-
-save_LIBS="$LIBS"
-AC_CHECK_LIB(lzo2, lzo2a_decompress,
- [AC_CHECK_HEADER(lzo/lzo2a.h, [
- have_lzo=yes
- AC_DEFINE(HAVE_LZO, 1, [Define to 1 if you have lzo available])
- lzo_LIBS="-llzo2"
- ],
- [have_lzo="no (requires lzpo http://www.oberhumer.com/opensource/lzo/)"])],
- [have_lzo="no (requires lzpo http://www.oberhumer.com/opensource/lzo/)"])
-AC_SUBST(lzo_LIBS)
-LIBS="$save_LIBS"
-
-AC_CHECK_LIB(dl, dlsym,
- [have_dlsym=yes; have_dl=yes],
- [have_dlsym=no; have_dl=no])
-if test "x$have_dlsym" = "xno"; then
- AC_CHECK_FUNC(dlsym, [have_dlsym=yes], [have_dlsym=no])
-fi
-AC_CHECK_HEADERS(dlfcn.h, [have_dlsym=yes], [have_dlsym=no])
-AM_CONDITIONAL(CAIRO_HAS_DL, test "x$have_dl" = "xyes")
-if test "x$have_dlsym" = "xyes"; then
- AC_DEFINE([CAIRO_HAS_DLSYM], 1, [Define to 1 if dlsym is available])
-fi
-AM_CONDITIONAL(CAIRO_HAS_DLSYM, test "x$have_dlsym" = "xyes")
-
-AC_CHECK_HEADERS(xlocale.h)
-AC_CHECK_FUNCS(newlocale strtod_l)
-
-dnl ===========================================================================
-
-CAIRO_ENABLE_SURFACE_BACKEND(xlib, Xlib, auto, [
- xlib_REQUIRES="x11 xext"
- PKG_CHECK_MODULES(xlib, $xlib_REQUIRES, ,
- [xlib_REQUIRES=""
- AC_PATH_XTRA
- if test "x$no_x" = xyes; then
- use_xlib="no (requires X development libraries)"
- else
- xlib_NONPKGCONFIG_LIBS="$X_PRE_LIBS $X_LIBS -lX11 -lXext $X_EXTRA_LIBS"
- xlib_NONPKGCONFIG_CFLAGS=$X_CFLAGS
- fi])
-
- AC_CHECK_HEADER(sys/ipc.h)
- AC_CHECK_HEADER(sys/shm.h)
-
- if test "$ac_cv_header_sys_ipc_h" = "yes" -a "$ac_cv_header_sys_shm_h" = "yes"; then
- AC_MSG_CHECKING(whether shmctl IPC_RMID allowes subsequent attaches)
- AC_RUN_IFELSE([AC_LANG_SOURCE([[
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- int main()
- {
- char *shmaddr;
- int id = shmget (IPC_PRIVATE, 4, IPC_CREAT | 0600);
- if (id == -1) return 2;
- shmaddr = shmat (id, 0, 0);
- shmctl (id, IPC_RMID, 0);
- if ((char*) shmat (id, 0, 0) == (char*) -1) {
- shmdt (shmaddr);
- return 1;
- }
- shmdt (shmaddr);
- shmdt (shmaddr);
- return 0;
- }
- ]])],
- [
- AC_DEFINE(IPC_RMID_DEFERRED_RELEASE, 1, Define to 1 if shared memory segments are released deferred.)
- AC_MSG_RESULT(yes)],
- [AC_MSG_RESULT(no)],[AC_MSG_RESULT(assuming no)])
- fi
-
- AC_CHECK_HEADERS([X11/extensions/XShm.h X11/extensions/shmproto.h X11/extensions/shmstr.h], [], [],
- [#include <X11/Xlibint.h>
- #include <X11/Xproto.h>])
-])
-
-CAIRO_ENABLE_SURFACE_BACKEND(xlib_xrender, Xlib Xrender, auto, [
- if test "x$use_xlib" != "xyes"; then
- use_xlib_xrender="no (requires --enable-xlib)"
- else
- dnl Check for Xrender header files if the Xrender package is not installed:
- xlib_xrender_BASE=cairo-xlib
- dnl Keep in sync with meson.build!
- xlib_xrender_REQUIRES="xrender >= 0.6"
- PKG_CHECK_MODULES(xlib_xrender, $xlib_xrender_REQUIRES, ,
- [xlib_xrender_REQUIRES=""
- old_CPPFLAGS=$CPPFLAGS
- CPPFLAGS="$CPPFLAGS $xlib_CFLAGS $xlib_NONPKGCONFIG_CFLAGS"
- AC_CHECK_HEADER(X11/extensions/Xrender.h,
- [xlib_xrender_NONPKGCONFIG_LIBS="-lXrender"],
- [use_xlib_xrender="no (requires $xlib_xrender_REQUIRES https://freedesktop.org/Software/xlibs)"],
- [#include <X11/X.h>])
- CPPFLAGS=$old_CPPFLAGS
- ])
-
- old_CFLAGS=$CFLAGS
- old_LIBS=$LIBS
- CFLAGS="$CFLAGS $xlib_CFLAGS $xlib_NONPKGCONFIG_CFLAGS $xlib_xrender_CFLAGS $xlib_xrender_NONPKGCONFIG_CFLAGS"
- LIBS="$LIBS $xlib_LIBS $xlib_NONPKGCONFIG_LIBS $xlib_xrender_LIBS $xlib_xrender_NONPKGCONFIG_LIBS"
- AC_CHECK_FUNCS([XRenderCreateSolidFill XRenderCreateLinearGradient XRenderCreateRadialGradient XRenderCreateConicalGradient])
- CFLAGS=$old_CFLAGS
- LIBS=$old_LIBS
-
- fi
-])
-
-dnl ===========================================================================
-
-CAIRO_ENABLE_SURFACE_BACKEND(xcb, XCB, auto, [
- dnl Keep in sync with meson.build!
- xcb_REQUIRES="xcb >= 1.6 xcb-render >= 1.6"
- PKG_CHECK_MODULES(xcb, $xcb_REQUIRES, ,
- [use_xcb="no (requires $xcb_REQUIRES https://xcb.freedesktop.org)"])
-])
-
-CAIRO_ENABLE_FUNCTIONS(xlib_xcb, Xlib/XCB, no, [
- if test "x$use_xcb" = "xyes" -a "x$use_xlib" = "xyes"; then
- xlib_xcb_REQUIRES="x11-xcb"
- PKG_CHECK_MODULES(xlib_xcb, $xlib_xcb_REQUIRES, ,
- [use_xlib_xcb="no (requires $xlib_xcb_REQUIRES https://xcb.freedesktop.org)"])
- else
- use_xlib_xcb="no (requires both --enable-xlib and --enable-xcb)"
- fi
-])
-
-CAIRO_ENABLE_FUNCTIONS(xcb_shm, XCB/SHM, auto, [
- if test "x$use_xcb" = "xyes"; then
- xcb_shm_REQUIRES="xcb-shm"
- PKG_CHECK_MODULES(xcb_shm, $xcb_shm_REQUIRES, ,
- [use_xcb_shm="no (requires $xcb_shm https://xcb.freedesktop.org)"])
- else
- use_xcb_shm="no (requires --enable-xcb)"
- fi
-])
-
-dnl ===========================================================================
-
-CAIRO_ENABLE_SURFACE_BACKEND(quartz, Quartz, auto, [
- dnl There is no pkgconfig for quartz; lets do a header check
- AC_CHECK_HEADER(ApplicationServices/ApplicationServices.h, , [use_quartz="no (requires ApplicationServices framework)"])
- AC_CHECK_FUNC([CTFontDrawGlyphs],,[use_quartz_fonts="no (requires Mac OS X 10.7 or later)"])
- if test "x$use_quartz" = "xyes" ; then
- quartz_LIBS="-Xlinker -framework -Xlinker ApplicationServices"
- fi
-])
-
-CAIRO_ENABLE_FONT_BACKEND(quartz_font, Quartz, auto, [
- use_quartz_font=$use_quartz
-])
-
-CAIRO_ENABLE_SURFACE_BACKEND(quartz_image, Quartz Image, no, [
- use_quartz_image=$use_quartz
-])
-
-dnl ===========================================================================
-
-CAIRO_ENABLE_SURFACE_BACKEND(win32, Microsoft Windows, auto, [
- if test "x$have_windows" != xyes; then
- use_win32="no (requires a Win32 platform)"
- fi
- win32_LIBS="-lgdi32 -lmsimg32"
-])
-
-CAIRO_ENABLE_FONT_BACKEND(win32_font, Microsoft Windows, auto, [
- use_win32_font=$use_win32
-])
-
-test_win32_printing=no
-if test "x$use_win32" = "xyes"; then
- AC_CHECK_PROG(GS, gs, gs)
- if test "$GS"; then
- AC_DEFINE([CAIRO_CAN_TEST_WIN32_PRINTING_SURFACE], 1, [Define to 1 if the Win32 Printing backend can be tested (needs ghostscript)])
- test_win32_printing="yes"
- else
- AC_MSG_WARN([Win32 Printing backend will not be tested since ghostscript is not available])
- test_win32_printing="no (requires ghostscript)"
- fi
-fi
-
-AM_CONDITIONAL(CAIRO_CAN_TEST_WIN32_PRINTING_SURFACE, test "x$test_win32_printing" = "xyes")
-
-dnl ===========================================================================
-
-CAIRO_ENABLE_FUNCTIONS(png, PNG, yes, [
- use_png=no
- AC_ARG_VAR([png_REQUIRES], [module name for libpng to search for using pkg-config])
- if test "x$png_REQUIRES" = x; then
- # libpng13 is GnuWin32's libpng-1.2.8 :-(
- for l in libpng libpng14 libpng12 libpng13 libpng10; do
- if $PKG_CONFIG --exists $l ; then
- png_REQUIRES=$l
- use_png=yes
- break
- fi
- done
- else
- use_png=yes
- fi
-
- if test "x$use_png" = "xyes" ; then
- PKG_CHECK_MODULES(png, $png_REQUIRES, , : )
- else
- AC_MSG_WARN([Could not find libpng in the pkg-config search path])
- fi
-])
-
-dnl ===========================================================================
-CAIRO_ENABLE_SURFACE_BACKEND(gl, OpenGL, no, [
- gl_REQUIRES="gl"
- PKG_CHECK_MODULES(gl, $gl_REQUIRES,, [
- dnl Fallback to searching for headers
- AC_CHECK_HEADER(GL/gl.h,, [use_gl="no (gl.pc nor OpenGL headers not found)"])
- if test "x$use_gl" = "xyes"; then
- gl_NONPKGCONFIG_CFLAGS=
- gl_NONPKGCONFIG_LIBS="-lGL"
- fi])
-
- if test "x$have_dl" = "xyes" -a "x$have_dlsym" = "xyes"; then
- gl_LIBS="$gl_LIBS -ldl"
- fi
-
- need_glx_functions=yes
- need_wgl_functions=yes
- need_egl_functions=yes
-])
-
-dnl ===========================================================================
-CAIRO_ENABLE_SURFACE_BACKEND(glesv2, OpenGLESv2, no, [
- glesv2_REQUIRES="glesv2"
- PKG_CHECK_MODULES(glesv2, $glesv2_REQUIRES,, [
- dnl Fallback to searching for headers
- AC_CHECK_HEADER(GLES2/gl2.h,, [use_glesv2="no (glesv2.pc nor OpenGL ES 2.0 headers not found)"])
- if test "x$use_glesv2" = "xyes"; then
- glesv2_NONPKGCONFIG_CFLAGS=
- glesv2_NONPKGCONFIG_LIBS="-lGLESv2"
- fi])
-
- if test "x$have_dl" = "xyes" -a "x$have_dlsym" = "xyes"; then
- glesv2_LIBS="$glesv2_LIBS -ldl"
- fi
-
- if test "x$use_glesv2" = "xyes" -a "x$use_gl" = "xyes"; then
- AC_MSG_ERROR([use either --enable-gl=yes or --enable-glesv2=yes. Not both at the same time.])
- fi
-
- need_egl_functions=yes
-])
-
-dnl ===========================================================================
-CAIRO_ENABLE_SURFACE_BACKEND(glesv3, OpenGLESv3, no, [
- dnl glesv3 is provided via libGLESv2.so, so require glesv2.pc (there is no libGLESv3, nor glesv3.pc)
- glesv3_REQUIRES="glesv2"
- PKG_CHECK_MODULES(glesv3, $glesv3_REQUIRES,, [
- use_glesv3="no (glesv2.pc not found, required for glesv3)"
- ])
-
- dnl Since there is no glesv3.pc, need to search for header files
- AC_CHECK_HEADER(GLES3/gl3.h,, [use_glesv3="no (OpenGL ES 3.0 headers not found)"])
- if test "x$use_glesv3" = "xyes"; then
- glesv3_NONPKGCONFIG_CFLAGS=
- glesv3_NONPKGCONFIG_LIBS="-lGLESv2"
- fi
-
- if test "x$have_dl" = "xyes" -a "x$have_dlsym" = "xyes"; then
- glesv3_LIBS="$glesv3_LIBS -ldl"
- fi
-
- if test "x$use_glesv3" = "xyes" -a "x$use_gl" = "xyes"; then
- AC_MSG_ERROR([use either --enable-gl=yes or --enable-glesv3=yes. Not both at the same time.])
- fi
-
- need_egl_functions=yes
-])
-
-dnl ===========================================================================
-
-CAIRO_ENABLE_FUNCTIONS(egl, EGL, auto, [
- if test "x$need_egl_functions" = "xyes"; then
- egl_REQUIRES="egl"
- PKG_CHECK_MODULES(egl, $egl_REQUIRES, ,
- [egl_REQUIRES=""
- AC_CHECK_HEADER(EGL/egl.h,, [use_egl="no (EGL headers not found)"])
- if test "x$use_egl" = "xyes"; then
- egl_NONPKGCONFIG_CFLAGS=
- egl_NONPKGCONFIG_LIBS=
- save_LIBS="$LIBS"
- other_egl_LIBS=""
- # Temporary workaround for missing link from egl13
- AC_CHECK_LIB(csi, csi_stream_attachresource, other_egl_LIBS="-lcsi")
- LIBS="$other_egl_LIBS $LIBS"
- for egl_lib in EGL egl13 egl12 egl11; do
- if test -z "$egl_NONPKGCONFIG_LIBS"; then
- AC_CHECK_LIB($egl_lib, eglGetError, egl_NONPKGCONFIG_LIBS="-l$egl_lib")
- fi
- done
- if test -z "$egl_NONPKGCONFIG_LIBS"; then
- use_egl="no (EGL library not found)"
- else
- egl_NONPKGCONFIG_LIBS="$egl_NONPKGCONFIG_LIBS $other_egl_LIBS"
- fi
- LIBS="$save_LIBS"
- fi
- ])
- else
- use_egl="no (not required by any backend)"
- fi
-])
-
-CAIRO_ENABLE_FUNCTIONS(glx, GLX, auto, [
- if test "x$need_glx_functions" = "xyes"; then
- save_CFLAGS="$CFLAGS"
- CFLAGS="$CFLAGS $gl_CFLAGS $gl_NONPKGCONFIG_CFLAGS"
- AC_CHECK_HEADER(GL/glx.h,, [use_glx="no (GLX headers not found)"])
- glx_NONPKGCONFIG_CFLAGS=
- glx_NONPKGCONFIG_LIBS="-lGL"
- CFLAGS="$save_CFLAGS"
- else
- use_glx="no (not required by any backend)"
- fi
-])
-
-CAIRO_ENABLE_FUNCTIONS(wgl, WGL, auto, [
- if test "x$need_wgl_functions" = "xyes"; then
- AC_CHECK_HEADER(windows.h,, [use_wgl="no (WGL headers not found)"])
- else
- use_wgl="no (not required by any backend)"
- fi
-])
-
-dnl ===========================================================================
-
-any2ppm_cs=no
-CAIRO_ENABLE_SURFACE_BACKEND(script, script, yes, [
- any2ppm_cs=yes
- # The script backend requires zlib.
- use_script=$have_libz
- script_NONPKGCONFIG_LIBS=-lz
-])
-
-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
-# Requires.private, but at least up to 2003-06-07, there was no
-# freetype2.pc in the release.
-#
-# FreeType versions come in three forms:
-# release (such as 2.1.9)
-# libtool (such as 9.7.3) (returned by freetype-config and pkg-config)
-# platform-specific/soname (such as 6.3.4)
-# and they recommend you never use the platform-specific version
-# (see docs/VERSION.DLL in freetype2 sources)
-#
-# Set these as appropriate:
-
-# release number - for information only
-FREETYPE_MIN_RELEASE=2.1.9
-# libtool-specific version - this is what is checked
-# Keep in sync with meson.build!
-FREETYPE_MIN_VERSION=9.7.3
-
-CAIRO_ENABLE_FONT_BACKEND(ft, FreeType, auto, [
-
- PKG_CHECK_MODULES(FREETYPE, freetype2 >= $FREETYPE_MIN_VERSION,
- [freetype_pkgconfig=yes],
- [freetype_pkgconfig=no])
-
- if test "x$freetype_pkgconfig" = "xyes"; then
- ft_REQUIRES="freetype2 >= $FREETYPE_MIN_VERSION $ft_REQUIRES"
- else
-
- if test -z "$FREETYPE_CONFIG"; then
- AC_PATH_PROG(FREETYPE_CONFIG, freetype-config, no)
- fi
- if test "x$FREETYPE_CONFIG" = "xno" ; then
- use_ft='no (freetype-config not found in path or $FREETYPE_CONFIG)'
- else
- AC_MSG_CHECKING(freetype2 libtool version)
-
- FREETYPE_VERSION=`$FREETYPE_CONFIG --version`
- AX_COMPARE_VERSION([$FREETYPE_VERSION], [gt], [$FREETYPE_MIN_VERSION],
- [AC_MSG_RESULT($FREETYPE_VERSION - OK)
- ft_NONPKGCONFIG_CFLAGS=`$FREETYPE_CONFIG --cflags`
- ft_NONPKGCONFIG_LIBS=`$FREETYPE_CONFIG --libs`],
- [AC_MSG_RESULT($FREETYPE_VERSION - Too old)
- use_ft="no ($FREETYPE_VERSION found; version $FREETYPE_MIN_VERSION from release $FREETYPE_MIN_RELEASE required)"])
- fi
- fi
-
- ft_CFLAGS="$FREETYPE_CFLAGS"
- ft_LIBS="$FREETYPE_LIBS"
-])
-
-# Keep in sync with meson.build!
-FONTCONFIG_MIN_VERSION=2.2.95
-CAIRO_ENABLE_FONT_BACKEND(fc, Fontconfig, auto, [
- use_fc=$use_ft
- if test "x$use_fc" = "xyes"; then
- fc_REQUIRES="fontconfig >= $FONTCONFIG_MIN_VERSION"
- PKG_CHECK_MODULES(FONTCONFIG, $fc_REQUIRES,,
- [use_fc="no (requires $fc_REQUIRES)"])
- fi
- fc_CFLAGS="$FONTCONFIG_CFLAGS"
- fc_LIBS="$FONTCONFIG_LIBS"
-])
-
-if test "x$use_ft" = "xyes"; then
- _save_libs="$LIBS"
- _save_cflags="$CFLAGS"
- LIBS="$LIBS $ft_LIBS"
- CFLAGS="$CFLAGS $ft_CFLAGS"
-
- AC_CHECK_FUNCS(FT_Get_X11_Font_Format FT_GlyphSlot_Embolden FT_GlyphSlot_Oblique FT_Load_Sfnt_Table FT_Library_SetLcdFilter FT_Get_Var_Design_Coordinates FT_Done_MM_Var FT_Palette_Select)
-
- AC_MSG_CHECKING(for FT_HAS_COLOR)
- AC_LINK_IFELSE([AC_LANG_PROGRAM([
-#include <ft2build.h>
-#include FT_FREETYPE_H
-],[
-FT_Long has_color = FT_HAS_COLOR( ((FT_Face)NULL) );
-])],[AC_MSG_RESULT([yes])],[
- AC_DEFINE([FT_HAS_COLOR(x)], [(0)], [Define to (0) if freetype2 does not support color fonts])
- AC_MSG_RESULT([no, disable color font (freetype2 >= 2.5.1 is required)])
-])
-
- LIBS="$_save_libs"
- CFLAGS="$_save_cflags"
-fi
-
-if test "x$use_fc" = "xyes"; then
- CAIRO_CHECK_FUNCS_WITH_FLAGS(FcInit FcFini, [$FONTCONFIG_CFLAGS], [$FONTCONFIG_LIBS])
-fi
-
-dnl ===========================================================================
-
-CAIRO_ENABLE_SURFACE_BACKEND(ps, PostScript, yes, [
- # The ps backend requires zlib.
- use_ps=$have_libz
- ps_NONPKGCONFIG_LIBS=-lz
-])
-
-dnl ===========================================================================
-
-# Keep in sync with meson.build!
-SPECTRE_VERSION_REQUIRED=0.2.0
-test_ps=no
-any2ppm_ps=no
-if test "x$use_ps" = "xyes"; then
- AC_CHECK_PROG(GS, gs, gs)
- if test "$GS"; then
- AC_DEFINE([CAIRO_CAN_TEST_PS_SURFACE], 1, [Define to 1 if the PS backend can be tested (needs ghostscript)])
- test_ps="yes"
- else
- AC_MSG_WARN([PS backend will not be tested since ghostscript is not available])
- test_ps="no (requires ghostscript)"
- fi
-
- libspectre_DEPENDENCY="libspectre >= $SPECTRE_VERSION_REQUIRED"
- PKG_CHECK_MODULES(LIBSPECTRE, $libspectre_DEPENDENCY,
- [any2ppm_ps=yes],
- [test_ps="no (requires libspectre)"])
-fi
-
-AM_CONDITIONAL(CAIRO_CAN_TEST_PS_SURFACE, test "x$test_ps" = "xyes")
-AM_CONDITIONAL(CAIRO_HAS_SPECTRE, test "x$any2ppm_ps" = "xyes")
-if test "x$any2ppm_ps" = "xyes"; then
- AC_DEFINE([CAIRO_HAS_SPECTRE], 1, [Define to 1 if libspectre is available])
-fi
-AC_SUBST(LIBSPECTRE_CFLAGS)
-AC_SUBST(LIBSPECTRE_LIBS)
-
-dnl ===========================================================================
-
-CAIRO_ENABLE_SURFACE_BACKEND(pdf, PDF, yes, [
- # The pdf backend requires zlib.
- use_pdf=$have_libz
- pdf_NONPKGCONFIG_LIBS=-lz
-])
-
-dnl ===========================================================================
-
-# poppler-0.17.4 fixes text-pattern and text-transform
-# Keep in sync with meson.build!
-POPPLER_VERSION_REQUIRED=0.17.4
-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,
- [CAIRO_CHECK_FUNCS_WITH_FLAGS(poppler_page_render, [$POPPLER_CFLAGS], [$POPPLER_LIBS],
- [test_pdf=yes; any2ppm_pdf=yes],
- [test_pdf="no (requires $poppler_DEPENDENCY)"])],
- [test_pdf="no (requires $poppler_DEPENDENCY)"])
- if test "x$test_pdf" = "xyes"; then
- AC_DEFINE([CAIRO_CAN_TEST_PDF_SURFACE], 1, [Define to 1 if the PDF backend can be tested (need poppler and other dependencies for pdf2png)])
- else
- AC_MSG_WARN([PDF backend will not be tested since poppler >= $POPPLER_VERSION_REQUIRED is not available])
- fi
-fi
-
-AM_CONDITIONAL(CAIRO_CAN_TEST_PDF_SURFACE, test "x$test_pdf" = "xyes")
-AC_SUBST(POPPLER_CFLAGS)
-AC_SUBST(POPPLER_LIBS)
-
-AM_CONDITIONAL(CAIRO_HAS_MULTI_PAGE_SURFACES, test "x$use_ps" = "xyes" -o "x$use_pdf" = "xyes")
-
-dnl ===========================================================================
-
-CAIRO_ENABLE_SURFACE_BACKEND(svg, SVG, yes, [
- if test "x$use_png" != "xyes"; then
- use_svg="no (requires --enable-png)"
- fi
-])
-
-dnl Keep in sync with meson.build!
-LIBRSVG_VERSION_REQUIRED=2.35.0
-test_svg=no
-any2ppm_svg=no
-if test "x$use_svg" = "xyes"; then
- librsvg_DEPENDENCY="librsvg-2.0 >= $LIBRSVG_VERSION_REQUIRED"
- PKG_CHECK_MODULES(LIBRSVG, $librsvg_DEPENDENCY gdk-2.0,
- [CAIRO_CHECK_FUNCS_WITH_FLAGS(rsvg_pixbuf_from_file, [$LIBRSVG_CFLAGS], [$LIBRSVG_LIBS],
- [test_svg=yes; any2ppm_svg=yes],
- [test_svg="no (requires $librsvg_DEPENDENCY)"])],
- [test_svg="no (requires $librsvg_DEPENDENCY)"])
- if test "x$test_svg" = "xyes"; then
- AC_DEFINE([CAIRO_CAN_TEST_SVG_SURFACE], 1, [Define to 1 if the SVG backend can be tested])
- else
- AC_MSG_WARN([SVG backend will not be tested since librsvg >= $LIBRSVG_VERSION_REQUIRED is not available])
- fi
-fi
-
-AM_CONDITIONAL(CAIRO_CAN_TEST_SVG_SURFACE, test "x$test_svg" = "xyes")
-AC_SUBST(LIBRSVG_CFLAGS)
-AC_SUBST(LIBRSVG_LIBS)
-
-dnl ===========================================================================
-
-dnl XXX make this a private feature?
-CAIRO_ENABLE(test_surfaces, test surfaces, no)
-
-dnl ===========================================================================
-
-CAIRO_ENABLE_SURFACE_BACKEND(image, image, always, [
- dnl Keep in sync with meson.build!
- pixman_REQUIRES="pixman-1 >= 0.36.0"
- PKG_CHECK_MODULES(pixman, $pixman_REQUIRES, ,
- [use_image="no (requires $pixman_REQUIRES https://cairographics.org/releases/)"])
- image_REQUIRES=$pixman_REQUIRES
- image_CFLAGS=$pixman_CFLAGS
- image_LIBS=$pixman_LIBS
-])
-
-if pkg-config --exists 'pixman-1 >= 0.27.1'; then
- AC_DEFINE([HAS_PIXMAN_GLYPHS], 1, [Enable pixman glyph cache])
-fi
-
-
-dnl ===========================================================================
-
-CAIRO_ENABLE_SURFACE_BACKEND(mime, mime, always)
-CAIRO_ENABLE_SURFACE_BACKEND(recording, recording, always)
-CAIRO_ENABLE_SURFACE_BACKEND(observer, observer, always)
-CAIRO_ENABLE_SURFACE_BACKEND(tee, tee, no)
-CAIRO_ENABLE_SURFACE_BACKEND(xml, xml, no, [
- if test "x$use_png" != "xyes"; then
- use_xml="no (requires --enable-png)"
- else
- use_xml=$have_libz
- xml_NONPKGCONFIG_LIBS=-lz
- fi
-])
-
-dnl ===========================================================================
-
-CAIRO_ENABLE_FONT_BACKEND(user, user, always)
-
-dnl ===========================================================================
-dnl
-dnl This needs to be last on our list of features so that the pthread libs and flags
-dnl gets prefixed in front of everything else in CAIRO_{CFLAGS,LIBS}.
-dnl
-have_real_pthread=no
-have_pthread=no
-CAIRO_ENABLE(pthread, pthread, auto, [CAIRO_CONFIGURE_PTHREAD])
-AM_CONDITIONAL(HAVE_REAL_PTHREAD, test "x$use_pthread" = "xyes" -a "x$have_real_pthread" = "xyes")
-AM_CONDITIONAL(HAVE_PTHREAD, test "x$use_pthread" = "xyes")
-AC_SUBST(pthread_CFLAGS)
-AC_SUBST(pthread_LIBS)
-AC_SUBST(real_pthread_CFLAGS)
-AC_SUBST(real_pthread_LIBS)
-
-
-dnl ===========================================================================
-dnl Build gobject integration library
-
-CAIRO_ENABLE_FUNCTIONS(gobject, gobject, auto, [
- dnl Keep in sync with meson.build!
- gobject_REQUIRES="gobject-2.0 glib-2.0 >= 2.14"
- PKG_CHECK_MODULES(GOBJECT, $gobject_REQUIRES, ,
- [use_gobject="no (requires $gobject_REQUIRES https://download.gnome.org/pub/GNOME/sources/glib/)"])
- gobject_NONPKGCONFIG_EXTRA_LIBS="-L\${libdir} -lcairo-gobject"
-])
-dnl I'm too lazy to fix the caching properly
-if test "x$use_gobject" = "xyes"; then
- PKG_CHECK_MODULES(GOBJECT, $gobject_REQUIRES, : )
-fi
-
-dnl ===========================================================================
-dnl Default to quick testing during development, but force a full test before
-dnl release
-
-AC_ARG_ENABLE(full-testing,
- AS_HELP_STRING([--enable-full-testing],
- [Sets the test suite to perform full testing by default, which
- will dramatically slow down make check, but is a
- *requirement* before release.]), [
-if test "x$enableval" = "xyes"; then
- CAIRO_TEST_MODE=full
- AC_SUBST(CAIRO_TEST_MODE)
-fi
-])
-
-dnl ===========================================================================
-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_cs" = "xyes")
-
-dnl ===========================================================================
-dnl Some utilities need to dlopen the shared libraries, so they need to
-dnl know how libtools will name them
-
-case $host in
-*-*-darwin*)
- SHLIB_EXT="dylib"
- ;;
-*)
- SHLIB_EXT="so"
- ;;
-esac
-AC_DEFINE_UNQUOTED(SHARED_LIB_EXT, "${SHLIB_EXT}", [Shared library file extension])
-AC_SUBST(SHLIB_EXT)
-
-dnl ===========================================================================
-dnl The tracing utility requires LD_PRELOAD, so only build it for systems
-dnl that are known to work.
-
-case $host in
-*-linux*|*-*bsd*|*-solaris*|*-*-darwin*|*-dragonfly*|*-*-gnu*)
- have_ld_preload="yes"
- ;;
-*)
- have_ld_preload="no"
- ;;
-esac
-
-CAIRO_ENABLE(trace, cairo-trace, auto, [
- if test "x$have_ld_preload" != "xyes" -o \
- "x$have_libz" != "xyes" -o \
- "x$have_real_pthread" != "xyes" -o \
- "x$have_dlsym" != "xyes"; then
- use_trace="no (requires dynamic linker and zlib and real pthreads)"
- fi
-])
-
-CAIRO_ENABLE(interpreter, cairo-script-interpreter, yes, [
- if test "x$have_libz" != "xyes"; then
- use_interpreter="no (requires zlib)"
- fi
-])
-
-AC_CHECK_LIB(bfd, bfd_openr,
- [AC_CHECK_HEADER(bfd.h, [have_bfd=yes],
- [have_bfd=no])], [have_bfd=no])
-dnl bfd_section_flags is an inline func so we don't bother with linking the lib in
-AC_LINK_IFELSE([AC_LANG_PROGRAM([
- #include <bfd.h>
- asection *s;
-],[
- return bfd_section_flags(s) == 0;
-])],[],[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
-
-CAIRO_ENABLE(symbol_lookup, symbol-lookup, auto, [
- if test "x$have_bfd" != "xyes"; then
- use_symbol_lookup="no (requires bfd)"
- fi
-])
-
-PKG_CHECK_MODULES(glib, glib-2.0, have_glib=yes, have_glib=no)
-AC_SUBST(glib_CFLAGS)
-AC_SUBST(glib_LIBS)
-AM_CONDITIONAL(BUILD_SPHINX, test "x$have_glib" = "xyes" -a "x$have_windows" = "xno" -a "x$use_png" = "xyes")
-
-save_LIBS="$LIBS"
-AC_CHECK_LIB(rt, shm_open, shm_LIBS="-lrt")
-AC_SUBST(shm_LIBS)
-LIBS="$save_LIBS"
-
-dnl ===========================================================================
-
-AC_ARG_ENABLE(some-floating-point,
- AS_HELP_STRING([--disable-some-floating-point],
- [Disable certain code paths that rely heavily on double precision
- floating-point calculation. This option can improve
- performance on systems without a double precision floating-point
- unit, but might degrade performance on those that do.]), [
-if test "x$enableval" = "xno"; then
- # A value of 'no' for $enableval means that they want to disable, which
- # means 'yes' for $disable_some_floating_point.
- disable_some_floating_point=yes
-fi
-], [disable_some_floating_point=no])
-
-AM_CONDITIONAL(DISABLE_SOME_FLOATING_POINT,
- test "x$disable_some_floating_point" = "xyes")
-if test "x$disable_some_floating_point" = "xyes"; then
- AC_DEFINE(DISABLE_SOME_FLOATING_POINT, 1,
- [Define to 1 to disable certain code paths that rely heavily on
- double precision floating-point calculation])
-fi
-
-dnl ===========================================================================
-
-# We use GTK+ for some utility/debugging tools
-PKG_CHECK_MODULES(gtk, "gtk+-2.0",have_gtk=yes, have_gtk=no)
-AM_CONDITIONAL(HAVE_GTK, test "x$have_gtk" = "xyes")
-
-AC_CONFIG_FILES([
-Makefile
-boilerplate/Makefile
-src/Makefile
-test/Makefile
-test/pdiff/Makefile
-perf/Makefile
-perf/micro/Makefile
-util/Makefile
-util/cairo-fdr/Makefile
-util/cairo-gobject/Makefile
-util/cairo-missing/Makefile
-util/cairo-script/Makefile
-util/cairo-script/examples/Makefile
-util/cairo-sphinx/Makefile
-util/cairo-trace/Makefile
-util/cairo-trace/cairo-trace
-doc/Makefile
-doc/public/Makefile
-])
-AC_CONFIG_COMMANDS([cairo-trace],
- [chmod a+x util/cairo-trace/cairo-trace])
-
-AC_OUTPUT
-CAIRO_REPORT
diff --git a/doc/Makefile.am b/doc/Makefile.am
deleted file mode 100644
index 864a9f1df..000000000
--- a/doc/Makefile.am
+++ /dev/null
@@ -1,7 +0,0 @@
-include $(top_srcdir)/build/Makefile.am.common
-
-SUBDIRS=public
-
-doc:
- cd public && $(MAKE) $(AM_MAKEFLAGS) doc
-.PHONY: doc
diff --git a/doc/bibliography.md b/doc/bibliography.md
new file mode 100644
index 000000000..f3452243a
--- /dev/null
+++ b/doc/bibliography.md
@@ -0,0 +1,103 @@
+# Bibliography
+
+Here's an effort to document some of the academic work that was
+referenced during the implementation of cairo. It is presented in the
+context of operations as they would be performed by either
+`cairo_stroke()` or `cairo_fill()`:
+
+Given a Bézier path, approximate it with line segments:
+
+- The deCasteljau algorithm
+ "Outillages methodes calcul", P de Casteljau, technical
+ report, - Andre Citroen Automobiles SA, Paris, 1959
+
+Note: That technical report might be "hard" to find, but fortunately this
+algorithm will be described in any reasonable textbook on computational
+geometry. Two that have been recommended by cairo contributors are:
+
+- "Computational Geometry, Algorithms and Applications", M. de
+ Berg, M. van Kreveld, M. Overmars, M. Schwarzkopf;
+ Springer-Verlag, ISBN: 3-540-65620-0.
+
+- "Computational Geometry in C (Second Edition)", Joseph O'Rourke,
+ Cambridge University Press, ISBN 0521640105.
+
+Then, if stroking, construct a polygonal representation of the pen
+approximating a circle (if filling skip three steps):
+
+- "Good approximation of circles by curvature-continuous Bezier
+ curves", Tor Dokken and Morten Daehlen, Computer Aided
+ Geometric Design 8 (1990) 22-41.
+
+Add points to that pen based on the initial/final path faces and take the
+convex hull:
+
+- Convex hull algorithm
+
+[Again, see your favorite computational geometry textbook. Should cite the
+name of the algorithm cairo uses here, if it has a name.]
+
+Now, "convolve" the "tracing" of the pen with the tracing of the path:
+
+- "A Kinetic Framework for Computational Geometry", Leonidas
+ J. Guibas, Lyle Ramshaw, and Jorge Stolfi, Proceedings of the
+ 24th IEEE Annual Symposium on Foundations of Computer Science
+ (FOCS), November 1983, 100-111.
+
+The result of the convolution is a polygon that must be filled. A fill
+operations begins here. We use a very conventional Bentley-Ottmann
+pass for computing the intersections, informed by some hints on robust
+implementation courtesy of John Hobby:
+
+- John D. Hobby, Practical Segment Intersection with Finite
+ Precision Output, Computation Geometry Theory and
+ Applications, 13(4), 1999.
+ <http://cm.bell-labs.com/who/hobby/93_2-27.pdf>
+
+Hobby's primary contribution in that paper is his "tolerance square"
+algorithm for robustness against edges being "bent" due to restricting
+intersection coordinates to the grid available by finite-precision
+arithmetic. This is one algorithm we have not implemented yet.
+
+We use a data-structure called Skiplists in the our implementation of
+Bentley-Ottmann:
+
+- W. Pugh, Skip Lists: a Probabilistic Alternative to Balanced Trees,
+ Communications of the ACM, vol. 33, no. 6, pp.668-676, 1990.
+ <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 may want to rasterize
+directly from those edges at some point.
+
+Given the set of tessellated trapezoids, we currently execute a
+straightforward, (and slow), point-sampled rasterization, (and currently
+with a near-pessimal regular 15x17 grid).
+
+We've now computed a mask which gets fed along with the source and
+destination into cairo's fundamental rendering equation. The most basic form
+of this equation is:
+
+ destination = (source IN mask) OP destination
+
+with the restriction that no part of the destination outside the current
+clip region is affected. In this equation, IN refers to the Porter-Duff "in"
+operation, while OP refers to a any user-selected Porter-Duff operator:
+
+- T. Porter & T. Duff, Compositing Digital Images Computer
+ Graphics Volume 18, Number 3 July 1984 pp 253-259
+ <http://keithp.com/~keithp/porterduff/p253-porter.pdf>
diff --git a/doc/public/Makefile.am b/doc/public/Makefile.am
deleted file mode 100644
index b9e31ded0..000000000
--- a/doc/public/Makefile.am
+++ /dev/null
@@ -1,60 +0,0 @@
-include $(top_srcdir)/build/Makefile.am.common
-include $(top_srcdir)/src/Makefile.am.features
-
-# The name of the module.
-DOC_MODULE=cairo
-
-# The top-level SGML file.
-DOC_MAIN_SGML_FILE=cairo-docs.xml
-
-# Extra options to supply to gtkdoc-scan
-SCAN_OPTIONS=--deprecated-guards="CAIRO_DISABLE_DEPRECATED" --ignore-decorators="cairo_public|cairo_private"
-
-# The directory containing the source code.
-DOC_SOURCE_DIR=$(top_srcdir)/src
-
-# Used for dependencies
-HFILE_GLOB=$(top_srcdir)/src/cairo*.h
-CFILE_GLOB=$(top_srcdir)/src/cairo*.c
-EXTRA_HFILES=$(top_builddir)/src/cairo-supported-features.h
-
-# Headers to ignore
-IGNORE_HFILES= \
- cairo-features.h \
- cairo-features-win32.h \
- $(all_cairo_private) \
- $(unsupported_cairo_headers) \
- $(NULL)
-
-# Extra options to supply to gtkdoc-mkdb
-MKDB_OPTIONS=--sgml-mode --output-format=xml --name-space=cairo
-
-# Non-autogenerated SGML files to be included in $(DOC_MAIN_SGML_FILE)
-content_files = \
- language-bindings.xml \
- version.xml \
- $(NULL)
-
-version.xml: $(top_srcdir)/src/cairo-version.h
- echo $(CAIRO_VERSION_MAJOR).$(CAIRO_VERSION_MINOR).$(CAIRO_VERSION_MICRO) > $@
-
-# Images to copy into HTML directory
-HTML_IMAGES =
-
-# Extra options to supply to gtkdoc-fixref
-FIXXREF_OPTIONS=
-
-include $(top_srcdir)/build/Makefile.am.gtk-doc
-
-dist-hook: doc
-
-# This line really belongs in gtk-doc.mk
-$(REPORT_FILES): sgml-build.stamp
-
-if ENABLE_GTK_DOC
-TESTS += check-doc-coverage.sh
-endif
-
-TESTS += check-doc-syntax.sh
-EXTRA_DIST += check-doc-coverage.sh check-doc-syntax.sh
-TESTS_ENVIRONMENT = srcdir="$(srcdir)" top_srcdir="$(top_srcdir)" MAKE="$(MAKE) $(AM_MAKEFLAGS)" DOC_MODULE="$(DOC_MODULE)" REPORT_FILES="$(REPORT_FILES)"
diff --git a/doc/public/cairo-docs.xml b/doc/public/cairo-docs.xml
index b5afa1b90..cc7c9aa04 100644
--- a/doc/public/cairo-docs.xml
+++ b/doc/public/cairo-docs.xml
@@ -43,11 +43,11 @@
<xi:include href="xml/cairo-win32.xml"/>
<xi:include href="xml/cairo-svg.xml"/>
<xi:include href="xml/cairo-quartz.xml" />
- <!--xi:include href="xml/cairo-quartz-image.xml"/-->
<xi:include href="xml/cairo-xcb.xml"/>
<xi:include href="xml/cairo-xlib.xml"/>
<xi:include href="xml/cairo-xlib-xrender.xml"/>
<xi:include href="xml/cairo-script.xml"/>
+ <xi:include href="xml/cairo-surface-observer.xml"/>
</chapter>
<chapter id="cairo-support">
<title>Utilities</title>
@@ -56,32 +56,53 @@
<xi:include href="xml/cairo-version.xml"/>
<xi:include href="xml/cairo-types.xml"/>
</chapter>
- <index id="index-all">
+ <index id="api-index-all">
<title>Index</title>
+ <xi:include href="xml/api-index-full.xml"/>
</index>
- <index id="index-1.2" role="1.2">
+ <!--index id="deprecated-api-index">
+ <title>Index of deprecated symbols</title>
+ <xi:include href="xml/api-index-deprecated.xml"/>
+ </index-->
+ <index id="api-index-1-0">
+ <title>Index of new symbols in 1.0</title>
+ <xi:include href="xml/api-index-1.0.xml"/>
+ </index>
+ <index id="api-index-1-2">
<title>Index of new symbols in 1.2</title>
+ <xi:include href="xml/api-index-1.2.xml"/>
</index>
- <index id="index-1.4" role="1.4">
+ <index id="api-index-1-4">
<title>Index of new symbols in 1.4</title>
+ <xi:include href="xml/api-index-1.4.xml"/>
</index>
- <index id="index-1.6" role="1.6">
+ <index id="api-index-1-6">
<title>Index of new symbols in 1.6</title>
+ <xi:include href="xml/api-index-1.6.xml"/>
</index>
- <index id="index-1.8" role="1.8">
+ <index id="api-index-1-8">
<title>Index of new symbols in 1.8</title>
+ <xi:include href="xml/api-index-1.8.xml"/>
</index>
- <index id="index-1.10" role="1.10">
+ <index id="api-index-1-10">
<title>Index of new symbols in 1.10</title>
+ <xi:include href="xml/api-index-1.10.xml"/>
</index>
- <index id="index-1.12" role="1.12">
+ <index id="api-index-1-12">
<title>Index of new symbols in 1.12</title>
+ <xi:include href="xml/api-index-1.12.xml"/>
</index>
- <index id="index-1.14" role="1.14">
+ <index id="api-index-1-14">
<title>Index of new symbols in 1.14</title>
+ <xi:include href="xml/api-index-1.14.xml"/>
</index>
- <index id="index-1.16" role="1.16">
+ <index id="api-index-1-16">
<title>Index of new symbols in 1.16</title>
+ <xi:include href="xml/api-index-1.16.xml"/>
+ </index>
+ <index id="api-index-1-18">
+ <title>Index of new symbols in 1.18</title>
+ <xi:include href="xml/api-index-1.18.xml"/>
</index>
<xi:include href="language-bindings.xml"/>
</book>
diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt
index 2aeecdca1..5f53fc49c 100644
--- a/doc/public/cairo-sections.txt
+++ b/doc/public/cairo-sections.txt
@@ -30,6 +30,10 @@ cairo_win32_scaled_font_get_device_to_logical
<FILE>cairo-dwrite-fonts</FILE>
CAIRO_HAS_DWRITE_FONT
cairo_dwrite_font_face_create_for_dwrite_fontface
+cairo_dwrite_font_face_get_rendering_params
+cairo_dwrite_font_face_set_rendering_params
+cairo_dwrite_font_face_get_measuring_mode
+cairo_dwrite_font_face_set_measuring_mode
</SECTION>
<SECTION>
@@ -57,6 +61,8 @@ cairo_user_font_face_set_unicode_to_glyph_func
cairo_user_font_face_get_unicode_to_glyph_func
cairo_user_font_face_set_text_to_glyphs_func
cairo_user_font_face_get_text_to_glyphs_func
+cairo_user_scaled_font_get_foreground_marker
+cairo_user_scaled_font_get_foreground_source
</SECTION>
<SECTION>
@@ -160,6 +166,8 @@ CAIRO_HAS_QUARTZ_SURFACE
cairo_quartz_surface_create
cairo_quartz_surface_create_for_cg_context
cairo_quartz_surface_get_cg_context
+cairo_quartz_image_surface_create
+cairo_quartz_image_surface_get_image
</SECTION>
<SECTION>
@@ -513,6 +521,14 @@ cairo_font_options_set_hint_metrics
cairo_font_options_get_hint_metrics
cairo_font_options_get_variations
cairo_font_options_set_variations
+cairo_color_mode_t
+cairo_font_options_set_color_mode
+cairo_font_options_get_color_mode
+CAIRO_COLOR_PALETTE_DEFAULT
+cairo_font_options_set_color_palette
+cairo_font_options_get_color_palette
+cairo_font_options_set_custom_palette_color
+cairo_font_options_get_custom_palette_color
</SECTION>
<SECTION>
@@ -670,6 +686,8 @@ cairo_show_page
cairo_get_reference_count
cairo_set_user_data
cairo_get_user_data
+cairo_set_hairline
+cairo_get_hairline
<SUBSECTION Private>
cairo_public
CAIRO_BEGIN_DECLS
diff --git a/doc/public/language-bindings.xml b/doc/public/language-bindings.xml
index a00a00448..1d04ec018 100644
--- a/doc/public/language-bindings.xml
+++ b/doc/public/language-bindings.xml
@@ -423,14 +423,6 @@ public void writeToPNG (OutputStream stream) throws IOException;
operations do nothing. Retrieving the status of the
singleton object returns <constant>CAIRO_STATUS_NO_MEMORY</constant>
</para>
- <remark>
- Is this going to apply to
- <type>cairo_surface_t</type> as well?
- </remark>
- <remark>
- What about cairo_copy_path_data()? It's probably going to
- have to return <constant>NULL</constant>.
- </remark>
</listitem>
<listitem><para>
Errors propagate from object to object. Setting a pattern
@@ -438,8 +430,6 @@ public void writeToPNG (OutputStream stream) throws IOException;
<type>cairo_t</type> puts the type into an error state.
</para></listitem>
</itemizedlist>
- <remark>Much of the above is not yet implemented at the time of
- this writing</remark>
<para>
A language binding could copy the C approach, and for a
language without exceptions, this is likely the right thing
diff --git a/doc/public/meson.build b/doc/public/meson.build
index 31168f268..278ef4703 100644
--- a/doc/public/meson.build
+++ b/doc/public/meson.build
@@ -98,7 +98,6 @@ ignore_headers = [
'cairo-svg-surface-private.h',
'cairo-tag-attributes-private.h',
'cairo-tag-stack-private.h',
- 'cairo-tee-surface-private.h',
'cairo-time-private.h',
'cairo-traps-private.h',
'cairo-tristrip-private.h',
@@ -140,6 +139,7 @@ gnome.gtkdoc('cairo',
'--ignore-decorators=' + '|'.join(ignore_decorators),
'--ignore-headers=' + ' '.join(ignore_headers),
],
+ mkdb_args: ['--source-suffixes=h,c,cpp'],
content_files: [
'language-bindings.xml',
],
diff --git a/doc/releasing.md b/doc/releasing.md
new file mode 100644
index 000000000..ab5abb62b
--- /dev/null
+++ b/doc/releasing.md
@@ -0,0 +1,175 @@
+# Releasing Cairo
+
+Here are the steps to follow to create a new cairo release:
+
+## 0. Decide type of release and checkout the appropriate branch
+
+The Cairo project makes three types of releases: Development snapshot
+releases, stable minor releases, and stable micro (aka "point") releases.
+Micro releases should be only bugfixes and no API additions. If there are
+API additions consider making a Minor release. Snapshot releases can be
+done of the current development tree between Minor releases, as desired.
+
+For stable releases (both minor and micro), the work should be done on the
+given release branch. E.g. for 1.14.12, check out the 1.14 branch via "git
+checkout origin/1.14 -b 1.14".
+
+## 1. Ensure that there are no local, uncommitted/unpushed mods
+
+You're probably in a good state if both "git diff HEAD" and "git log
+master..origin/master" give no output.
+
+## 2. Verify that the code passes `meson dist`
+
+First, make sure you have 'nm' and 'readelf' commands in `PATH`. this
+should be OK with any Linux distro.
+
+Running "meson dist" should result in no warnings or errors and end with a
+message of the form:
+
+ Created source/cairo/_build/meson-dist/cairo-1.17.8.tar.xz
+
+If the test suite does not pass, you can use:
+
+ meson dist --no-tests
+
+But this should only be allowed for development snapshots. Please, always
+check the state of the CI pipeline on GitLab.
+
+## 3. Decide what the new version number for the release will be.
+
+Cairo uses even numbers for official releases, and odd numbers for
+development snapshots. Thus, for a Minor release it would be:
+
+ LAST_RELEASE="X.Y.Z" # e.g. 1.12.0
+ THIS_RELEASE="X.Y+2.0" # e.g. 1.14.0
+
+While for a Micro release the version numbers should be:
+
+ LAST_RELEASE="X.Y.Z" # e.g. 1.14.0
+ THIS_RELEASE="X.Y.Z+2" # e.g. 1.14.2
+
+Snapshots are similar but have odd minor versions. Also, the first snapshot
+release in a new series will be .2 rather than .0, e.g.:
+
+ LAST_RELEASE="X.Y.Z" # e.g. 1.14.0
+ THIS_RELEASE="X.Y+1.0" # e.g. 1.15.2
+
+and subsequent snapshots in that series are just normal micro releases:
+
+ LAST_RELEASE="X.Y.Z" # e.g. 1.15.2
+ THIS_RELEASE="X.Y.Z+2" # e.g. 1.15.4
+
+## 4. Fill out an entry in the NEWS file
+
+Sift through the logs since the last release. This is most easily done with
+a command such as:
+
+ git log --stat ${LAST_RELEASE}..
+
+Summarize major changes briefly in a style similar to other entries in NEWS.
+Take special care to note any additions in the API. These should be easy to
+find by noting modifications to .h files in the log command above. And more
+specifically, the following command will show each patch that has changed a
+public header file since the given version:
+
+```
+find src/ -name '*.h' ! -name '*-private.h' \
+ ! -name 'cairoint.h' ! -name 'cairo-*features*.h' | \
+ xargs git diff ${LAST_RELEASE}.. --
+```
+
+
+## 5. Increment `CAIRO_VERSION_{MINOR|MICRO}` in `src/cairo-version.h`:
+
+If there are backward-incompatible changes in the API, stop now and don't
+release. Go back and fix the API instead. Cairo is intended to remain
+backwards-compatible as far as API.
+
+So `CAIRO_VERSION_MAJOR` will not be incremented unless we come up with a
+new versioning scheme to take advantage of it.
+
+If there are API additions, then increment `CAIRO_VERSION_MINOR` and reset
+`CAIRO_VERSION_MICRO` to 0. **NOTE**: The minor version is only incremented
+for releases, not for snapshots.
+
+Otherwise, (i.e. there are only bug fixes), increment `CAIRO_VERSION_MICRO`
+to the next larger (even) number.
+
+## 6. For Minor releases, add an index entry to `doc/public/cairo-docs.xml`
+
+Towards the end of the file, add a new section for the stable release.
+It'll look something like:
+
+```xml
+<index id="api-index-X-Y">
+ <title>Index of new symbols in X.Y</title>
+ <xi:include href="xml/api-index-X.Y.xml"/>
+</index>
+```
+
+## 7. Commit the changes to `NEWS` and `src/cairo-version.h`
+
+It's especially important to mention the new version number in your commit
+log.
+
+## 8. Generate the release archive
+
+The `meson dist` command will:
+
+ * Generate the final tar file
+ * Generate an sha1sum file
+
+Once you have the release archive you will need to:
+
+ * Sign the sha1sum using your GPG setup (asks for your GPG password)
+ * `scp` the three files to appear on https://cairographics.org/releases
+ * Generate a versioned manual and upload it to appear as both:
+ - `https://cairographics.org/manual-${THIS_RELEASE}`
+ - `https://cairographics.org/manual`
+ * Place local copies of the three files in the releases directory
+ * Create a `LATEST-{package_version}` file (after deleting any old one)
+ * Tag the entire source tree with a `${THIS_RELEASE}` tag, and sign the
+ tag with your GPG key (asks for your GPG password, and you may need to
+ set `GIT_COMMITTER_NAME` and `GIT_COMMITTER_EMAIL` to match your
+ public-key's setting or this fails.)
+ * Provide some text for the release announcement (see below).
+
+## 9. Update master (or the stable branch) version number.
+
+For Micro releases (X.Y.Z+2), increment `CAIRO_VERSION_MICRO` to the next
+larger (odd) number in `src/cairo-version.h`.
+
+ DEVEL_VERSION="X.Y.Z+1" # e.g. 1.15.10 -> 1.15.11
+
+For Minor releases (X.Y.0), increment `CAIRO_VERSION_MINOR` to the next
+larger (odd) number, and set `CAIRO_VERSION_MICRO` to 1.
+
+ DEVEL_VERSION="X.Y.Z+1" # e.g. 1.16.0 -> 1.17.1
+
+Then, commit:
+
+ git commit src/cairo-version.h -m "Bump version for ${DEVEL_VERSION}"
+
+## 9. Push the new tag out
+
+Use:
+
+ git push --atomic origin master ${THIS_RELEASE}
+
+to ensure that both the tag and the latest changes in your tree are uploaded
+at the same time.
+
+## 10. Send out an announcement message.
+
+Send a message to cairo-announce@cairographics.org and CC
+cairo@cairographics.org, and ftp-release@lists.freedesktop.org (pr@lwn.net
+as well for major releases) to announce the release, adding the excerpt from
+NEWS and the shortlog of all changes since last release, generated by:
+
+ git shortlog ${LAST_RELEASE}...
+
+## 11. Add the announcement to the website
+
+Add a new entry in the `news` directory. It will automatically get indexed
+onto the homepage when the site refreshes.
diff --git a/meson-cc-tests/fuzzer.c b/meson-cc-tests/fuzzer.c
new file mode 100644
index 000000000..0ae4a3101
--- /dev/null
+++ b/meson-cc-tests/fuzzer.c
@@ -0,0 +1,7 @@
+#include <stddef.h>
+#include <stdint.h>
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ return 0;
+}
diff --git a/meson.build b/meson.build
index 970f49a52..c5a65cd33 100644
--- a/meson.build
+++ b/meson.build
@@ -4,8 +4,8 @@ project('cairo', 'c', 'cpp',
default_options: ['warning_level=2'],
)
-# Keep in sync with configure.ac!
freetype_required_version = '>= 9.7.3'
+freetype_colrv1_required_version = '>= 25.0.19'
fontconfig_required_version = '>= 2.2.95'
xrender_required_version = '>= 0.6'
xcb_required_version = '>= 1.6'
@@ -69,7 +69,7 @@ if cc.get_id() != 'msvc'
]
if get_option('optimization') in ['1', '2', '3']
- cflags += ['-Wp,-D_FORTIFY_SOURCE=2', '-Wl,-lssp']
+ cflags += '-Wp,-D_FORTIFY_SOURCE=2'
endif
supported_cflags = cc.get_supported_arguments(cflags)
@@ -97,9 +97,6 @@ endif
add_project_arguments('-D_GNU_SOURCE', language: 'c')
-# Autotools compatibility
-add_project_arguments('-DHAVE_CONFIG_H', language: 'c')
-
# Make sure source directory hasn't been configured with autotools
fs = import('fs')
if fs.exists('config.h') or fs.exists('src/cairo-features.h') or fs.exists('src/cairo-supported-features.h')
@@ -302,6 +299,8 @@ if fontconfig_dep.found()
}]
endif
+ttx = find_program('ttx', required: false)
+
freetype_dep = dependency('freetype2',
required: get_option('freetype'),
version: freetype_required_version,
@@ -337,6 +336,16 @@ if freetype_dep.found()
if not cc.links(files('meson-cc-tests/ft_has_color.c'), dependencies: freetype_dep, name: 'FT has color')
conf.set('FT_HAS_COLOR', '(0)')
endif
+ if cc.has_type('FT_SVG_Document', dependencies: freetype_dep, prefix: '#include <freetype/otsvg.h>')
+ conf.set('HAVE_FT_SVG_DOCUMENT', 1)
+ if ttx.found()
+ conf.set('CAIRO_CAN_TEST_TTX_FONT', 1)
+ endif
+ endif
+ if freetype_dep.version().version_compare(freetype_colrv1_required_version) and \
+ cc.has_function('FT_Get_Color_Glyph_Paint', dependencies: freetype_dep)
+ conf.set('HAVE_FT_COLR_V1', 1)
+ endif
check_funcs += ft_check_funcs
deps += [freetype_dep]
endif
@@ -482,6 +491,8 @@ if host_machine.system() == 'darwin' and not get_option('quartz').disabled()
endif
if host_machine.system() == 'windows'
+ add_project_arguments('-DWIN32_LEAN_AND_MEAN', '-DNOMINMAX', language: ['c', 'cpp'])
+
win32_extra_deps = [
cc.find_library('gdi32'),
cc.find_library('msimg32'),
@@ -506,19 +517,18 @@ if host_machine.system() == 'windows'
]
cpp_compiler = meson.get_compiler('cpp')
- d2d_dep = cpp_compiler.find_library('d2d1', required: false)
- dwrite_dep = cpp_compiler.find_library('dwrite', required: false)
+ d2d_dep = cpp_compiler.find_library('d2d1', required: get_option('dwrite'))
+ dwrite_dep = cpp_compiler.find_library('dwrite', required: get_option('dwrite'))
d2d_header = cpp_compiler.has_header('d2d1.h')
d2d_3_header = cpp_compiler.has_header('d2d1_3.h')
dwrite_header = cpp_compiler.has_header('dwrite.h')
- dwrite_3_header = cpp_compiler.has_header('dwrite_3.h')
- wincodec_dep = cpp_compiler.find_library('windowscodecs', required: false)
+ wincodec_dep = cpp_compiler.find_library('windowscodecs', required: get_option('dwrite'))
wincodec_header = cpp_compiler.has_header('wincodec.h')
if d2d_dep.found() and dwrite_dep.found() and d2d_header and dwrite_header and wincodec_dep.found() and wincodec_header
feature_conf.set('CAIRO_HAS_DWRITE_FONT', 1)
built_features += [{
- 'name': 'cairo-win32-dwrite-font',
+ 'name': 'cairo-dwrite-font',
'description': 'Microsoft Windows DWrite font backend',
'deps': [dwrite_dep, d2d_dep, wincodec_dep],
}]
@@ -528,139 +538,9 @@ if host_machine.system() == 'windows'
conf.set('HAVE_D2D1_3_H', 1)
endif
- # Exclude MinGW dwrite_3.h because it has a broken definition of DWRITE_COLOR_GLYPH_RUN1.
- if cpp_compiler.has_header('dwrite_3.h') and cpp_compiler.get_define('__MINGW32__') == ''
- conf.set('HAVE_DWRITE_3_H', 1)
- endif
- endif
-endif
-
-# GL / GLESV2 / GLESV3 are mutually exclusive
-gl_backend = get_option('gl-backend')
-need_egl_functions = false
-need_wgl_functions = false
-need_glx_functions = false
-
-if gl_backend in ['auto', 'gl']
- gl_dep = dependency('gl', required: false)
- if not gl_dep.found()
- gl_dep = cc.find_library('GL', required: gl_backend == 'gl')
- endif
- if gl_dep.found() and \
- cc.has_header('GL/gl.h', required: gl_backend == 'gl', dependencies: gl_dep) and \
- cc.has_header('GL/glext.h', required: gl_backend == 'gl', dependencies: gl_dep)
- deps += [gl_dep]
-
- need_egl_functions = true
- need_wgl_functions = true
- need_glx_functions = true
-
- feature_conf.set('CAIRO_HAS_GL_SURFACE', 1)
- built_features += [{
- 'name': 'cairo-gl',
- 'description': 'OpenGL surface backend',
- 'deps': [gl_dep],
- }]
- endif
-endif
-
-if feature_conf.get('CAIRO_HAS_GL_SURFACE', 0) == 0 and ['auto', 'glesv2'].contains(gl_backend)
- glesv2_dep = dependency('glesv2', required: false)
- if not glesv2_dep.found()
- glesv2_dep = cc.find_library('GLESv2', required: gl_backend == 'glesv2')
- endif
- if glesv2_dep.found() and \
- cc.has_header('GLES2/gl2.h', required: gl_backend == 'glesv2', dependencies: glesv2_dep) and \
- cc.has_header('GLES2/gl2ext.h', required: gl_backend == 'glesv2', dependencies: glesv2_dep)
- deps += [glesv2_dep]
- need_egl_functions = true
-
- feature_conf.set('CAIRO_HAS_GLESV2_SURFACE', 1)
- built_features += [{
- 'name': 'cairo-glesv2',
- 'source-key': 'cairo-gl',
- 'description': 'OpenGLESv2 surface backend',
- 'deps': [glesv2_dep],
- }]
- endif
-endif
-
-if feature_conf.get('CAIRO_HAS_GL_SURFACE', 0) == 0 and feature_conf.get('CAIRO_HAS_GLESV2_SURFACE', 0) == 0 and ['auto', 'glesv3'].contains(gl_backend)
- # glesv3 is provided via libGLESv2.so (there is no libGLESv3, nor glesv3.pc)
- glesv3_dep = dependency('glesv2', required: false)
- if not glesv3_dep.found()
- glesv3_dep = cc.find_library('GLESv2', required: gl_backend == 'glesv3')
- endif
-
- if glesv3_dep.found() and \
- cc.has_header('GLES3/gl3.h', required: gl_backend == 'glesv3', dependencies: glesv3_dep) and \
- cc.has_header('GLES3/gl3ext.h', required: gl_backend == 'glesv3', dependencies: glesv3_dep)
- deps += [glesv3_dep]
- need_egl_functions = true
-
- feature_conf.set('CAIRO_HAS_GLESV3_SURFACE', 1)
- built_features += [{
- 'name': 'cairo-glesv3',
- 'source-key': 'cairo-gl',
- 'description': 'OpenGLESv3 surface backend',
- 'deps': [glesv3_dep],
- }]
- endif
-endif
-
-if need_egl_functions
- # FIXME: automagic
- egl_extra_deps = []
- egl_dep = dependency('egl', required: false)
- if not egl_dep.found()
- if cc.has_header('EGL/egl.h')
- csi_dep = cc.find_library('csi', required: false)
- if csi_dep.found() and cc.has_function('csi_stream_attachresource', dependencies: [csi_dep])
- egl_extra_deps += csi_dep
- endif
-
- foreach libname : ['EGL', 'egl13', 'egl12', 'egl11']
- dep = cc.find_library(libname, required: false)
- if dep.found() and cc.has_function('eglGetError', dependencies: [dep])
- egl_dep = dep
- break
- endif
- endforeach
- endif
- endif
-
- if egl_dep.found()
- deps += egl_dep
- feature_conf.set('CAIRO_HAS_EGL_FUNCTIONS', 1)
- built_features += [{
- 'name': 'cairo-egl',
- 'description': 'EGL functions',
- 'deps': [egl_dep] + egl_extra_deps,
- }]
- endif
-endif
-
-if need_glx_functions
- # FIXME: automagic
- if cc.has_header('GL/glx.h')
- feature_conf.set('CAIRO_HAS_GLX_FUNCTIONS', 1)
- built_features += [{
- 'name': 'cairo-glx',
- 'description': 'GLX functions',
- 'deps': [cc.find_library('GL')],
- }]
- endif
-endif
-
-# Untested
-if need_wgl_functions
- # FIXME: automagic
- if cc.has_header('windows.h')
- feature_conf.set('CAIRO_HAS_WGL_FUNCTIONS', 1)
- built_features += [{
- 'name': 'cairo-wgl',
- 'description': 'WGL functions',
- }]
+ add_project_arguments('-DWINVER=_WIN32_WINNT_WIN10', '-D_WIN32_WINNT=_WIN32_WINNT_WIN10', '-DNTDDI_VERSION=NTDDI_WIN10_RS3', language: ['c', 'cpp'])
+ else
+ add_project_arguments('-DWINVER=_WIN32_WINNT_WIN2K', '-D_WIN32_WINNT=_WIN32_WINNT_WIN2K', language: ['c', 'cpp'])
endif
endif
@@ -708,15 +588,6 @@ if zlib_dep.found()
conf.set('CAIRO_HAS_INTERPRETER', 1)
endif
-if zlib_dep.found() and png_dep.found() and get_option('xml').enabled()
- feature_conf.set('CAIRO_HAS_XML_SURFACE', 1)
- built_features += [{
- 'name': 'cairo-xml',
- 'description': 'XML surface backend',
- 'deps': [zlib_dep],
- }]
-endif
-
bfd_dep = cc.find_library('bfd', has_headers: ['bfd.h'], required: get_option('symbol-lookup'))
if bfd_dep.found() and \
cc.has_function('bfd_openr', dependencies: [bfd_dep]) and \
@@ -952,7 +823,6 @@ summary({
'Observer': true,
'Mime': true,
'Tee': feature_conf.get('CAIRO_HAS_TEE_SURFACE', 0) == 1,
- 'XML': feature_conf.get('CAIRO_HAS_XML_SURFACE', 0) == 1,
'Xlib': feature_conf.get('CAIRO_HAS_XLIB_SURFACE', 0) == 1,
'Xlib Xrender': feature_conf.get('CAIRO_HAS_XLIB_XRENDER_SURFACE', 0) == 1,
'Quartz': feature_conf.get('CAIRO_HAS_QUARTZ_SURFACE', 0) == 1,
@@ -963,9 +833,6 @@ summary({
'PostScript': feature_conf.get('CAIRO_HAS_PS_SURFACE', 0) == 1,
'PDF': feature_conf.get('CAIRO_HAS_PDF_SURFACE', 0) == 1,
'SVG': feature_conf.get('CAIRO_HAS_SVG_SURFACE', 0) == 1,
- 'OpenGL': feature_conf.get('CAIRO_HAS_GL_SURFACE', 0) == 1,
- 'OpenGL ES 2.0': feature_conf.get('CAIRO_HAS_GLESV2_SURFACE', 0) == 1,
- 'OpenGL ES 3.0': feature_conf.get('CAIRO_HAS_GLESV3_SURFACE', 0) == 1,
}, section: 'Surface Backends', bool_yn: true)
summary({
@@ -979,9 +846,6 @@ summary({
summary({
'PNG functions': feature_conf.get('CAIRO_HAS_PNG_FUNCTIONS', 0) == 1,
- 'GLX functions': feature_conf.get('CAIRO_HAS_GLX_FUNCTIONS', 0) == 1,
- 'WGL functions': feature_conf.get('CAIRO_HAS_WGL_FUNCTIONS', 0) == 1,
- 'EGL functions': feature_conf.get('CAIRO_HAS_EGL_FUNCTIONS', 0) == 1,
'X11-xcb': feature_conf.get('CAIRO_HAS_XLIB_XCB_FUNCTIONS', 0) == 1,
'XCB-shm': feature_conf.get('CAIRO_HAS_XCB_SHM_FUNCTIONS', 0) == 1,
}, section: 'Functions', bool_yn: true)
diff --git a/meson_options.txt b/meson_options.txt
index ebc65c77e..5b96940dd 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -1,20 +1,15 @@
# Cairo font backends
+option('dwrite', type : 'feature', value : 'auto')
option('fontconfig', type : 'feature', value : 'auto')
option('freetype', type : 'feature', value : 'auto')
# Cairo surface backends
-option('gl-backend', type : 'combo', value : 'disabled',
- # FIXME: https://github.com/mesonbuild/meson/issues/4566
- choices : ['auto', 'gl', 'glesv2', 'glesv3', 'disabled'])
-option('glesv2', type : 'feature', value : 'disabled')
-option('glesv3', type : 'feature', value : 'disabled')
option('png', type : 'feature', value : 'auto') # png and svg surfaces
option('quartz', type : 'feature', value : 'auto')
option('tee', type : 'feature', value : 'disabled')
option('xcb', type : 'feature', value : 'auto')
option('xlib', type : 'feature', value : 'auto')
option('xlib-xcb', type : 'feature', value : 'disabled')
-option('xml', type : 'feature', value : 'disabled')
option('zlib', type : 'feature', value : 'auto') # script, ps, pdf, xml surfaces
# Tests
@@ -32,8 +27,3 @@ option('symbol-lookup', type: 'feature', value : 'auto',
# Documentation
option('gtk_doc', type : 'boolean', value : false,
description: 'Build the Cairo API reference (depends on gtk-doc)')
-
-# FIXME: implement these to avoid automagic
-#option('egl', type : 'feature', value : 'auto')
-#option('glx', type : 'feature', value : 'auto')
-#option('wgl', type : 'feature', value : 'auto')
diff --git a/perf/Makefile.am b/perf/Makefile.am
deleted file mode 100644
index 40b35bc38..000000000
--- a/perf/Makefile.am
+++ /dev/null
@@ -1,154 +0,0 @@
-include $(top_srcdir)/build/Makefile.am.common
-
-include $(top_srcdir)/perf/Makefile.sources
-
-AM_CPPFLAGS = \
- -I$(srcdir) \
- -I$(top_srcdir)/boilerplate \
- -I$(top_srcdir)/src \
- -I$(top_srcdir)/util/cairo-missing \
- -I$(top_srcdir)/util/cairo-script \
- -I$(top_builddir)/src \
- $(CAIRO_CFLAGS)
-
-AM_LDFLAGS = $(CAIRO_LDFLAGS)
-
-SUBDIRS = micro
-
-noinst_PROGRAMS = \
- cairo-analyse-trace \
- cairo-perf-trace \
- cairo-perf-micro \
- $(NULL)
-
-EXTRA_PROGRAMS += \
- cairo-analyse-trace \
- cairo-perf-micro \
- cairo-perf-trace \
- cairo-perf-diff-files \
- cairo-perf-print \
- cairo-perf-chart \
- cairo-perf-compare-backends \
- cairo-perf-graph-files \
- $(NULL)
-EXTRA_DIST += cairo-perf-diff COPYING
-EXTRA_LTLIBRARIES += libcairoperf.la
-
-LDADD = libcairoperf.la \
- $(top_builddir)/boilerplate/libcairoboilerplate.la \
- $(top_builddir)/src/libcairo.la
-
-cairo_perf_micro_SOURCES = $(cairo_perf_micro_sources)
-cairo_perf_micro_LDADD = \
- $(top_builddir)/perf/micro/libcairo-perf-micro.la \
- $(LDADD)
-cairo_perf_micro_DEPENDENCIES = \
- $(top_builddir)/perf/micro/libcairo-perf-micro.la \
- $(LDADD)
-
-libcairoperf_la_SOURCES = \
- $(libcairoperf_sources) \
- $(libcairoperf_external_sources) \
- $(libcairoperf_headers) \
- $(NULL)
-
-cairo_analyse_trace_SOURCES = \
- $(cairo_analyse_trace_sources) \
- $(cairo_analyse_trace_external_sources)
-cairo_analyse_trace_LDADD = \
- $(top_builddir)/util/cairo-script/libcairo-script-interpreter.la \
- $(top_builddir)/util/cairo-missing/libcairo-missing.la \
- $(LDADD)
-cairo_analyse_trace_DEPENDENCIES = \
- $(top_builddir)/util/cairo-script/libcairo-script-interpreter.la \
- $(top_builddir)/util/cairo-missing/libcairo-missing.la \
- $(LDADD)
-
-cairo_perf_trace_SOURCES = \
- $(cairo_perf_trace_sources) \
- $(cairo_perf_trace_external_sources)
-cairo_perf_trace_LDADD = \
- $(top_builddir)/util/cairo-script/libcairo-script-interpreter.la \
- $(top_builddir)/util/cairo-missing/libcairo-missing.la \
- $(LDADD)
-cairo_perf_trace_DEPENDENCIES = \
- $(top_builddir)/util/cairo-script/libcairo-script-interpreter.la \
- $(top_builddir)/util/cairo-missing/libcairo-missing.la \
- $(LDADD)
-
-cairo_perf_diff_files_SOURCES = $(cairo_perf_diff_files_sources)
-cairo_perf_print_SOURCES = $(cairo_perf_print_sources)
-cairo_perf_chart_SOURCES = $(cairo_perf_chart_sources)
-cairo_perf_compare_backends_SOURCES = $(cairo_perf_compare_backends_sources)
-
-cairo_perf_graph_files_SOURCES = \
- $(cairo_perf_graph_files_sources) \
- $(cairo_perf_graph_files_headers)
-cairo_perf_graph_files_CFLAGS = @gtk_CFLAGS@
-cairo_perf_graph_files_LDADD = @gtk_LIBS@ $(LDADD)
-
-# Install rules to rebuild the libraries and add explicit dependencies
-$(top_builddir)/perf/micro/libcairo-perf-micro.la:
- cd $(top_builddir)/perf/micro && $(MAKE) $(AM_MAKEFLAGS) libcairo-perf-micro.la
-
-$(top_builddir)/boilerplate/libcairoboilerplate.la: $(top_builddir)/src/libcairo.la
- cd $(top_builddir)/boilerplate && $(MAKE) $(AM_MAKEFLAGS) libcairoboilerplate.la
-
-$(top_builddir)/src/libcairo.la:
- cd $(top_builddir)/src && $(MAKE) $(AM_MAKEFLAGS) libcairo.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
-
-
-# Do a funny transition of CAIRO_TEST_TARGET through TARGETS such that
-# one can limit tested targets both through CAIRO_TEST_TARGET env var
-# and TARGETS make var on the command line. Same for the rest.
-TARGETS = $(CAIRO_TEST_TARGET)
-TARGETS_EXCLUDE = $(CAIRO_TEST_TARGET_EXCLUDE)
-FORMAT = $(CAIRO_TEST_TARGET_FORMAT)
-ITERS = $(CAIRO_PERF_ITERATIONS)
-
-CAIRO_PERF_ENVIRONMENT = CAIRO_PERF_ITERATIONS="$(ITERS)" CAIRO_TEST_TARGET="$(TARGETS)" CAIRO_TEST_TARGET_FORMAT="$(FORMAT)" CAIRO_TEST_TARGET_EXCLUDE="$(TARGETS_EXCLUDE)"
-
-perf: cairo-perf-micro$(EXEEXT) cairo-perf-trace$(EXEEXT)
- -$(CAIRO_PERF_ENVIRONMENT) ./cairo-perf-micro$(EXEEXT)
- -$(CAIRO_PERF_ENVIRONMENT) ./cairo-perf-trace$(EXEEXT)
-
-html-local: index.html
-
-perf-tag.html : cairo-perf-micro${EXEEXT}
- $(CAIRO_PERF_ENVIRONMENT) ./cairo-perf-diff -t -h $@ `git describe --abbrev=0` HEAD
-perf-commit.html : cairo-perf-micro${EXEEXT}
- $(CAIRO_PERF_ENVIRONMENT) ./cairo-perf-diff -t -h $@ HEAD
-
-# Summarise changes in index.html, with details in links
-index.html: perf-tag.html perf-commit.html
- echo "<html><head><title>Performance Changes</title></head><body>Against <a href=\"perf-tag.html\">"`git describe --abbrev=0`"</a><br><a href=\"perf-commit.html\">Latest commit</a></body>" > $@
-
-EXTRA_VALGRIND_FLAGS = $(CAIRO_EXTRA_VALGRIND_FLAGS)
-VALGRIND_MEMCHECK_FLAGS = \
- --tool=memcheck \
- --suppressions=$(top_srcdir)/test/.valgrind-suppressions \
- --leak-check=yes --show-reachable=yes
-VALGRIND_CALLGRIND_FLAGS = \
- --tool=callgrind
-CLEANFILES += \
- valgrind-log \
- callgrind.out.* \
- index.html
-
-perf-valgrind:
- $(MAKE) $(AM_MAKEFLAGS) perf \
- $(top_builddir)/libtool --mode=execute \
- valgrind $(VALGRIND_MEMCHECK_FLAGS) $(EXTRA_VALGRIND_FLAGS)' \
- | tee valgrind-log
-
-perf-callgrind:
- $(MAKE) $(AM_MAKEFLAGS) perf \
- $(top_builddir)/libtool --mode=execute \
- valgrind $(VALGRIND_CALLGRIND_FLAGS) $(EXTRA_VALGRIND_FLAGS)'
-
-.PHONY: perf perf-valgrind perf-callgrind
-
-EXTRA_DIST += Makefile.win32
diff --git a/perf/Makefile.sources b/perf/Makefile.sources
deleted file mode 100644
index 1fcf14809..000000000
--- a/perf/Makefile.sources
+++ /dev/null
@@ -1,38 +0,0 @@
-libcairoperf_sources = \
- cairo-perf.c \
- cairo-perf-report.c \
- cairo-stats.c \
- $(NULL)
-
-libcairoperf_external_sources = ../src/cairo-time.c
-
-libcairoperf_headers = \
- cairo-perf.h \
- cairo-stats.h \
- $(NULL)
-
-cairo_analyse_trace_sources = cairo-analyse-trace.c
-cairo_analyse_trace_external_sources = ../src/cairo-error.c
-
-cairo_perf_trace_sources = cairo-perf-trace.c
-cairo_perf_trace_external_sources = \
- ../src/cairo-error.c \
- ../src/cairo-hash.c \
- $(NULL)
-
-cairo_perf_micro_sources = cairo-perf-micro.c
-
-cairo_perf_diff_files_sources = cairo-perf-diff-files.c
-
-cairo_perf_print_sources = cairo-perf-print.c
-
-cairo_perf_chart_sources = cairo-perf-chart.c
-
-cairo_perf_compare_backends_sources = cairo-perf-compare-backends.c
-
-cairo_perf_graph_files_sources = \
- cairo-perf-graph-files.c \
- cairo-perf-graph-widget.c \
- $(NULL)
-
-cairo_perf_graph_files_headers = cairo-perf-graph.h
diff --git a/perf/Makefile.win32 b/perf/Makefile.win32
deleted file mode 100644
index 084abf00e..000000000
--- a/perf/Makefile.win32
+++ /dev/null
@@ -1,78 +0,0 @@
-top_srcdir = ..
-include $(top_srcdir)/build/Makefile.win32.common
-include $(top_srcdir)/perf/Makefile.sources
-
-CFLAGS += -I$(top_srcdir)/boilerplate -I$(top_srcdir)/util/cairo-script/
-
-PERF_LIBS = \
- $(CFG)/libcairoperf.lib \
- $(top_builddir)/boilerplate/$(CFG)/boiler.lib \
- $(top_builddir)/src/$(CFG)/cairo-static.lib \
- $(NULL)
-
-PERF_EXES = \
- $(CFG)/cairo-perf-trace.exe \
- $(CFG)/cairo-perf-micro.exe \
- $(CFG)/cairo-perf-diff-files.exe \
- $(CFG)/cairo-perf-print.exe \
- $(CFG)/cairo-perf-chart.exe \
- $(CFG)/cairo-perf-compare-backends.exe \
- $(NULL)
-
-all: inform $(PERF_EXES)
-
-perf: inform $(CFG)/cairo-perf-micro.exe
- ./$(CFG)/cairo-perf-micro.exe
-
-
-libcairoperf_OBJECTS = $(patsubst %.c, $(CFG)/%-static.obj, $(libcairoperf_sources))
-
-$(CFG)/libcairoperf.lib: $(libcairoperf_OBJECTS)
- @$(AR) $(CAIRO_ARFLAGS) -OUT:$@ $(libcairoperf_OBJECTS)
-
-cairo_perf_trace_OBJECTS = \
- $(patsubst %.c, $(CFG)/%-static.obj, $(cairo_perf_trace_sources)) \
- $(top_builddir)/util/cairo-script/$(CFG)/libcairo-script-interpreter.lib \
- $(NULL)
-
-cairo_perf_micro_OBJECTS = \
- $(patsubst %.c, $(CFG)/%-static.obj, $(cairo_perf_micro_sources)) \
- ./micro/$(CFG)/libcairo-perf-micro.lib \
- $(NULL)
-
-cairo_perf_diff_files_OBJECTS = $(patsubst %.c, $(CFG)/%-static.obj, $(cairo_perf_diff_files_sources))
-cairo_perf_print_OBJECTS = $(patsubst %.c, $(CFG)/%-static.obj, $(cairo_perf_print_sources))
-cairo_perf_chart_OBJECTS = $(patsubst %.c, $(CFG)/%-static.obj, $(cairo_perf_chart_sources))
-cairo_perf_compare_backends_OBJECTS = $(patsubst %.c, $(CFG)/%-static.obj, $(cairo_perf_compare_backends_sources))
-
-
-$(CFG)/cairo-perf-trace.exe: $(cairo_perf_trace_OBJECTS) $(PERF_LIBS)
- @$(LD) $(CAIRO_LDFLAGS) -OUT:$@ $(cairo_perf_trace_OBJECTS) $(PERF_LIBS) $(CAIRO_LIBS)
-
-$(CFG)/cairo-perf-micro.exe: $(cairo_perf_micro_OBJECTS) $(PERF_LIBS)
- @$(LD) $(CAIRO_LDFLAGS) -OUT:$@ $(cairo_perf_micro_OBJECTS) $(PERF_LIBS) $(CAIRO_LIBS)
-
-$(CFG)/cairo-perf-diff-files.exe: $(cairo_perf_diff_files_OBJECTS) $(PERF_LIBS)
- @$(LD) $(CAIRO_LDFLAGS) -OUT:$@ $(cairo_perf_diff_files_OBJECTS) $(PERF_LIBS) $(CAIRO_LIBS)
-
-$(CFG)/cairo-perf-print.exe: $(cairo_perf_print_OBJECTS) $(PERF_LIBS)
- @$(LD) $(CAIRO_LDFLAGS) -OUT:$@ $(cairo_perf_print_OBJECTS) $(PERF_LIBS) $(CAIRO_LIBS)
-
-$(CFG)/cairo-perf-chart.exe: $(cairo_perf_chart_OBJECTS) $(PERF_LIBS)
- @$(LD) $(CAIRO_LDFLAGS) -OUT:$@ $(cairo_perf_chart_OBJECTS) $(PERF_LIBS) $(CAIRO_LIBS)
-
-$(CFG)/cairo-perf-compare-backends.exe: $(cairo_perf_compare_backends_OBJECTS) $(PERF_LIBS)
- @$(LD) $(CAIRO_LDFLAGS) -OUT:$@ $(cairo_perf_compare_backends_OBJECTS) $(PERF_LIBS) $(CAIRO_LIBS)
-
-
-./micro/$(CFG)/libcairo-perf-micro.lib:
- $(MAKE) -C micro -f Makefile.win32
-
-$(top_builddir)/src/$(CFG)/cairo-static.lib:
- $(MAKE) -C $(top_srcdir)/src -f Makefile.win32
-
-$(top_builddir)/boilerplate/$(CFG)/boiler.lib:
- $(MAKE) -C $(top_srcdir)/boilerplate -f Makefile.win32
-
-$(top_builddir)/util/cairo-script/$(CFG)/libcairo-script-interpreter.lib:
- $(MAKE) -C $(top_srcdir)/util/cairo-script -f Makefile.win32
diff --git a/perf/cairo-perf-chart.c b/perf/cairo-perf-chart.c
index 738fe5c7b..9ccb9b42e 100644
--- a/perf/cairo-perf-chart.c
+++ b/perf/cairo-perf-chart.c
@@ -139,7 +139,7 @@ find_ranges (struct chart *chart)
double test_time;
int seen_non_null;
int num_tests = 0;
- double slow_sum = 0, fast_sum = 0, sum;
+ double slow_sum = 0, fast_sum = 0, sum = 0;
int slow_count = 0, fast_count = 0;
int *count;
int i;
diff --git a/perf/cairo-perf-graph-files.c b/perf/cairo-perf-graph-files.c
index 1fd99e4ad..9a2a325e6 100644
--- a/perf/cairo-perf-graph-files.c
+++ b/perf/cairo-perf-graph-files.c
@@ -25,14 +25,19 @@
* Authors: Chris Wilson <chris@chris-wilson.co.uk>
*/
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
#include "cairo-perf.h"
#include "cairo-perf-graph.h"
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
#include <errno.h>
+
+#ifdef G_OS_UNIX
+#include <unistd.h>
#include <fcntl.h>
+#endif
#include <cairo.h>
@@ -232,6 +237,8 @@ show_case_toggled (GtkCellRendererToggle *cell,
graph_view_update_visible ((GraphView *) app->gv);
}
+#ifdef G_OS_UNIX
+
static gboolean
git_read (GIOChannel *io,
GIOCondition cond,
@@ -300,6 +307,8 @@ do_git (struct _app_data *app,
g_io_add_watch (app->git_io, G_IO_IN | G_IO_HUP, (GIOFunc) git_read, app);
}
+#endif
+
static void
gv_report_selected (GraphView *gv,
int i,
@@ -327,7 +336,11 @@ gv_report_selected (GraphView *gv,
argv[3] = id;
argv[4] = NULL;
+#ifdef G_OS_UNIX
do_git (app, argv);
+#else
+ g_print ("id: %s\n", id);
+#endif
g_free (id);
}
}
diff --git a/perf/cairo-perf-graph-widget.c b/perf/cairo-perf-graph-widget.c
index e56eee1bc..9da0abbfe 100644
--- a/perf/cairo-perf-graph-widget.c
+++ b/perf/cairo-perf-graph-widget.c
@@ -25,6 +25,8 @@
* Authors: Chris Wilson <chris@chris-wilson.co.uk>
*/
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
#include "cairo-perf.h"
#include "cairo-perf-graph.h"
diff --git a/perf/cairo-perf.c b/perf/cairo-perf.c
index ebef8eb59..244d6cb74 100644
--- a/perf/cairo-perf.c
+++ b/perf/cairo-perf.c
@@ -37,7 +37,6 @@
#endif
#if defined(_WIN32)
-#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#elif defined(_POSIX_PRIORITY_SCHEDULING)
#include <sched.h>
diff --git a/perf/dirent-win32.h b/perf/dirent-win32.h
index 0f2ed05e5..435a6cfa2 100644
--- a/perf/dirent-win32.h
+++ b/perf/dirent-win32.h
@@ -26,7 +26,6 @@
#include "cairo-compiler-private.h"
-#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define stat _stat
diff --git a/perf/micro/Makefile.am b/perf/micro/Makefile.am
deleted file mode 100644
index 3edbf531c..000000000
--- a/perf/micro/Makefile.am
+++ /dev/null
@@ -1,16 +0,0 @@
-include $(top_srcdir)/build/Makefile.am.common
-
-include $(top_srcdir)/perf/micro/Makefile.sources
-
-noinst_LTLIBRARIES = libcairo-perf-micro.la
-libcairo_perf_micro_la_SOURCES = \
- $(libcairo_perf_micro_sources) \
- $(libcairo_perf_micro_headers)
-
-AM_CPPFLAGS = \
- -I$(srcdir) \
- -I$(top_srcdir)/boilerplate \
- -I$(top_srcdir)/src \
- -I$(top_srcdir)/perf \
- -I$(top_builddir)/src \
- $(CAIRO_CFLAGS)
diff --git a/perf/micro/Makefile.sources b/perf/micro/Makefile.sources
deleted file mode 100644
index 19ead179d..000000000
--- a/perf/micro/Makefile.sources
+++ /dev/null
@@ -1,51 +0,0 @@
-libcairo_perf_micro_sources = \
- cairo-perf-cover.c \
- box-outline.c \
- composite-checker.c \
- disjoint.c \
- fill.c \
- hatching.c \
- hash-table.c \
- line.c \
- a1-line.c \
- long-lines.c \
- mosaic.c \
- paint.c \
- paint-with-alpha.c \
- mask.c \
- pattern_create_radial.c \
- rectangles.c \
- rounded-rectangles.c \
- stroke.c \
- subimage_copy.c \
- tessellate.c \
- text.c \
- tiger.c \
- glyphs.c \
- twin.c \
- unaligned-clip.c \
- wave.c \
- world-map.c \
- zrusin.c \
- long-dashed-lines.c \
- dragon.c \
- pythagoras-tree.c \
- intersections.c \
- many-strokes.c \
- wide-strokes.c \
- many-fills.c \
- wide-fills.c \
- many-curves.c \
- curve.c \
- a1-curve.c \
- spiral.c \
- pixel.c \
- sierpinski.c \
- fill-clip.c \
- $(NULL)
-
-libcairo_perf_micro_headers = \
- mosaic.h \
- world-map.h \
- zrusin-another.h \
- $(NULL)
diff --git a/perf/micro/Makefile.win32 b/perf/micro/Makefile.win32
deleted file mode 100644
index f41f781d7..000000000
--- a/perf/micro/Makefile.win32
+++ /dev/null
@@ -1,12 +0,0 @@
-top_srcdir = ../..
-include $(top_srcdir)/build/Makefile.win32.common
-include $(top_srcdir)/perf/micro/Makefile.sources
-
-CFLAGS += -I$(top_srcdir)/perf -I$(top_srcdir)/boilerplate/
-
-OBJECTS = $(patsubst %.c, $(CFG)/%-static.obj, $(libcairo_perf_micro_sources))
-
-all: inform $(CFG)/libcairo-perf-micro.lib
-
-$(CFG)/libcairo-perf-micro.lib: $(OBJECTS)
- @$(AR) $(CAIRO_ARFLAGS) -OUT:$@ $(OBJECTS)
diff --git a/src/Makefile.am b/src/Makefile.am
deleted file mode 100644
index c03ef71a8..000000000
--- a/src/Makefile.am
+++ /dev/null
@@ -1,99 +0,0 @@
-# Note: All source files are listed in Makefile.sources.
-
-include $(top_srcdir)/build/Makefile.am.common
-include $(srcdir)/Makefile.am.features
-
-EXTRA_DIST += Makefile.win32 Makefile.win32.features
-#MAINTAINERCLEANFILES += $(srcdir)/Makefile.win32.features
-
-AM_CPPFLAGS = -I$(srcdir) $(CAIRO_CFLAGS)
-AM_LDFLAGS = $(CAIRO_LDFLAGS)
-
-if OS_WIN32
-export_symbols = -export-symbols cairo.def
-cairo_def_dependency = cairo.def
-endif
-
-$(top_builddir)/config.h: $(top_srcdir)/config.h.in
- cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) config.h
-
-cairoincludedir = $(includedir)/cairo
-cairoinclude_HEADERS = $(enabled_cairo_headers)
-
-lib_LTLIBRARIES = libcairo.la
-
-libcairo_la_SOURCES = \
- $(enabled_cairo_headers) \
- $(enabled_cairo_private) \
- $(enabled_cairo_sources) \
- $(NULL)
-libcairo_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(CAIRO_LIBTOOL_VERSION_INFO) -no-undefined $(export_symbols)
-libcairo_la_LIBADD = $(CAIRO_LIBS)
-libcairo_la_DEPENDENCIES = $(cairo_def_dependency)
-
-# Special headers
-nodist_cairoinclude_HEADERS = cairo-features.h
-nodist_libcairo_la_SOURCES = cairo-features.h
-BUILT_SOURCES += cairo-features.h cairo-supported-features.h
-DISTCLEANFILES += cairo-features.h cairo-supported-features.h
-cairo-features.h cairo-supported-features.h:
- cd $(top_builddir) && ./config.status src/$@
-
-pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = $(enabled_cairo_pkgconf)
-
-CLEANFILES += cairo.def
-cairo.def: cairo-features.h $(enabled_cairo_headers)
- @echo Generating $@
- @(echo EXPORTS; \
- (cd $(srcdir); cat $(enabled_cairo_headers) || echo 'cairo_ERROR ()' ) | \
- $(EGREP) -v '^# *include' | \
- ( cat cairo-features.h - | $(CPP) -D__cplusplus - || echo 'cairo_ERROR ()' ) | \
- $(EGREP) '^cairo_.* \(' | \
- sed -e 's/[ ].*//' | \
- sort; \
- echo LIBRARY libcairo-$(CAIRO_VERSION_SONUM).dll; \
- ) >$@
- @ ! grep -q cairo_ERROR $@ || ($(RM) $@; false)
-
-TESTS_ENVIRONMENT = \
- srcdir="$(srcdir)" \
- MAKE="$(MAKE) $(AM_MAKEFLAGS)" \
- all_cairo_files="$(all_cairo_files)" \
- all_cairo_headers="$(all_cairo_headers)" \
- all_cairo_private="$(all_cairo_private)" \
- all_cairo_sources="$(all_cairo_sources)" \
- enabled_cairo_headers="$(enabled_cairo_headers)" \
- enabled_cairo_private="$(enabled_cairo_private)" \
- enabled_cairo_sources="$(enabled_cairo_sources)" \
- $(NULL)
-TESTS_SH = \
- check-def.sh \
- check-doc-syntax.sh \
- check-headers.sh \
- check-plt.sh \
- check-preprocessor-syntax.sh \
- $(NULL)
-TESTS += $(TESTS_SH)
-if CROSS_COMPILING
-else
-TESTS += check-link$(EXEEXT)
-endif
-
-EXTRA_DIST += $(TESTS_SH) check-has-hidden-symbols.c check-doc-syntax.awk
-check_PROGRAMS += check-link
-check_link_LDADD = libcairo.la
-
-check: headers-standalone
-
-PREPROCESS_ARGS = $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS)
-COMPILE_ARGS = $(PREPROCESS_ARGS) $(AM_CFLAGS) $(CFLAGS)
-
-# The pre-processed result is used by check-{def,plt}.sh to determine whether
-# cairo has been compiled with symbol hiding.
-.c.i: $(cairoinclude_HEADERS) $(nodist_cairoinclude_HEADERS) cairoint.h $(top_builddir)/config.h
- $(CPP) $(PREPROCESS_ARGS) $< -o $@
-.c.s: $(cairoinclude_HEADERS) $(nodist_cairoinclude_HEADERS) cairoint.h $(top_builddir)/config.h
- $(CC) $(COMPILE_ARGS) $< -S -o $@
-
-include $(srcdir)/Makefile.am.analysis
diff --git a/src/Makefile.am.analysis b/src/Makefile.am.analysis
deleted file mode 100644
index 63bb844df..000000000
--- a/src/Makefile.am.analysis
+++ /dev/null
@@ -1,35 +0,0 @@
-
-SPARSE = sparse
-sparse:
- @echo Checking enabled sources with sparse checker
- @status=true; for f in $(enabled_cairo_sources); do \
- echo $(SPARSE) $(PREPROCESS_ARGS) $(srcdir)/$$f; \
- $(SPARSE) $(PREPROCESS_ARGS) $(srcdir)/$$f || status=false; \
- done; $$status
-
-SPLINT = splint -badflag
-splint:
- @echo Checking enabled sources with splint checker
- @status=true; for f in $(enabled_cairo_sources); do \
- echo $(SPLINT) $(PREPROCESS_ARGS) $(srcdir)/$$f; \
- $(SPLINT) $(PREPROCESS_ARGS) $(srcdir)/$$f || status=false; \
- done; $$status
-
-UNO = uno
-uno:
- @echo Checking enabled sources with uno checker
- cd $(srcdir); $(UNO) $(PREPROCESS_ARGS) -DHAVE_CONFIG_H -U__GNUC__ $(enabled_cairo_sources)
-
-headers-standalone: $(enabled_cairo_headers) $(enabled_cairo_private)
- @echo Checking that enabled public/private headers can be compiled standalone
- @status=true; for f in $(enabled_cairo_headers) $(enabled_cairo_private); do \
- echo " CHECK $$f"; \
- echo "#include \"$(srcdir)/$$f\"" > headers-standalone-tmp.c; \
- echo "int main(int argc, char * argv[]) { return 0; }" >> headers-standalone-tmp.c; \
- $(COMPILE) -o headers-standalone-tmp headers-standalone-tmp.c || status=false; \
- $(RM) headers-standalone-tmp headers-standalone-tmp.c; \
- done; $$status
- @touch $@
-CLEANFILES += headers-standalone
-
-analysis: all headers-standalone sparse splint uno
diff --git a/src/Makefile.sources b/src/Makefile.sources
deleted file mode 100644
index 9328fca97..000000000
--- a/src/Makefile.sources
+++ /dev/null
@@ -1,405 +0,0 @@
-# Makefile.sources
-#
-# This file is the canonical location listing all the source files used
-# to build the cairo library. Every source file is categorized as one of:
-#
-# * public header file
-# * private header file (must end in -private.h except for cairoint.h)
-# * source code file
-#
-# Every source file should be specified exactly once, grouped with the
-# feature that uses the source file. If more than one feature use the
-# file (like pdf_operators or font_subset files), the files should be
-# appended to to the base cairo files, and the code inside them
-# enabled/disabled using C preprocessor macros defined in cairoint.h.
-# See how pdf_operators or font_subset are handled.
-#
-# The sources are picked up according to the configured features
-# by the generated file Makefile.am.features or Makefile.win32.features.
-#
-# These are a few special source files. Those are not included in this
-# file to not confuse build systems. Each build system must handle them
-# separately. These files include:
-#
-# * cairo-features.h:
-# This file is generated by configure and includes macros signifying
-# which features are enabled. This file should be installed like
-# other public headers, but should NOT be distributed in the cairo
-# distribution.
-#
-# * cairo-supported-features.h:
-# This file is generated by configure and includes macros signifying
-# all supported features. This is used by gtk-doc to generate
-# documentation for all those macros, enabled or not.
-# This file is NOT used during the build of the library and should
-# NOT be installed or distributed.
-#
-# Please follow the strict syntax of this file, including keeping file
-# lists sorted.
-#
-
-cairo_headers = cairo.h cairo-version.h cairo-deprecated.h
-cairo_private = \
- cairoint.h \
- cairo-analysis-surface-private.h \
- cairo-arc-private.h \
- cairo-array-private.h \
- cairo-atomic-private.h \
- cairo-backend-private.h \
- cairo-box-inline.h \
- cairo-boxes-private.h \
- cairo-cache-private.h \
- cairo-clip-inline.h \
- cairo-clip-private.h \
- cairo-combsort-inline.h \
- cairo-compiler-private.h \
- cairo-composite-rectangles-private.h \
- cairo-compositor-private.h \
- cairo-contour-inline.h \
- cairo-contour-private.h \
- cairo-damage-private.h \
- cairo-default-context-private.h \
- cairo-device-private.h \
- cairo-error-inline.h \
- cairo-error-private.h \
- cairo-fixed-private.h \
- cairo-fixed-type-private.h \
- cairo-fontconfig-private.h \
- cairo-freed-pool-private.h \
- cairo-freelist-private.h \
- cairo-freelist-type-private.h \
- cairo-gstate-private.h \
- cairo-hash-private.h \
- cairo-image-info-private.h \
- cairo-image-surface-inline.h \
- cairo-image-surface-private.h \
- cairo-line-inline.h \
- cairo-line-private.h \
- cairo-list-inline.h \
- cairo-list-private.h \
- cairo-malloc-private.h \
- cairo-mempool-private.h \
- cairo-mutex-impl-private.h \
- cairo-mutex-list-private.h \
- cairo-mutex-private.h \
- cairo-mutex-type-private.h \
- cairo-output-stream-private.h \
- cairo-paginated-private.h \
- cairo-paginated-surface-private.h \
- cairo-path-fixed-private.h \
- cairo-path-private.h \
- cairo-pattern-inline.h \
- cairo-pattern-private.h \
- cairo-pixman-private.h \
- cairo-private.h \
- cairo-recording-surface-inline.h \
- cairo-recording-surface-private.h \
- cairo-reference-count-private.h \
- cairo-region-private.h \
- cairo-rtree-private.h \
- cairo-scaled-font-private.h \
- cairo-slope-private.h \
- cairo-spans-compositor-private.h \
- cairo-spans-private.h \
- cairo-stroke-dash-private.h \
- cairo-surface-backend-private.h \
- cairo-surface-clipper-private.h \
- cairo-surface-fallback-private.h \
- cairo-surface-inline.h \
- cairo-surface-observer-inline.h \
- cairo-surface-observer-private.h \
- cairo-surface-offset-private.h \
- cairo-surface-private.h \
- cairo-surface-snapshot-inline.h \
- cairo-surface-snapshot-private.h \
- cairo-surface-subsurface-inline.h \
- cairo-surface-subsurface-private.h \
- cairo-surface-wrapper-private.h \
- cairo-time-private.h \
- cairo-traps-private.h \
- cairo-tristrip-private.h \
- cairo-types-private.h \
- cairo-user-font-private.h \
- cairo-wideint-private.h \
- cairo-wideint-type-private.h \
- $(NULL)
-cairo_sources = \
- cairo-analysis-surface.c \
- cairo-arc.c \
- cairo-array.c \
- cairo-atomic.c \
- cairo-base64-stream.c \
- cairo-base85-stream.c \
- cairo-bentley-ottmann-rectangular.c \
- cairo-bentley-ottmann-rectilinear.c \
- cairo-bentley-ottmann.c \
- cairo-botor-scan-converter.c \
- cairo-boxes-intersect.c \
- cairo-boxes.c \
- cairo-cache.c \
- cairo-clip-boxes.c \
- cairo-clip-polygon.c \
- cairo-clip-region.c \
- cairo-clip-surface.c \
- cairo-clip-tor-scan-converter.c \
- cairo-clip.c \
- cairo-color.c \
- cairo-composite-rectangles.c \
- cairo-compositor.c \
- cairo-contour.c \
- cairo-damage.c \
- cairo-debug.c \
- cairo-default-context.c \
- cairo-device.c \
- cairo-error.c \
- cairo-fallback-compositor.c \
- cairo-fixed.c \
- cairo-font-face-twin-data.c \
- cairo-font-face-twin.c \
- cairo-font-face.c \
- cairo-font-options.c \
- cairo-freed-pool.c \
- cairo-freelist.c \
- cairo-gstate.c \
- cairo-hash.c \
- cairo-hull.c \
- cairo-image-compositor.c \
- cairo-image-info.c \
- cairo-image-source.c \
- cairo-image-surface.c \
- cairo-line.c \
- cairo-lzw.c \
- cairo-mask-compositor.c \
- cairo-matrix.c \
- cairo-mempool.c \
- cairo-mesh-pattern-rasterizer.c \
- cairo-misc.c \
- cairo-mono-scan-converter.c \
- cairo-mutex.c \
- cairo-no-compositor.c \
- cairo-observer.c \
- cairo-output-stream.c \
- cairo-paginated-surface.c \
- cairo-path-bounds.c \
- cairo-path-fill.c \
- cairo-path-fixed.c \
- cairo-path-in-fill.c \
- cairo-path-stroke-boxes.c \
- cairo-path-stroke-polygon.c \
- cairo-path-stroke-traps.c \
- cairo-path-stroke-tristrip.c \
- cairo-path-stroke.c \
- cairo-path.c \
- cairo-pattern.c \
- cairo-pen.c \
- cairo-polygon-intersect.c \
- cairo-polygon-reduce.c \
- cairo-polygon.c \
- cairo-raster-source-pattern.c \
- cairo-recording-surface.c \
- cairo-rectangle.c \
- cairo-rectangular-scan-converter.c \
- cairo-region.c \
- cairo-rtree.c \
- cairo-scaled-font.c \
- cairo-shape-mask-compositor.c \
- cairo-slope.c \
- cairo-spans-compositor.c \
- cairo-spans.c \
- cairo-spline.c \
- cairo-stroke-dash.c \
- cairo-stroke-style.c \
- cairo-surface-clipper.c \
- cairo-surface-fallback.c \
- cairo-surface-observer.c \
- cairo-surface-offset.c \
- cairo-surface-snapshot.c \
- cairo-surface-subsurface.c \
- cairo-surface-wrapper.c \
- cairo-surface.c \
- cairo-time.c \
- cairo-tor-scan-converter.c \
- cairo-tor22-scan-converter.c \
- cairo-toy-font-face.c \
- cairo-traps-compositor.c \
- cairo-traps.c \
- cairo-tristrip.c \
- cairo-unicode.c \
- cairo-user-font.c \
- cairo-version.c \
- cairo-wideint.c \
- cairo.c \
- $(NULL)
-
-_cairo_font_subset_private = \
- cairo-scaled-font-subsets-private.h \
- cairo-truetype-subset-private.h \
- cairo-type1-private.h \
- cairo-type3-glyph-surface-private.h \
- $(NULL)
-_cairo_font_subset_sources = \
- cairo-cff-subset.c \
- cairo-scaled-font-subsets.c \
- cairo-truetype-subset.c \
- cairo-type1-fallback.c \
- cairo-type1-glyph-names.c \
- cairo-type1-subset.c \
- cairo-type3-glyph-surface.c \
- $(NULL)
-cairo_private += $(_cairo_font_subset_private)
-cairo_sources += $(_cairo_font_subset_sources)
-
-cairo_egl_sources =
-cairo_glx_sources =
-cairo_wgl_sources =
-
-_cairo_pdf_operators_private = \
- cairo-pdf-operators-private.h \
- cairo-pdf-shading-private.h \
- cairo-tag-attributes-private.h \
- $(NULL)
-_cairo_pdf_operators_sources = \
- cairo-pdf-operators.c \
- cairo-pdf-shading.c \
- cairo-tag-attributes.c \
- $(NULL)
-cairo_private += $(_cairo_pdf_operators_private)
-cairo_sources += $(_cairo_pdf_operators_sources)
-
-cairo_png_sources = cairo-png.c
-
-cairo_ps_headers = cairo-ps.h
-cairo_ps_private = cairo-ps-surface-private.h
-cairo_ps_sources = cairo-ps-surface.c
-
-_cairo_deflate_stream_sources = cairo-deflate-stream.c
-cairo_sources += $(_cairo_deflate_stream_sources)
-
-cairo_pdf_headers = cairo-pdf.h
-cairo_pdf_private = cairo-pdf-surface-private.h cairo-tag-stack-private.h
-cairo_pdf_sources = cairo-pdf-surface.c cairo-pdf-interchange.c cairo-tag-stack.c
-
-cairo_svg_headers = cairo-svg.h
-cairo_svg_private = cairo-svg-surface-private.h
-cairo_svg_sources = cairo-svg-surface.c
-
-cairo_ft_headers = cairo-ft.h
-cairo_ft_private = cairo-ft-private.h
-cairo_ft_sources = cairo-ft-font.c
-
-# These are private, even though they look like public headers
-cairo_test_surfaces_private = \
- test-compositor-surface.h \
- test-compositor-surface-private.h \
- test-null-compositor-surface.h \
- test-paginated-surface.h \
- $(NULL)
-cairo_test_surfaces_sources = \
- test-compositor-surface.c \
- test-null-compositor-surface.c \
- test-base-compositor-surface.c \
- test-paginated-surface.c \
- $(NULL)
-
-cairo_xlib_headers = cairo-xlib.h
-cairo_xlib_private = \
- cairo-xlib-private.h \
- cairo-xlib-surface-private.h \
- cairo-xlib-xrender-private.h \
- $(NULL)
-cairo_xlib_sources = \
- cairo-xlib-display.c \
- cairo-xlib-core-compositor.c \
- cairo-xlib-fallback-compositor.c \
- cairo-xlib-render-compositor.c \
- cairo-xlib-screen.c \
- cairo-xlib-source.c \
- cairo-xlib-surface.c \
- cairo-xlib-surface-shm.c \
- cairo-xlib-visual.c \
- cairo-xlib-xcb-surface.c \
- $(NULL)
-
-cairo_xlib_xrender_headers = cairo-xlib-xrender.h
-
-cairo_xcb_headers = cairo-xcb.h
-cairo_xcb_private = cairo-xcb-private.h
-cairo_xcb_sources = \
- cairo-xcb-connection.c \
- cairo-xcb-connection-core.c \
- cairo-xcb-connection-render.c \
- cairo-xcb-connection-shm.c \
- cairo-xcb-screen.c \
- cairo-xcb-shm.c \
- cairo-xcb-surface.c \
- cairo-xcb-surface-core.c \
- cairo-xcb-surface-render.c \
- cairo-xcb-resources.c \
- $(NULL)
-
-cairo_quartz_headers = cairo-quartz.h
-cairo_quartz_private = cairo-quartz-private.h
-cairo_quartz_sources = cairo-quartz-surface.c
-
-cairo_quartz_image_headers = cairo-quartz-image.h
-cairo_quartz_image_sources = cairo-quartz-image-surface.c
-
-cairo_quartz_font_sources = cairo-quartz-font.c
-
-cairo_win32_headers = cairo-win32.h
-cairo_win32_private = win32/cairo-win32-private.h
-cairo_win32_sources = \
- win32/cairo-win32-debug.c \
- win32/cairo-win32-device.c \
- win32/cairo-win32-gdi-compositor.c \
- win32/cairo-win32-system.c \
- win32/cairo-win32-surface.c \
- win32/cairo-win32-display-surface.c \
- win32/cairo-win32-printing-surface.c \
- $(NULL)
-cairo_win32_font_sources = \
- win32/cairo-win32-font.c \
- $(NULL)
-
-cairo_gl_headers = cairo-gl.h
-cairo_gl_private = cairo-gl-private.h \
- cairo-gl-dispatch-private.h \
- cairo-gl-ext-def-private.h \
- cairo-gl-gradient-private.h
-
-cairo_gl_sources = cairo-gl-composite.c \
- cairo-gl-device.c \
- cairo-gl-dispatch.c \
- cairo-gl-glyphs.c \
- cairo-gl-gradient.c \
- cairo-gl-info.c \
- cairo-gl-msaa-compositor.c \
- cairo-gl-operand.c \
- cairo-gl-shaders.c \
- cairo-gl-source.c \
- cairo-gl-spans-compositor.c \
- cairo-gl-surface.c \
- cairo-gl-traps-compositor.c
-
-cairo_glesv2_headers = $(cairo_gl_headers)
-cairo_glesv2_private = $(cairo_gl_private)
-cairo_glesv2_sources = $(cairo_gl_sources)
-
-cairo_glesv3_headers = $(cairo_gl_headers)
-cairo_glesv3_private = $(cairo_gl_private)
-cairo_glesv3_sources = $(cairo_gl_sources)
-
-cairo_egl_sources += cairo-egl-context.c
-cairo_glx_sources += cairo-glx-context.c
-cairo_wgl_sources += cairo-wgl-context.c
-
-cairo_script_headers = cairo-script.h
-cairo_script_private = cairo-script-private.h
-cairo_script_sources = cairo-script-surface.c
-
-cairo_tee_headers = cairo-tee.h
-cairo_tee_private = cairo-tee-surface-private.h
-cairo_tee_sources = cairo-tee-surface.c
-
-cairo_xml_headers = cairo-xml.h
-cairo_xml_sources = cairo-xml-surface.c
diff --git a/src/Makefile.win32 b/src/Makefile.win32
deleted file mode 100644
index 9afefe2b7..000000000
--- a/src/Makefile.win32
+++ /dev/null
@@ -1,28 +0,0 @@
-top_srcdir = ..
-include $(top_srcdir)/build/Makefile.win32.common
-include Makefile.win32.features
-
-SOURCES = $(enabled_cairo_sources)
-
-STATIC_SOURCES = cairo-system.c
-
-OBJECTS = $(patsubst %.c, $(CFG)/%.obj, $(SOURCES))
-OBJECTS_STATIC = $(patsubst %cairo-system.obj, %cairo-system-static.obj, $(OBJECTS))
-
-static: inform $(CFG)/cairo-static.lib
-dynamic: inform $(CFG)/cairo.dll
-
-$(CFG)/cairo.dll: $(OBJECTS)
- @$(LD) $(CAIRO_LDFLAGS) -DLL -OUT:$@ $(CAIRO_LIBS) $(PIXMAN_LIBS) $(OBJECTS)
-
-$(CFG)/cairo-static.lib: $(OBJECTS_STATIC)
- @$(AR) $(CAIRO_ARFLAGS) -OUT:$@ $(PIXMAN_LIBS) $(OBJECTS_STATIC)
-
-all: inform $(CFG)/cairo.dll $(CFG)/cairo-static.lib
- @echo "Built successfully!"
- @echo "You should copy the following files to a proper place now:"
- @echo ""
- @echo " src/cairo-features.h"
- @for x in $(enabled_cairo_headers); do echo " src/$$x"; done
- @echo " src/$(CFG)/cairo.dll"
- @echo " src/$(CFG)/cairo-static.lib"
diff --git a/src/Makefile.win32.features b/src/Makefile.win32.features
deleted file mode 100644
index fbc774d4f..000000000
--- a/src/Makefile.win32.features
+++ /dev/null
@@ -1,459 +0,0 @@
-# Generated by configure. Do not edit.
-
-ifeq ($(top_srcdir),)
-include Makefile.sources
-else
-include $(top_srcdir)/src/Makefile.sources
-endif
-
-supported_cairo_headers = $(cairo_headers)
-unsupported_cairo_headers =
-all_cairo_headers = $(cairo_headers)
-all_cairo_private = $(cairo_private)
-all_cairo_sources = $(cairo_sources)
-
-enabled_cairo_headers = $(cairo_headers)
-enabled_cairo_private = $(cairo_private)
-enabled_cairo_sources = $(cairo_sources)
-
-all_cairo_pkgconf = cairo.pc
-enabled_cairo_pkgconf = cairo.pc
-
-supported_cairo_headers += $(cairo_xlib_headers)
-all_cairo_headers += $(cairo_xlib_headers)
-all_cairo_private += $(cairo_xlib_private)
-all_cairo_sources += $(cairo_xlib_sources)
-ifeq ($(CAIRO_HAS_XLIB_SURFACE),1)
-enabled_cairo_headers += $(cairo_xlib_headers)
-enabled_cairo_private += $(cairo_xlib_private)
-enabled_cairo_sources += $(cairo_xlib_sources)
-endif
-all_cairo_pkgconf += cairo-xlib.pc
-ifeq ($(CAIRO_HAS_XLIB_SURFACE),1)
-enabled_cairo_pkgconf += cairo-xlib.pc
-endif
-
-supported_cairo_headers += $(cairo_xlib_xrender_headers)
-all_cairo_headers += $(cairo_xlib_xrender_headers)
-all_cairo_private += $(cairo_xlib_xrender_private)
-all_cairo_sources += $(cairo_xlib_xrender_sources)
-ifeq ($(CAIRO_HAS_XLIB_XRENDER_SURFACE),1)
-enabled_cairo_headers += $(cairo_xlib_xrender_headers)
-enabled_cairo_private += $(cairo_xlib_xrender_private)
-enabled_cairo_sources += $(cairo_xlib_xrender_sources)
-endif
-all_cairo_pkgconf += cairo-xlib-xrender.pc
-ifeq ($(CAIRO_HAS_XLIB_XRENDER_SURFACE),1)
-enabled_cairo_pkgconf += cairo-xlib-xrender.pc
-endif
-
-supported_cairo_headers += $(cairo_xcb_headers)
-all_cairo_headers += $(cairo_xcb_headers)
-all_cairo_private += $(cairo_xcb_private)
-all_cairo_sources += $(cairo_xcb_sources)
-ifeq ($(CAIRO_HAS_XCB_SURFACE),1)
-enabled_cairo_headers += $(cairo_xcb_headers)
-enabled_cairo_private += $(cairo_xcb_private)
-enabled_cairo_sources += $(cairo_xcb_sources)
-endif
-all_cairo_pkgconf += cairo-xcb.pc
-ifeq ($(CAIRO_HAS_XCB_SURFACE),1)
-enabled_cairo_pkgconf += cairo-xcb.pc
-endif
-
-unsupported_cairo_headers += $(cairo_xlib_xcb_headers)
-all_cairo_headers += $(cairo_xlib_xcb_headers)
-all_cairo_private += $(cairo_xlib_xcb_private)
-all_cairo_sources += $(cairo_xlib_xcb_sources)
-ifeq ($(CAIRO_HAS_XLIB_XCB_FUNCTIONS),1)
-enabled_cairo_headers += $(cairo_xlib_xcb_headers)
-enabled_cairo_private += $(cairo_xlib_xcb_private)
-enabled_cairo_sources += $(cairo_xlib_xcb_sources)
-endif
-all_cairo_pkgconf += cairo-xlib-xcb.pc
-ifeq ($(CAIRO_HAS_XLIB_XCB_FUNCTIONS),1)
-enabled_cairo_pkgconf += cairo-xlib-xcb.pc
-endif
-
-supported_cairo_headers += $(cairo_xcb_shm_headers)
-all_cairo_headers += $(cairo_xcb_shm_headers)
-all_cairo_private += $(cairo_xcb_shm_private)
-all_cairo_sources += $(cairo_xcb_shm_sources)
-ifeq ($(CAIRO_HAS_XCB_SHM_FUNCTIONS),1)
-enabled_cairo_headers += $(cairo_xcb_shm_headers)
-enabled_cairo_private += $(cairo_xcb_shm_private)
-enabled_cairo_sources += $(cairo_xcb_shm_sources)
-endif
-all_cairo_pkgconf += cairo-xcb-shm.pc
-ifeq ($(CAIRO_HAS_XCB_SHM_FUNCTIONS),1)
-enabled_cairo_pkgconf += cairo-xcb-shm.pc
-endif
-
-supported_cairo_headers += $(cairo_quartz_headers)
-all_cairo_headers += $(cairo_quartz_headers)
-all_cairo_private += $(cairo_quartz_private)
-all_cairo_sources += $(cairo_quartz_sources)
-ifeq ($(CAIRO_HAS_QUARTZ_SURFACE),1)
-enabled_cairo_headers += $(cairo_quartz_headers)
-enabled_cairo_private += $(cairo_quartz_private)
-enabled_cairo_sources += $(cairo_quartz_sources)
-endif
-all_cairo_pkgconf += cairo-quartz.pc
-ifeq ($(CAIRO_HAS_QUARTZ_SURFACE),1)
-enabled_cairo_pkgconf += cairo-quartz.pc
-endif
-
-supported_cairo_headers += $(cairo_quartz_font_headers)
-all_cairo_headers += $(cairo_quartz_font_headers)
-all_cairo_private += $(cairo_quartz_font_private)
-all_cairo_sources += $(cairo_quartz_font_sources)
-ifeq ($(CAIRO_HAS_QUARTZ_FONT),1)
-enabled_cairo_headers += $(cairo_quartz_font_headers)
-enabled_cairo_private += $(cairo_quartz_font_private)
-enabled_cairo_sources += $(cairo_quartz_font_sources)
-endif
-all_cairo_pkgconf += cairo-quartz-font.pc
-ifeq ($(CAIRO_HAS_QUARTZ_FONT),1)
-enabled_cairo_pkgconf += cairo-quartz-font.pc
-endif
-
-unsupported_cairo_headers += $(cairo_quartz_image_headers)
-all_cairo_headers += $(cairo_quartz_image_headers)
-all_cairo_private += $(cairo_quartz_image_private)
-all_cairo_sources += $(cairo_quartz_image_sources)
-ifeq ($(CAIRO_HAS_QUARTZ_IMAGE_SURFACE),1)
-enabled_cairo_headers += $(cairo_quartz_image_headers)
-enabled_cairo_private += $(cairo_quartz_image_private)
-enabled_cairo_sources += $(cairo_quartz_image_sources)
-endif
-all_cairo_pkgconf += cairo-quartz-image.pc
-ifeq ($(CAIRO_HAS_QUARTZ_IMAGE_SURFACE),1)
-enabled_cairo_pkgconf += cairo-quartz-image.pc
-endif
-
-supported_cairo_headers += $(cairo_win32_headers)
-all_cairo_headers += $(cairo_win32_headers)
-all_cairo_private += $(cairo_win32_private)
-all_cairo_sources += $(cairo_win32_sources)
-ifeq ($(CAIRO_HAS_WIN32_SURFACE),1)
-enabled_cairo_headers += $(cairo_win32_headers)
-enabled_cairo_private += $(cairo_win32_private)
-enabled_cairo_sources += $(cairo_win32_sources)
-endif
-all_cairo_pkgconf += cairo-win32.pc
-ifeq ($(CAIRO_HAS_WIN32_SURFACE),1)
-enabled_cairo_pkgconf += cairo-win32.pc
-endif
-
-supported_cairo_headers += $(cairo_win32_font_headers)
-all_cairo_headers += $(cairo_win32_font_headers)
-all_cairo_private += $(cairo_win32_font_private)
-all_cairo_sources += $(cairo_win32_font_sources)
-ifeq ($(CAIRO_HAS_WIN32_FONT),1)
-enabled_cairo_headers += $(cairo_win32_font_headers)
-enabled_cairo_private += $(cairo_win32_font_private)
-enabled_cairo_sources += $(cairo_win32_font_sources)
-endif
-all_cairo_pkgconf += cairo-win32-font.pc
-ifeq ($(CAIRO_HAS_WIN32_FONT),1)
-enabled_cairo_pkgconf += cairo-win32-font.pc
-endif
-
-supported_cairo_headers += $(cairo_png_headers)
-all_cairo_headers += $(cairo_png_headers)
-all_cairo_private += $(cairo_png_private)
-all_cairo_sources += $(cairo_png_sources)
-ifeq ($(CAIRO_HAS_PNG_FUNCTIONS),1)
-enabled_cairo_headers += $(cairo_png_headers)
-enabled_cairo_private += $(cairo_png_private)
-enabled_cairo_sources += $(cairo_png_sources)
-endif
-all_cairo_pkgconf += cairo-png.pc
-ifeq ($(CAIRO_HAS_PNG_FUNCTIONS),1)
-enabled_cairo_pkgconf += cairo-png.pc
-endif
-
-unsupported_cairo_headers += $(cairo_gl_headers)
-all_cairo_headers += $(cairo_gl_headers)
-all_cairo_private += $(cairo_gl_private)
-all_cairo_sources += $(cairo_gl_sources)
-ifeq ($(CAIRO_HAS_GL_SURFACE),1)
-enabled_cairo_headers += $(cairo_gl_headers)
-enabled_cairo_private += $(cairo_gl_private)
-enabled_cairo_sources += $(cairo_gl_sources)
-endif
-all_cairo_pkgconf += cairo-gl.pc
-ifeq ($(CAIRO_HAS_GL_SURFACE),1)
-enabled_cairo_pkgconf += cairo-gl.pc
-endif
-
-unsupported_cairo_headers += $(cairo_glesv2_headers)
-all_cairo_headers += $(cairo_glesv2_headers)
-all_cairo_private += $(cairo_glesv2_private)
-all_cairo_sources += $(cairo_glesv2_sources)
-ifeq ($(CAIRO_HAS_GLESV2_SURFACE),1)
-enabled_cairo_headers += $(cairo_glesv2_headers)
-enabled_cairo_private += $(cairo_glesv2_private)
-enabled_cairo_sources += $(cairo_glesv2_sources)
-endif
-all_cairo_pkgconf += cairo-glesv2.pc
-ifeq ($(CAIRO_HAS_GLESV2_SURFACE),1)
-enabled_cairo_pkgconf += cairo-glesv2.pc
-endif
-
-unsupported_cairo_headers += $(cairo_glesv3_headers)
-all_cairo_headers += $(cairo_glesv3_headers)
-all_cairo_private += $(cairo_glesv3_private)
-all_cairo_sources += $(cairo_glesv3_sources)
-ifeq ($(CAIRO_HAS_GLESV3_SURFACE),1)
-enabled_cairo_headers += $(cairo_glesv3_headers)
-enabled_cairo_private += $(cairo_glesv3_private)
-enabled_cairo_sources += $(cairo_glesv3_sources)
-endif
-all_cairo_pkgconf += cairo-glesv3.pc
-ifeq ($(CAIRO_HAS_GLESV3_SURFACE),1)
-enabled_cairo_pkgconf += cairo-glesv3.pc
-endif
-
-supported_cairo_headers += $(cairo_egl_headers)
-all_cairo_headers += $(cairo_egl_headers)
-all_cairo_private += $(cairo_egl_private)
-all_cairo_sources += $(cairo_egl_sources)
-ifeq ($(CAIRO_HAS_EGL_FUNCTIONS),1)
-enabled_cairo_headers += $(cairo_egl_headers)
-enabled_cairo_private += $(cairo_egl_private)
-enabled_cairo_sources += $(cairo_egl_sources)
-endif
-all_cairo_pkgconf += cairo-egl.pc
-ifeq ($(CAIRO_HAS_EGL_FUNCTIONS),1)
-enabled_cairo_pkgconf += cairo-egl.pc
-endif
-
-supported_cairo_headers += $(cairo_glx_headers)
-all_cairo_headers += $(cairo_glx_headers)
-all_cairo_private += $(cairo_glx_private)
-all_cairo_sources += $(cairo_glx_sources)
-ifeq ($(CAIRO_HAS_GLX_FUNCTIONS),1)
-enabled_cairo_headers += $(cairo_glx_headers)
-enabled_cairo_private += $(cairo_glx_private)
-enabled_cairo_sources += $(cairo_glx_sources)
-endif
-all_cairo_pkgconf += cairo-glx.pc
-ifeq ($(CAIRO_HAS_GLX_FUNCTIONS),1)
-enabled_cairo_pkgconf += cairo-glx.pc
-endif
-
-supported_cairo_headers += $(cairo_wgl_headers)
-all_cairo_headers += $(cairo_wgl_headers)
-all_cairo_private += $(cairo_wgl_private)
-all_cairo_sources += $(cairo_wgl_sources)
-ifeq ($(CAIRO_HAS_WGL_FUNCTIONS),1)
-enabled_cairo_headers += $(cairo_wgl_headers)
-enabled_cairo_private += $(cairo_wgl_private)
-enabled_cairo_sources += $(cairo_wgl_sources)
-endif
-all_cairo_pkgconf += cairo-wgl.pc
-ifeq ($(CAIRO_HAS_WGL_FUNCTIONS),1)
-enabled_cairo_pkgconf += cairo-wgl.pc
-endif
-
-supported_cairo_headers += $(cairo_script_headers)
-all_cairo_headers += $(cairo_script_headers)
-all_cairo_private += $(cairo_script_private)
-all_cairo_sources += $(cairo_script_sources)
-ifeq ($(CAIRO_HAS_SCRIPT_SURFACE),1)
-enabled_cairo_headers += $(cairo_script_headers)
-enabled_cairo_private += $(cairo_script_private)
-enabled_cairo_sources += $(cairo_script_sources)
-endif
-all_cairo_pkgconf += cairo-script.pc
-ifeq ($(CAIRO_HAS_SCRIPT_SURFACE),1)
-enabled_cairo_pkgconf += cairo-script.pc
-endif
-
-supported_cairo_headers += $(cairo_ft_headers)
-all_cairo_headers += $(cairo_ft_headers)
-all_cairo_private += $(cairo_ft_private)
-all_cairo_sources += $(cairo_ft_sources)
-ifeq ($(CAIRO_HAS_FT_FONT),1)
-enabled_cairo_headers += $(cairo_ft_headers)
-enabled_cairo_private += $(cairo_ft_private)
-enabled_cairo_sources += $(cairo_ft_sources)
-endif
-all_cairo_pkgconf += cairo-ft.pc
-ifeq ($(CAIRO_HAS_FT_FONT),1)
-enabled_cairo_pkgconf += cairo-ft.pc
-endif
-
-supported_cairo_headers += $(cairo_fc_headers)
-all_cairo_headers += $(cairo_fc_headers)
-all_cairo_private += $(cairo_fc_private)
-all_cairo_sources += $(cairo_fc_sources)
-ifeq ($(CAIRO_HAS_FC_FONT),1)
-enabled_cairo_headers += $(cairo_fc_headers)
-enabled_cairo_private += $(cairo_fc_private)
-enabled_cairo_sources += $(cairo_fc_sources)
-endif
-all_cairo_pkgconf += cairo-fc.pc
-ifeq ($(CAIRO_HAS_FC_FONT),1)
-enabled_cairo_pkgconf += cairo-fc.pc
-endif
-
-supported_cairo_headers += $(cairo_ps_headers)
-all_cairo_headers += $(cairo_ps_headers)
-all_cairo_private += $(cairo_ps_private)
-all_cairo_sources += $(cairo_ps_sources)
-ifeq ($(CAIRO_HAS_PS_SURFACE),1)
-enabled_cairo_headers += $(cairo_ps_headers)
-enabled_cairo_private += $(cairo_ps_private)
-enabled_cairo_sources += $(cairo_ps_sources)
-endif
-all_cairo_pkgconf += cairo-ps.pc
-ifeq ($(CAIRO_HAS_PS_SURFACE),1)
-enabled_cairo_pkgconf += cairo-ps.pc
-endif
-
-supported_cairo_headers += $(cairo_pdf_headers)
-all_cairo_headers += $(cairo_pdf_headers)
-all_cairo_private += $(cairo_pdf_private)
-all_cairo_sources += $(cairo_pdf_sources)
-ifeq ($(CAIRO_HAS_PDF_SURFACE),1)
-enabled_cairo_headers += $(cairo_pdf_headers)
-enabled_cairo_private += $(cairo_pdf_private)
-enabled_cairo_sources += $(cairo_pdf_sources)
-endif
-all_cairo_pkgconf += cairo-pdf.pc
-ifeq ($(CAIRO_HAS_PDF_SURFACE),1)
-enabled_cairo_pkgconf += cairo-pdf.pc
-endif
-
-supported_cairo_headers += $(cairo_svg_headers)
-all_cairo_headers += $(cairo_svg_headers)
-all_cairo_private += $(cairo_svg_private)
-all_cairo_sources += $(cairo_svg_sources)
-ifeq ($(CAIRO_HAS_SVG_SURFACE),1)
-enabled_cairo_headers += $(cairo_svg_headers)
-enabled_cairo_private += $(cairo_svg_private)
-enabled_cairo_sources += $(cairo_svg_sources)
-endif
-all_cairo_pkgconf += cairo-svg.pc
-ifeq ($(CAIRO_HAS_SVG_SURFACE),1)
-enabled_cairo_pkgconf += cairo-svg.pc
-endif
-
-all_cairo_private += $(cairo_test_surfaces_private) $(cairo_test_surfaces_headers)
-all_cairo_sources += $(cairo_test_surfaces_sources)
-ifeq ($(CAIRO_HAS_TEST_SURFACES),1)
-enabled_cairo_private += $(cairo_test_surfaces_private) $(cairo_test_surfaces_headers)
-enabled_cairo_sources += $(cairo_test_surfaces_sources)
-endif
-
-supported_cairo_headers += $(cairo_image_headers)
-all_cairo_headers += $(cairo_image_headers)
-all_cairo_private += $(cairo_image_private)
-all_cairo_sources += $(cairo_image_sources)
-enabled_cairo_headers += $(cairo_image_headers)
-enabled_cairo_private += $(cairo_image_private)
-enabled_cairo_sources += $(cairo_image_sources)
-
-supported_cairo_headers += $(cairo_mime_headers)
-all_cairo_headers += $(cairo_mime_headers)
-all_cairo_private += $(cairo_mime_private)
-all_cairo_sources += $(cairo_mime_sources)
-enabled_cairo_headers += $(cairo_mime_headers)
-enabled_cairo_private += $(cairo_mime_private)
-enabled_cairo_sources += $(cairo_mime_sources)
-
-supported_cairo_headers += $(cairo_recording_headers)
-all_cairo_headers += $(cairo_recording_headers)
-all_cairo_private += $(cairo_recording_private)
-all_cairo_sources += $(cairo_recording_sources)
-enabled_cairo_headers += $(cairo_recording_headers)
-enabled_cairo_private += $(cairo_recording_private)
-enabled_cairo_sources += $(cairo_recording_sources)
-
-supported_cairo_headers += $(cairo_observer_headers)
-all_cairo_headers += $(cairo_observer_headers)
-all_cairo_private += $(cairo_observer_private)
-all_cairo_sources += $(cairo_observer_sources)
-enabled_cairo_headers += $(cairo_observer_headers)
-enabled_cairo_private += $(cairo_observer_private)
-enabled_cairo_sources += $(cairo_observer_sources)
-
-unsupported_cairo_headers += $(cairo_tee_headers)
-all_cairo_headers += $(cairo_tee_headers)
-all_cairo_private += $(cairo_tee_private)
-all_cairo_sources += $(cairo_tee_sources)
-ifeq ($(CAIRO_HAS_TEE_SURFACE),1)
-enabled_cairo_headers += $(cairo_tee_headers)
-enabled_cairo_private += $(cairo_tee_private)
-enabled_cairo_sources += $(cairo_tee_sources)
-endif
-all_cairo_pkgconf += cairo-tee.pc
-ifeq ($(CAIRO_HAS_TEE_SURFACE),1)
-enabled_cairo_pkgconf += cairo-tee.pc
-endif
-
-unsupported_cairo_headers += $(cairo_xml_headers)
-all_cairo_headers += $(cairo_xml_headers)
-all_cairo_private += $(cairo_xml_private)
-all_cairo_sources += $(cairo_xml_sources)
-ifeq ($(CAIRO_HAS_XML_SURFACE),1)
-enabled_cairo_headers += $(cairo_xml_headers)
-enabled_cairo_private += $(cairo_xml_private)
-enabled_cairo_sources += $(cairo_xml_sources)
-endif
-all_cairo_pkgconf += cairo-xml.pc
-ifeq ($(CAIRO_HAS_XML_SURFACE),1)
-enabled_cairo_pkgconf += cairo-xml.pc
-endif
-
-supported_cairo_headers += $(cairo_user_headers)
-all_cairo_headers += $(cairo_user_headers)
-all_cairo_private += $(cairo_user_private)
-all_cairo_sources += $(cairo_user_sources)
-enabled_cairo_headers += $(cairo_user_headers)
-enabled_cairo_private += $(cairo_user_private)
-enabled_cairo_sources += $(cairo_user_sources)
-
-all_cairo_private += $(cairo_pthread_private) $(cairo_pthread_headers)
-all_cairo_sources += $(cairo_pthread_sources)
-ifeq ($(CAIRO_HAS_PTHREAD),1)
-enabled_cairo_private += $(cairo_pthread_private) $(cairo_pthread_headers)
-enabled_cairo_sources += $(cairo_pthread_sources)
-endif
-
-supported_cairo_headers += $(cairo_gobject_headers)
-all_cairo_headers += $(cairo_gobject_headers)
-all_cairo_private += $(cairo_gobject_private)
-all_cairo_sources += $(cairo_gobject_sources)
-ifeq ($(CAIRO_HAS_GOBJECT_FUNCTIONS),1)
-enabled_cairo_headers += $(cairo_gobject_headers)
-enabled_cairo_private += $(cairo_gobject_private)
-enabled_cairo_sources += $(cairo_gobject_sources)
-endif
-all_cairo_pkgconf += cairo-gobject.pc
-ifeq ($(CAIRO_HAS_GOBJECT_FUNCTIONS),1)
-enabled_cairo_pkgconf += cairo-gobject.pc
-endif
-
-all_cairo_private += $(cairo_trace_private) $(cairo_trace_headers)
-all_cairo_sources += $(cairo_trace_sources)
-ifeq ($(CAIRO_HAS_TRACE),1)
-enabled_cairo_private += $(cairo_trace_private) $(cairo_trace_headers)
-enabled_cairo_sources += $(cairo_trace_sources)
-endif
-
-all_cairo_private += $(cairo_interpreter_private) $(cairo_interpreter_headers)
-all_cairo_sources += $(cairo_interpreter_sources)
-ifeq ($(CAIRO_HAS_INTERPRETER),1)
-enabled_cairo_private += $(cairo_interpreter_private) $(cairo_interpreter_headers)
-enabled_cairo_sources += $(cairo_interpreter_sources)
-endif
-
-all_cairo_private += $(cairo_symbol_lookup_private) $(cairo_symbol_lookup_headers)
-all_cairo_sources += $(cairo_symbol_lookup_sources)
-ifeq ($(CAIRO_HAS_SYMBOL_LOOKUP),1)
-enabled_cairo_private += $(cairo_symbol_lookup_private) $(cairo_symbol_lookup_headers)
-enabled_cairo_sources += $(cairo_symbol_lookup_sources)
-endif
diff --git a/src/cairo-analysis-surface-private.h b/src/cairo-analysis-surface-private.h
index 1e054c209..6489cceb8 100644
--- a/src/cairo-analysis-surface-private.h
+++ b/src/cairo-analysis-surface-private.h
@@ -38,7 +38,8 @@
#include "cairoint.h"
cairo_private cairo_surface_t *
-_cairo_analysis_surface_create (cairo_surface_t *target);
+_cairo_analysis_surface_create (cairo_surface_t *target,
+ cairo_bool_t create_region_ids);
cairo_private void
_cairo_analysis_surface_set_ctm (cairo_surface_t *surface,
@@ -64,6 +65,12 @@ cairo_private void
_cairo_analysis_surface_get_bounding_box (cairo_surface_t *surface,
cairo_box_t *bbox);
+cairo_private unsigned int
+_cairo_analysis_surface_get_source_region_id (cairo_surface_t *surface);
+
+cairo_private unsigned int
+_cairo_analysis_surface_get_mask_region_id (cairo_surface_t *surface);
+
cairo_private cairo_int_status_t
_cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
cairo_int_status_t status_b);
@@ -71,4 +78,10 @@ _cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
cairo_private cairo_surface_t *
_cairo_null_surface_create (cairo_content_t content);
+static inline cairo_bool_t
+_cairo_surface_is_analysis (const cairo_surface_t *surface)
+{
+ return (cairo_internal_surface_type_t)surface->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS;
+}
+
#endif /* CAIRO_ANALYSIS_SURFACE_H */
diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
index a118e338c..0e7ba8a38 100644
--- a/src/cairo-analysis-surface.c
+++ b/src/cairo-analysis-surface.c
@@ -1,3 +1,4 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/*
* Copyright © 2006 Keith Packard
* Copyright © 2007 Adrian Johnson
@@ -59,6 +60,10 @@ typedef struct {
cairo_region_t fallback_region;
cairo_box_t page_bbox;
+ cairo_bool_t create_region_ids;
+ unsigned source_region_id;
+ unsigned mask_region_id;
+
cairo_bool_t has_ctm;
cairo_matrix_t ctm;
@@ -257,7 +262,8 @@ _add_operation (cairo_analysis_surface_t *surface,
static cairo_int_status_t
_analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
const cairo_pattern_t *pattern,
- cairo_rectangle_int_t *extents)
+ cairo_rectangle_int_t *extents,
+ unsigned int *regions_id)
{
const cairo_surface_pattern_t *surface_pattern;
cairo_analysis_surface_t *tmp;
@@ -280,7 +286,7 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
}
tmp = (cairo_analysis_surface_t *)
- _cairo_analysis_surface_create (surface->target);
+ _cairo_analysis_surface_create (surface->target, surface->create_region_ids);
if (unlikely (tmp->base.status)) {
status =tmp->base.status;
goto cleanup1;
@@ -295,13 +301,29 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
source = _cairo_surface_get_source (source, NULL);
surface_is_unbounded = (pattern->extend == CAIRO_EXTEND_REPEAT
- || pattern->extend == CAIRO_EXTEND_REFLECT);
- status = _cairo_recording_surface_replay_and_create_regions (source,
- &pattern->matrix,
- &tmp->base,
- surface_is_unbounded);
- if (unlikely (status))
- goto cleanup2;
+ || pattern->extend == CAIRO_EXTEND_REFLECT);
+
+ if (surface->create_region_ids) {
+ status = _cairo_recording_surface_region_array_attach (source, regions_id);
+ if (unlikely (status))
+ goto cleanup2;
+
+ status = _cairo_recording_surface_replay_and_create_regions (source,
+ *regions_id,
+ &pattern->matrix,
+ &tmp->base,
+ surface_is_unbounded);
+ if (unlikely (status))
+ goto cleanup2;
+ } else {
+ status = _cairo_recording_surface_replay_with_clip (source,
+ &pattern->matrix,
+ &tmp->base,
+ NULL, /* target clip */
+ surface_is_unbounded);
+ if (unlikely (status))
+ goto cleanup2;
+ }
/* black background or mime data fills entire extents */
if (!(source->content & CAIRO_CONTENT_ALPHA) || _cairo_surface_has_mime_image (source)) {
@@ -412,6 +434,8 @@ _cairo_analysis_surface_paint (void *abstract_surface,
cairo_int_status_t backend_status;
cairo_rectangle_int_t extents;
+ surface->source_region_id = 0;
+ surface->mask_region_id = 0;
if (surface->target->backend->paint == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
} else {
@@ -427,7 +451,10 @@ _cairo_analysis_surface_paint (void *abstract_surface,
&extents);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
cairo_rectangle_int_t rec_extents;
- backend_status = _analyze_recording_surface_pattern (surface, source, &rec_extents);
+ backend_status = _analyze_recording_surface_pattern (surface,
+ source,
+ &rec_extents,
+ &surface->source_region_id);
_cairo_rectangle_intersect (&extents, &rec_extents);
}
@@ -445,6 +472,8 @@ _cairo_analysis_surface_mask (void *abstract_surface,
cairo_int_status_t backend_status;
cairo_rectangle_int_t extents;
+ surface->source_region_id = 0;
+ surface->mask_region_id = 0;
if (surface->target->backend->mask == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
} else {
@@ -468,7 +497,10 @@ _cairo_analysis_surface_mask (void *abstract_surface,
src_surface = _cairo_surface_get_source (src_surface, NULL);
if (_cairo_surface_is_recording (src_surface)) {
backend_source_status =
- _analyze_recording_surface_pattern (surface, source, &rec_extents);
+ _analyze_recording_surface_pattern (surface,
+ source,
+ &rec_extents,
+ &surface->source_region_id);
if (_cairo_int_status_is_error (backend_source_status))
return backend_source_status;
@@ -481,7 +513,10 @@ _cairo_analysis_surface_mask (void *abstract_surface,
mask_surface = _cairo_surface_get_source (mask_surface, NULL);
if (_cairo_surface_is_recording (mask_surface)) {
backend_mask_status =
- _analyze_recording_surface_pattern (surface, mask, &rec_extents);
+ _analyze_recording_surface_pattern (surface,
+ mask,
+ &rec_extents,
+ &surface->mask_region_id);
if (_cairo_int_status_is_error (backend_mask_status))
return backend_mask_status;
@@ -520,6 +555,8 @@ _cairo_analysis_surface_stroke (void *abstract_surface,
cairo_int_status_t backend_status;
cairo_rectangle_int_t extents;
+ surface->source_region_id = 0;
+ surface->mask_region_id = 0;
if (surface->target->backend->stroke == NULL) {
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
} else {
@@ -538,7 +575,10 @@ _cairo_analysis_surface_stroke (void *abstract_surface,
&extents);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
cairo_rectangle_int_t rec_extents;
- backend_status = _analyze_recording_surface_pattern (surface, source, &rec_extents);
+ backend_status = _analyze_recording_surface_pattern (surface,
+ source,
+ &rec_extents,
+ &surface->source_region_id);
_cairo_rectangle_intersect (&extents, &rec_extents);
}
@@ -590,7 +630,10 @@ _cairo_analysis_surface_fill (void *abstract_surface,
&extents);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
cairo_rectangle_int_t rec_extents;
- backend_status = _analyze_recording_surface_pattern (surface, source, &rec_extents);
+ backend_status = _analyze_recording_surface_pattern (surface,
+ source,
+ &rec_extents,
+ &surface->source_region_id);
_cairo_rectangle_intersect (&extents, &rec_extents);
}
@@ -619,6 +662,9 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
cairo_int_status_t status, backend_status;
cairo_rectangle_int_t extents, glyph_extents;
+ surface->source_region_id = 0;
+ surface->mask_region_id = 0;
+
/* Adapted from _cairo_surface_show_glyphs */
if (surface->target->backend->show_glyphs != NULL) {
backend_status =
@@ -654,7 +700,10 @@ _cairo_analysis_surface_show_glyphs (void *abstract_surface,
&extents);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
cairo_rectangle_int_t rec_extents;
- backend_status = _analyze_recording_surface_pattern (surface, source, &rec_extents);
+ backend_status = _analyze_recording_surface_pattern (surface,
+ source,
+ &rec_extents,
+ &surface->source_region_id);
_cairo_rectangle_intersect (&extents, &rec_extents);
}
@@ -699,6 +748,9 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
cairo_int_status_t status, backend_status;
cairo_rectangle_int_t extents, glyph_extents;
+ surface->source_region_id = 0;
+ surface->mask_region_id = 0;
+
/* Adapted from _cairo_surface_show_glyphs */
backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
if (surface->target->backend->show_text_glyphs != NULL) {
@@ -732,7 +784,10 @@ _cairo_analysis_surface_show_text_glyphs (void *abstract_surface,
&extents);
if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
cairo_rectangle_int_t rec_extents;
- backend_status = _analyze_recording_surface_pattern (surface, source, &rec_extents);
+ _analyze_recording_surface_pattern (surface,
+ source,
+ &rec_extents,
+ &surface->source_region_id);
_cairo_rectangle_intersect (&extents, &rec_extents);
}
@@ -760,6 +815,8 @@ _cairo_analysis_surface_tag (void *abstract_surface,
cairo_analysis_surface_t *surface = abstract_surface;
cairo_int_status_t backend_status;
+ surface->source_region_id = 0;
+ surface->mask_region_id = 0;
backend_status = CAIRO_INT_STATUS_SUCCESS;
if (surface->target->backend->tag != NULL) {
backend_status =
@@ -774,6 +831,14 @@ _cairo_analysis_surface_tag (void *abstract_surface,
return backend_status;
}
+static cairo_bool_t
+_cairo_analysis_surface_supports_color_glyph (void *abstract_surface,
+ cairo_scaled_font_t *scaled_font,
+ unsigned long glyph_index)
+{
+ return TRUE;
+}
+
static const cairo_surface_backend_t cairo_analysis_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
@@ -808,11 +873,13 @@ static const cairo_surface_backend_t cairo_analysis_surface_backend = {
_cairo_analysis_surface_has_show_text_glyphs,
_cairo_analysis_surface_show_text_glyphs,
NULL, /* get_supported_mime_types */
- _cairo_analysis_surface_tag
+ _cairo_analysis_surface_tag,
+ _cairo_analysis_surface_supports_color_glyph
};
cairo_surface_t *
-_cairo_analysis_surface_create (cairo_surface_t *target)
+_cairo_analysis_surface_create (cairo_surface_t *target,
+ cairo_bool_t create_region_ids)
{
cairo_analysis_surface_t *surface;
cairo_status_t status;
@@ -841,6 +908,10 @@ _cairo_analysis_surface_create (cairo_surface_t *target)
surface->has_supported = FALSE;
surface->has_unsupported = FALSE;
+ surface->create_region_ids = create_region_ids;
+ surface->source_region_id = 0;
+ surface->mask_region_id = 0;
+
_cairo_region_init (&surface->supported_region);
_cairo_region_init (&surface->fallback_region);
@@ -918,6 +989,23 @@ _cairo_analysis_surface_get_bounding_box (cairo_surface_t *abstract_surface,
*bbox = surface->page_bbox;
}
+unsigned int
+_cairo_analysis_surface_get_source_region_id (cairo_surface_t *abstract_surface)
+{
+ cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
+
+ return surface->source_region_id;
+}
+
+unsigned int
+_cairo_analysis_surface_get_mask_region_id (cairo_surface_t *abstract_surface)
+{
+ cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
+
+ return surface->mask_region_id;
+}
+
+
/* null surface type: a surface that does nothing (has no side effects, yay!) */
static cairo_int_status_t
@@ -926,6 +1014,12 @@ _paint_return_success (void *surface,
const cairo_pattern_t *source,
const cairo_clip_t *clip)
{
+ if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source;
+ if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
+ return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
+ }
+
return CAIRO_INT_STATUS_SUCCESS;
}
@@ -936,6 +1030,18 @@ _mask_return_success (void *surface,
const cairo_pattern_t *mask,
const cairo_clip_t *clip)
{
+ if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source;
+ if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
+ return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
+ }
+
+ if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask;
+ if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
+ return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
+ }
+
return CAIRO_INT_STATUS_SUCCESS;
}
@@ -951,6 +1057,12 @@ _stroke_return_success (void *surface,
cairo_antialias_t antialias,
const cairo_clip_t *clip)
{
+ if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source;
+ if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
+ return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
+ }
+
return CAIRO_INT_STATUS_SUCCESS;
}
@@ -964,6 +1076,12 @@ _fill_return_success (void *surface,
cairo_antialias_t antialias,
const cairo_clip_t *clip)
{
+ if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source;
+ if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
+ return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
+ }
+
return CAIRO_INT_STATUS_SUCCESS;
}
@@ -976,6 +1094,12 @@ _show_glyphs_return_success (void *surface,
cairo_scaled_font_t *scaled_font,
const cairo_clip_t *clip)
{
+ if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source;
+ if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
+ return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
+ }
+
return CAIRO_INT_STATUS_SUCCESS;
}
diff --git a/src/cairo-array.c b/src/cairo-array.c
index db7b6de7a..1c91b7c73 100644
--- a/src/cairo-array.c
+++ b/src/cairo-array.c
@@ -143,7 +143,6 @@ _cairo_array_truncate (cairo_array_t *array, unsigned int num_elements)
/**
* _cairo_array_index:
* @array: a #cairo_array_t
- * Returns: A pointer to the object stored at @index.
*
* If the resulting value is assigned to a pointer to an object of the same
* element_size as initially passed to _cairo_array_init() then that
@@ -161,6 +160,8 @@ _cairo_array_truncate (cairo_array_t *array, unsigned int num_elements)
* for (i = 0; i < _cairo_array_num_elements (&array); i++)
* ... use values[i] here ...
* </programlisting></informalexample>
+ *
+ * Returns: A pointer to the object stored at @index.
**/
void *
_cairo_array_index (cairo_array_t *array, unsigned int index)
@@ -187,7 +188,6 @@ _cairo_array_index (cairo_array_t *array, unsigned int index)
/**
* _cairo_array_index_const:
* @array: a #cairo_array_t
- * Returns: A pointer to the object stored at @index.
*
* If the resulting value is assigned to a pointer to an object of the same
* element_size as initially passed to _cairo_array_init() then that
@@ -205,6 +205,8 @@ _cairo_array_index (cairo_array_t *array, unsigned int index)
* for (i = 0; i < _cairo_array_num_elements (&array); i++)
* ... read values[i] here ...
* </programlisting></informalexample>
+ *
+ * Returns: A pointer to the object stored at @index.
**/
const void *
_cairo_array_index_const (const cairo_array_t *array, unsigned int index)
@@ -330,9 +332,10 @@ _cairo_array_allocate (cairo_array_t *array,
/**
* _cairo_array_num_elements:
* @array: a #cairo_array_t
- * Returns: The number of elements stored in @array.
*
* This space was left intentionally blank, but gtk-doc filled it.
+ *
+ * Returns: The number of elements stored in @array.
**/
unsigned int
_cairo_array_num_elements (const cairo_array_t *array)
@@ -343,10 +346,11 @@ _cairo_array_num_elements (const cairo_array_t *array)
/**
* _cairo_array_size:
* @array: a #cairo_array_t
- * Returns: The number of elements for which there is currently space
- * allocated in @array.
*
* This space was left intentionally blank, but gtk-doc filled it.
+ *
+ * Returns: The number of elements for which there is currently space
+ * allocated in @array.
**/
unsigned int
_cairo_array_size (const cairo_array_t *array)
diff --git a/src/cairo-atomic-private.h b/src/cairo-atomic-private.h
index a9eb38a7f..727f97c75 100644
--- a/src/cairo-atomic-private.h
+++ b/src/cairo-atomic-private.h
@@ -340,6 +340,8 @@ _cairo_atomic_ptr_cmpxchg_return_old (void **x, void *oldv, void *newv)
#ifndef HAS_ATOMIC_OPS
+typedef int cairo_atomic_int_t;
+
#if SIZEOF_VOID_P==SIZEOF_INT
typedef unsigned int cairo_atomic_intptr_t;
#elif SIZEOF_VOID_P==SIZEOF_LONG
@@ -350,8 +352,6 @@ typedef unsigned long long cairo_atomic_intptr_t;
#error No matching integer pointer type
#endif
-typedef cairo_atomic_intptr_t cairo_atomic_int_t;
-
cairo_private void
_cairo_atomic_int_inc (cairo_atomic_int_t *x);
@@ -376,7 +376,8 @@ cairo_private cairo_atomic_int_t
_cairo_atomic_int_get_relaxed (cairo_atomic_int_t *x);
void
_cairo_atomic_int_set_relaxed (cairo_atomic_int_t *x, cairo_atomic_int_t val);
-# define _cairo_atomic_ptr_get(x) (void *) _cairo_atomic_int_get((cairo_atomic_int_t *) x)
+cairo_private void*
+_cairo_atomic_ptr_get(void **x);
#else
# define _cairo_atomic_int_get(x) (*x)
# define _cairo_atomic_int_get_relaxed(x) (*x)
@@ -441,6 +442,7 @@ _cairo_atomic_ptr_cmpxchg_return_old_fallback(void **x, void *oldv, void *newv)
#define _cairo_status_set_error(status, err) do { \
int ret__; \
assert (err < CAIRO_STATUS_LAST_STATUS); \
+ assert (sizeof(*status) == sizeof(cairo_atomic_int_t)); \
/* hide compiler warnings about cairo_status_t != int (gcc treats its as \
* an unsigned integer instead, and about ignoring the return value. */ \
ret__ = _cairo_atomic_int_cmpxchg ((cairo_atomic_int_t *) status, CAIRO_STATUS_SUCCESS, err); \
diff --git a/src/cairo-atomic.c b/src/cairo-atomic.c
index 2af50cd38..3c4d51972 100644
--- a/src/cairo-atomic.c
+++ b/src/cairo-atomic.c
@@ -42,7 +42,7 @@ COMPILE_TIME_ASSERT(sizeof(void*) == sizeof(int) ||
sizeof(void*) == sizeof(long long));
#else
void
-_cairo_atomic_int_inc (cairo_atomic_intptr_t *x)
+_cairo_atomic_int_inc (cairo_atomic_int_t *x)
{
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
*x += 1;
@@ -50,7 +50,7 @@ _cairo_atomic_int_inc (cairo_atomic_intptr_t *x)
}
cairo_bool_t
-_cairo_atomic_int_dec_and_test (cairo_atomic_intptr_t *x)
+_cairo_atomic_int_dec_and_test (cairo_atomic_int_t *x)
{
cairo_bool_t ret;
@@ -61,10 +61,10 @@ _cairo_atomic_int_dec_and_test (cairo_atomic_intptr_t *x)
return ret;
}
-cairo_atomic_intptr_t
-_cairo_atomic_int_cmpxchg_return_old_impl (cairo_atomic_intptr_t *x, cairo_atomic_intptr_t oldv, cairo_atomic_intptr_t newv)
+cairo_atomic_int_t
+_cairo_atomic_int_cmpxchg_return_old_impl (cairo_atomic_int_t *x, cairo_atomic_int_t oldv, cairo_atomic_int_t newv)
{
- cairo_atomic_intptr_t ret;
+ cairo_atomic_int_t ret;
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
ret = *x;
@@ -90,10 +90,10 @@ _cairo_atomic_ptr_cmpxchg_return_old_impl (void **x, void *oldv, void *newv)
}
#ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER
-cairo_atomic_intptr_t
-_cairo_atomic_int_get (cairo_atomic_intptr_t *x)
+cairo_atomic_int_t
+_cairo_atomic_int_get (cairo_atomic_int_t *x)
{
- cairo_atomic_intptr_t ret;
+ cairo_atomic_int_t ret;
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
ret = *x;
@@ -102,19 +102,31 @@ _cairo_atomic_int_get (cairo_atomic_intptr_t *x)
return ret;
}
-cairo_atomic_intptr_t
-_cairo_atomic_int_get_relaxed (cairo_atomic_intptr_t *x)
+cairo_atomic_int_t
+_cairo_atomic_int_get_relaxed (cairo_atomic_int_t *x)
{
return _cairo_atomic_int_get (x);
}
void
-_cairo_atomic_int_set_relaxed (cairo_atomic_intptr_t *x, cairo_atomic_intptr_t val)
+_cairo_atomic_int_set_relaxed (cairo_atomic_int_t *x, cairo_atomic_int_t val)
{
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
*x = val;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
}
+
+void*
+_cairo_atomic_ptr_get (void **x)
+{
+ void *ret;
+
+ CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
+ ret = *x;
+ CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
+
+ return ret;
+}
#endif
#endif
diff --git a/src/cairo-boxes.c b/src/cairo-boxes.c
index 3c5d2a750..383a3eefb 100644
--- a/src/cairo-boxes.c
+++ b/src/cairo-boxes.c
@@ -102,16 +102,16 @@ _cairo_boxes_init_for_array (cairo_boxes_t *boxes,
boxes->is_pixel_aligned = n == num_boxes;
}
-/** _cairo_boxes_limit:
+/**
+ * _cairo_boxes_limit:
+ * @boxes: the box set to be filled (return buffer)
+ * @limits: array of the limiting boxes to compute the bounding
+ * box from
+ * @num_limits: length of the limits array
*
* Computes the minimum bounding box of the given list of boxes and assign
* it to the given boxes set. It also assigns that list as the list of
* limiting boxes in the box set.
- *
- * @param boxes the box set to be filled (return buffer)
- * @param limits array of the limiting boxes to compute the bounding
- * box from
- * @param num_limits length of the limits array
*/
void
_cairo_boxes_limit (cairo_boxes_t *boxes,
@@ -276,13 +276,13 @@ _cairo_boxes_add (cairo_boxes_t *boxes,
return boxes->status;
}
-/** _cairo_boxes_extents:
+/**
+ * _cairo_boxes_extents:
+ * @boxes: The box set whose minimum bounding is computed.
+ * @box: Return buffer for the computed result.
*
* Computes the minimum bounding box of the given box set and stores
* it in the given box.
- *
- * @param boxes The box set whose minimum bounding is computed.
- * @param box Return buffer for the computed result.
*/
void
_cairo_boxes_extents (const cairo_boxes_t *boxes,
@@ -336,15 +336,16 @@ _cairo_boxes_clear (cairo_boxes_t *boxes)
boxes->is_pixel_aligned = TRUE;
}
-/** _cairo_boxes_to_array:
+/**
+ * _cairo_boxes_to_array:
+ * @boxes The box set to be converted.
+ * @num_boxes Return buffer for the number of boxes (array count).
*
* Linearize a box set of possibly multiple chunks into one big chunk
* and returns an array of boxes
*
- * @param boxes The box set to be converted.
- * @param num_boxes Return buffer for the number of boxes (array count).
- * @return Pointer to the newly allocated array of boxes
- * (the number o elements is given in num_boxes).
+ * Return value: Pointer to the newly allocated array of boxes (the number o
+ * elements is given in num_boxes).
*/
cairo_box_t *
_cairo_boxes_to_array (const cairo_boxes_t *boxes,
diff --git a/src/cairo-cache.c b/src/cairo-cache.c
index 96809b585..afdca984e 100644
--- a/src/cairo-cache.c
+++ b/src/cairo-cache.c
@@ -56,7 +56,6 @@ _cairo_cache_entry_is_non_zero (const void *entry)
* @keys_equal: a function to return %TRUE if two keys are equal
* @entry_destroy: destroy notifier for cache entries
* @max_size: the maximum size for this cache
- * Returns: the newly created #cairo_cache_t
*
* Creates a new cache using the keys_equal() function to determine
* the equality of entries.
@@ -84,6 +83,8 @@ _cairo_cache_entry_is_non_zero (const void *entry)
* _cairo_cache_freeze() and _cairo_cache_thaw() calls can be
* used to establish a window during which no automatic removal of
* entries will occur.
+ *
+ * Returns: the newly created #cairo_cache_t
**/
cairo_status_t
_cairo_cache_init (cairo_cache_t *cache,
@@ -336,3 +337,10 @@ _cairo_hash_bytes (uintptr_t hash,
hash = ((hash << 5) + hash) + *bytes++;
return hash;
}
+
+uintptr_t
+_cairo_hash_uintptr (uintptr_t hash,
+ uintptr_t u)
+{
+ return _cairo_hash_bytes (hash, &u, sizeof(u));
+}
diff --git a/src/cairo-cff-subset.c b/src/cairo-cff-subset.c
index 4bf22e2b7..c7aaec4a8 100644
--- a/src/cairo-cff-subset.c
+++ b/src/cairo-cff-subset.c
@@ -390,7 +390,7 @@ encode_index_offset (unsigned char *p, int offset_size, unsigned long offset)
return p + offset_size;
}
-static unsigned long
+static size_t
decode_index_offset(unsigned char *p, int off_size)
{
unsigned long offset = 0;
@@ -412,8 +412,8 @@ cff_index_read (cairo_array_t *index, unsigned char **ptr, unsigned char *end_pt
cff_index_element_t element;
unsigned char *data, *p;
cairo_status_t status;
- int offset_size, count, start, i;
- int end = 0;
+ int offset_size, count, i;
+ size_t start, end = 0;
p = *ptr;
if (p + 2 > end_ptr)
@@ -422,7 +422,7 @@ cff_index_read (cairo_array_t *index, unsigned char **ptr, unsigned char *end_pt
p += 2;
if (count > 0) {
offset_size = *p++;
- if (p + (count + 1)*offset_size > end_ptr)
+ if (p + (count + 1)*offset_size > end_ptr || offset_size > 4)
return CAIRO_INT_STATUS_UNSUPPORTED;
data = p + offset_size*(count + 1) - 1;
start = decode_index_offset (p, offset_size);
@@ -430,7 +430,7 @@ cff_index_read (cairo_array_t *index, unsigned char **ptr, unsigned char *end_pt
for (i = 0; i < count; i++) {
end = decode_index_offset (p, offset_size);
p += offset_size;
- if (p > end_ptr)
+ if (p > end_ptr || end < start || data + end > end_ptr)
return CAIRO_INT_STATUS_UNSUPPORTED;
element.length = end - start;
element.is_copy = FALSE;
@@ -875,7 +875,7 @@ cairo_cff_font_read_name (cairo_cff_font_t *font)
cff_index_init (&index);
status = cff_index_read (&index, &font->current_ptr, font->data_end);
- if (!font->is_opentype) {
+ if (status == CAIRO_INT_STATUS_SUCCESS && !font->is_opentype) {
element = _cairo_array_index (&index, 0);
p = element->data;
len = element->length;
@@ -890,12 +890,10 @@ cairo_cff_font_read_name (cairo_cff_font_t *font)
len -= 7;
}
}
- font->ps_name = _cairo_malloc (len + 1);
- if (unlikely (font->ps_name == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- memcpy (font->ps_name, p, len);
- font->ps_name[len] = 0;
+ font->ps_name = _cairo_strndup ((char*)p, len);
+ if (unlikely (font->ps_name == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_escape_ps_name (&font->ps_name);
}
diff --git a/src/cairo-colr-glyph-render.c b/src/cairo-colr-glyph-render.c
new file mode 100644
index 000000000..28254fd51
--- /dev/null
+++ b/src/cairo-colr-glyph-render.c
@@ -0,0 +1,1248 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2022 Matthias Clasen
+ *
+ * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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.
+ *
+ * Contributor(s):
+ * Matthias Clasen <mclasen@redhat.com>
+ */
+
+#include "cairoint.h"
+#include "cairo-array-private.h"
+#include "cairo-ft-private.h"
+#include "cairo-path-private.h"
+#include "cairo-pattern-private.h"
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#if HAVE_FT_COLR_V1
+
+#include <ft2build.h>
+#include FT_CONFIG_OPTIONS_H
+#include FT_COLOR_H
+#include FT_GLYPH_H
+#include FT_OUTLINE_H
+#include FT_SIZES_H
+
+/* #define DEBUG_COLR 1 */
+
+typedef struct _cairo_colr_glyph_render {
+ FT_Face face;
+ FT_Color *palette;
+ unsigned int num_palette_entries;
+ cairo_pattern_t *foreground_marker;
+ cairo_pattern_t *foreground_source;
+ cairo_bool_t foreground_source_used;
+ int level;
+} cairo_colr_glyph_render_t;
+
+static cairo_status_t
+draw_paint (cairo_colr_glyph_render_t *render,
+ FT_OpaquePaint *paint,
+ cairo_t *cr);
+
+
+static inline double
+double_from_16_16 (FT_Fixed f)
+{
+ return f / (double) (1 << 16);
+}
+
+static inline double
+double_from_26_6 (FT_F26Dot6 f)
+{
+ return f / (double) (1 << 6);
+}
+
+static inline double
+double_from_2_14 (FT_F2Dot14 f)
+{
+ return f / (double) (1 << 14);
+}
+
+static inline double
+interpolate (double f0, double f1, double f)
+{
+ return f0 + f * (f1 - f0);
+}
+
+static inline void
+interpolate_points (cairo_point_double_t *p0,
+ cairo_point_double_t *p1,
+ double f,
+ cairo_point_double_t *out)
+{
+ out->x = interpolate (p0->x, p1->x, f);
+ out->y = interpolate (p0->y, p1->y, f);
+}
+
+static inline void
+interpolate_colors (cairo_color_t *c0,
+ cairo_color_t *c1,
+ double f,
+ cairo_color_t *out)
+{
+ out->red = interpolate (c0->red, c1->red, f);
+ out->green = interpolate (c0->green, c1->green, f);
+ out->blue = interpolate (c0->blue, c1->blue, f);
+ out->alpha = interpolate (c0->alpha, c1->alpha, f);
+}
+
+static inline double
+dot (cairo_point_double_t p, cairo_point_double_t q)
+{
+ return p.x * q.x + p.y * q.y;
+}
+
+static inline cairo_point_double_t
+normalize (cairo_point_double_t p)
+{
+ double len = sqrt (dot (p, p));
+
+ return (cairo_point_double_t) { p.x / len, p.y / len };
+}
+
+static inline cairo_point_double_t
+sum (cairo_point_double_t p, cairo_point_double_t q)
+{
+ return (cairo_point_double_t) { p.x + q.x, p.y + q.y };
+}
+
+static inline cairo_point_double_t
+difference (cairo_point_double_t p, cairo_point_double_t q)
+{
+ return (cairo_point_double_t) { p.x - q.x, p.y - q.y };
+}
+
+static inline cairo_point_double_t
+scale (cairo_point_double_t p, double f)
+{
+ return (cairo_point_double_t) { p.x * f, p.y * f };
+}
+
+static cairo_operator_t
+cairo_operator_from_ft_composite_mode (FT_Composite_Mode mode)
+{
+ switch (mode)
+ {
+ case FT_COLR_COMPOSITE_CLEAR: return CAIRO_OPERATOR_CLEAR;
+ case FT_COLR_COMPOSITE_SRC: return CAIRO_OPERATOR_SOURCE;
+ case FT_COLR_COMPOSITE_DEST: return CAIRO_OPERATOR_DEST;
+ case FT_COLR_COMPOSITE_SRC_OVER: return CAIRO_OPERATOR_OVER;
+ case FT_COLR_COMPOSITE_DEST_OVER: return CAIRO_OPERATOR_DEST_OVER;
+ case FT_COLR_COMPOSITE_SRC_IN: return CAIRO_OPERATOR_IN;
+ case FT_COLR_COMPOSITE_DEST_IN: return CAIRO_OPERATOR_DEST_IN;
+ case FT_COLR_COMPOSITE_SRC_OUT: return CAIRO_OPERATOR_OUT;
+ case FT_COLR_COMPOSITE_DEST_OUT: return CAIRO_OPERATOR_DEST_OUT;
+ case FT_COLR_COMPOSITE_SRC_ATOP: return CAIRO_OPERATOR_ATOP;
+ case FT_COLR_COMPOSITE_DEST_ATOP: return CAIRO_OPERATOR_DEST_ATOP;
+ case FT_COLR_COMPOSITE_XOR: return CAIRO_OPERATOR_XOR;
+ case FT_COLR_COMPOSITE_PLUS: return CAIRO_OPERATOR_ADD;
+ case FT_COLR_COMPOSITE_SCREEN: return CAIRO_OPERATOR_SCREEN;
+ case FT_COLR_COMPOSITE_OVERLAY: return CAIRO_OPERATOR_OVERLAY;
+ case FT_COLR_COMPOSITE_DARKEN: return CAIRO_OPERATOR_DARKEN;
+ case FT_COLR_COMPOSITE_LIGHTEN: return CAIRO_OPERATOR_LIGHTEN;
+ case FT_COLR_COMPOSITE_COLOR_DODGE: return CAIRO_OPERATOR_COLOR_DODGE;
+ case FT_COLR_COMPOSITE_COLOR_BURN: return CAIRO_OPERATOR_COLOR_BURN;
+ case FT_COLR_COMPOSITE_HARD_LIGHT: return CAIRO_OPERATOR_HARD_LIGHT;
+ case FT_COLR_COMPOSITE_SOFT_LIGHT: return CAIRO_OPERATOR_SOFT_LIGHT;
+ case FT_COLR_COMPOSITE_DIFFERENCE: return CAIRO_OPERATOR_DIFFERENCE;
+ case FT_COLR_COMPOSITE_EXCLUSION: return CAIRO_OPERATOR_EXCLUSION;
+ case FT_COLR_COMPOSITE_MULTIPLY: return CAIRO_OPERATOR_MULTIPLY;
+ case FT_COLR_COMPOSITE_HSL_HUE: return CAIRO_OPERATOR_HSL_HUE;
+ case FT_COLR_COMPOSITE_HSL_SATURATION: return CAIRO_OPERATOR_HSL_SATURATION;
+ case FT_COLR_COMPOSITE_HSL_COLOR: return CAIRO_OPERATOR_HSL_COLOR;
+ case FT_COLR_COMPOSITE_HSL_LUMINOSITY: return CAIRO_OPERATOR_HSL_LUMINOSITY;
+ case FT_COLR_COMPOSITE_MAX:
+ default:
+ ASSERT_NOT_REACHED;
+ }
+}
+
+static cairo_extend_t
+cairo_extend_from_ft_paint_extend (FT_PaintExtend extend)
+{
+ switch (extend)
+ {
+ case FT_COLR_PAINT_EXTEND_PAD: return CAIRO_EXTEND_PAD;
+ case FT_COLR_PAINT_EXTEND_REPEAT: return CAIRO_EXTEND_REPEAT;
+ case FT_COLR_PAINT_EXTEND_REFLECT: return CAIRO_EXTEND_REFLECT;
+ default:
+ ASSERT_NOT_REACHED;
+ }
+}
+
+static cairo_status_t
+draw_paint_colr_layers (cairo_colr_glyph_render_t *render,
+ FT_PaintColrLayers *colr_layers,
+ cairo_t *cr)
+{
+ FT_OpaquePaint paint;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+#if DEBUG_COLR
+ printf ("%*sDraw PaintColrLayers\n", 2 * render->level, "");
+#endif
+
+ while (FT_Get_Paint_Layers (render->face, &colr_layers->layer_iterator, &paint)) {
+ cairo_push_group (cr);
+ status = draw_paint (render, &paint, cr);
+ cairo_pop_group_to_source (cr);
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+ cairo_paint (cr);
+
+ if (unlikely (status))
+ break;
+ }
+
+ return status;
+}
+
+static void
+get_palette_color (cairo_colr_glyph_render_t *render,
+ FT_ColorIndex *ci,
+ cairo_color_t *color,
+ double *colr_alpha,
+ cairo_bool_t *is_foreground_color)
+{
+ cairo_bool_t foreground = FALSE;
+
+ if (ci->palette_index == 0xffff || ci->palette_index >= render->num_palette_entries) {
+ color->red = 0;
+ color->green = 0;
+ color->blue = 0;
+ color->alpha = 1;
+ foreground = TRUE;
+ } else {
+ FT_Color c = render->palette[ci->palette_index];
+ color->red = c.red / 255.0;
+ color->green = c.green / 255.0;
+ color->blue = c.blue / 255.0;
+ color->alpha = c.alpha / 255.0;
+ }
+
+ *colr_alpha = double_from_2_14 (ci->alpha);
+ *is_foreground_color = foreground;
+}
+
+static cairo_status_t
+draw_paint_solid (cairo_colr_glyph_render_t *render,
+ FT_PaintSolid *solid,
+ cairo_t *cr)
+{
+ cairo_color_t color;
+ double colr_alpha;
+ cairo_bool_t is_foreground_color;
+
+#if DEBUG_COLR
+ printf ("%*sDraw PaintSolid\n", 2 * render->level, "");
+#endif
+
+ get_palette_color (render, &solid->color, &color, &colr_alpha, &is_foreground_color);
+ if (is_foreground_color) {
+ cairo_set_source (cr, render->foreground_marker);
+ cairo_paint_with_alpha (cr, colr_alpha);
+ } else {
+ cairo_set_source_rgba (cr, color.red, color.green, color.blue, color.alpha * colr_alpha);
+ cairo_paint (cr);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+typedef struct _cairo_colr_color_stop {
+ cairo_color_t color;
+ double position;
+} cairo_colr_color_stop_t;
+
+typedef struct _cairo_colr_color_line {
+ int n_stops;
+ cairo_colr_color_stop_t *stops;
+} cairo_colr_color_line_t;
+
+static void
+free_colorline (cairo_colr_color_line_t *cl)
+{
+ free (cl->stops);
+ free (cl);
+}
+
+static int
+_compare_stops (const void *p1, const void *p2)
+{
+ const cairo_colr_color_stop_t *c1 = p1;
+ const cairo_colr_color_stop_t *c2 = p2;
+
+ if (c1->position < c2->position)
+ return -1;
+ else if (c1->position > c2->position)
+ return 1;
+ else
+ return 0;
+}
+
+static cairo_colr_color_line_t *
+read_colorline (cairo_colr_glyph_render_t *render,
+ FT_ColorLine *colorline)
+{
+ cairo_colr_color_line_t *cl;
+ FT_ColorStop stop;
+ int i;
+ double colr_alpha;
+ cairo_bool_t is_foreground_color;
+
+ cl = calloc (1, sizeof (cairo_colr_color_line_t));
+ if (unlikely (cl == NULL))
+ return NULL;
+
+ cl->n_stops = colorline->color_stop_iterator.num_color_stops;
+ cl->stops = calloc (cl->n_stops, sizeof (cairo_colr_color_stop_t));
+ if (unlikely (cl->stops == NULL)) {
+ free (cl);
+ return NULL;
+ }
+
+ i = 0;
+ while (FT_Get_Colorline_Stops (render->face, &stop, &colorline->color_stop_iterator)) {
+ cl->stops[i].position = double_from_16_16 (stop.stop_offset);
+ get_palette_color (render, &stop.color, &cl->stops[i].color, &colr_alpha, &is_foreground_color);
+ if (is_foreground_color) {
+ double red, green, blue, alpha;
+ if (cairo_pattern_get_rgba (render->foreground_source,
+ &red, &green, &blue, &alpha) == CAIRO_STATUS_SUCCESS)
+ {
+ cl->stops[i].color.red = red;
+ cl->stops[i].color.green = green;
+ cl->stops[i].color.blue = blue;
+ cl->stops[i].color.alpha = alpha * colr_alpha;
+ render->foreground_source_used = TRUE;
+ }
+ else
+ {
+ cl->stops[i].color.red = 0;
+ cl->stops[i].color.green = 0;
+ cl->stops[i].color.blue = 0;
+ cl->stops[i].color.alpha = colr_alpha;
+ }
+ } else {
+ cl->stops[i].color.alpha *= colr_alpha;
+ }
+ i++;
+ }
+
+ qsort (cl->stops, cl->n_stops, sizeof (cairo_colr_color_stop_t), _compare_stops);
+
+ return cl;
+}
+
+static void
+reduce_anchors (FT_PaintLinearGradient *gradient,
+ cairo_point_double_t *pp0,
+ cairo_point_double_t *pp1)
+{
+ cairo_point_double_t p0, p1, p2;
+ cairo_point_double_t q1, q2;
+ double s;
+ double k;
+
+ p0.x = double_from_16_16 (gradient->p0.x);
+ p0.y = double_from_16_16 (gradient->p0.y);
+ p1.x = double_from_16_16 (gradient->p1.x);
+ p1.y = double_from_16_16 (gradient->p1.y);
+ p2.x = double_from_16_16 (gradient->p2.x);
+ p2.y = double_from_16_16 (gradient->p2.y);
+
+ q2.x = p2.x - p0.x;
+ q2.y = p2.y - p0.y;
+ q1.x = p1.x - p0.x;
+ q1.y = p1.y - p0.y;
+
+ s = q2.x * q2.x + q2.y * q2.y;
+ if (s < 0.000001)
+ {
+ pp0->x = p0.x; pp0->y = p0.y;
+ pp1->x = p1.x; pp1->y = p1.y;
+ return;
+ }
+
+ k = (q2.x * q1.x + q2.y * q1.y) / s;
+ pp0->x = p0.x;
+ pp0->y = p0.y;
+ pp1->x = p1.x - k * q2.x;
+ pp1->y = p1.y - k * q2.y;
+}
+
+static void
+normalize_colorline (cairo_colr_color_line_t *cl,
+ double *out_min,
+ double *out_max)
+{
+ double min, max;
+
+ *out_min = 0.;
+ *out_max = 1.;
+
+ min = max = cl->stops[0].position;
+ for (int i = 0; i < cl->n_stops; i++) {
+ cairo_colr_color_stop_t *stop = &cl->stops[i];
+ min = MIN (min, stop->position);
+ max = MAX (max, stop->position);
+ }
+
+ if (min != max) {
+ for (int i = 0; i < cl->n_stops; i++) {
+ cairo_colr_color_stop_t *stop = &cl->stops[i];
+ stop->position = (stop->position - min) / (max - min);
+ }
+ *out_min = min;
+ *out_max = max;
+ }
+}
+
+static cairo_status_t
+draw_paint_linear_gradient (cairo_colr_glyph_render_t *render,
+ FT_PaintLinearGradient *gradient,
+ cairo_t *cr)
+{
+ cairo_colr_color_line_t *cl;
+ cairo_point_double_t p0, p1;
+ cairo_point_double_t pp0, pp1;
+ cairo_pattern_t *pattern;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ double min, max;
+
+#if DEBUG_COLR
+ printf ("%*sDraw PaintLinearGradient\n", 2 * render->level, "");
+#endif
+
+ cl = read_colorline (render, &gradient->colorline);
+ if (unlikely (cl == NULL))
+ return CAIRO_STATUS_NO_MEMORY;
+
+ /* cairo only allows stop positions between 0 and 1 */
+ normalize_colorline (cl, &min, &max);
+ reduce_anchors (gradient, &p0, &p1);
+ interpolate_points (&p0, &p1, min, &pp0);
+ interpolate_points (&p0, &p1, max, &pp1);
+
+ pattern = cairo_pattern_create_linear (pp0.x, pp0.y, pp1.x, pp1.y);
+
+ cairo_pattern_set_extend (pattern, cairo_extend_from_ft_paint_extend (gradient->colorline.extend));
+
+ for (int i = 0; i < cl->n_stops; i++) {
+ cairo_colr_color_stop_t *stop = &cl->stops[i];
+ cairo_pattern_add_color_stop_rgba (pattern, stop->position,
+ stop->color.red, stop->color.green, stop->color.blue, stop->color.alpha);
+ }
+
+ cairo_set_source (cr, pattern);
+ cairo_paint (cr);
+
+ cairo_pattern_destroy (pattern);
+
+ free_colorline (cl);
+
+ return status;
+}
+
+static cairo_status_t
+draw_paint_radial_gradient (cairo_colr_glyph_render_t *render,
+ FT_PaintRadialGradient *gradient,
+ cairo_t *cr)
+{
+ cairo_colr_color_line_t *cl;
+ cairo_point_double_t start, end;
+ cairo_point_double_t start1, end1;
+ double start_radius, end_radius;
+ double start_radius1, end_radius1;
+ double min, max;
+ cairo_pattern_t *pattern;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+#if DEBUG_COLR
+ printf ("%*sDraw PaintRadialGradient\n", 2 * render->level, "");
+#endif
+
+ cl = read_colorline (render, &gradient->colorline);
+ if (unlikely (cl == NULL))
+ return CAIRO_STATUS_NO_MEMORY;
+
+ start.x = double_from_16_16 (gradient->c0.x);
+ start.y = double_from_16_16 (gradient->c0.y);
+ end.x = double_from_16_16 (gradient->c1.x);
+ end.y = double_from_16_16 (gradient->c1.y);
+
+ start_radius = double_from_16_16 (gradient->r0);
+ end_radius = double_from_16_16 (gradient->r1);
+
+ /* cairo only allows stop positions between 0 and 1 */
+ normalize_colorline (cl, &min, &max);
+ interpolate_points (&start, &end, min, &start1);
+ interpolate_points (&start, &end, max, &end1);
+ start_radius1 = interpolate (start_radius, end_radius, min);
+ end_radius1 = interpolate (start_radius, end_radius, max);
+
+ pattern = cairo_pattern_create_radial (start1.x, start1.y, start_radius1,
+ end1.x, end1.y, end_radius1);
+
+ cairo_pattern_set_extend (pattern, cairo_extend_from_ft_paint_extend (gradient->colorline.extend));
+
+ for (int i = 0; i < cl->n_stops; i++) {
+ cairo_colr_color_stop_t *stop = &cl->stops[i];
+ cairo_pattern_add_color_stop_rgba (pattern, stop->position,
+ stop->color.red, stop->color.green, stop->color.blue, stop->color.alpha);
+ }
+
+ cairo_set_source (cr, pattern);
+ cairo_paint (cr);
+
+ cairo_pattern_destroy (pattern);
+
+ free_colorline (cl);
+
+ return status;
+}
+
+typedef struct {
+ cairo_point_double_t center, p0, c0, c1, p1;
+ cairo_color_t color0, color1;
+} cairo_colr_gradient_patch_t;
+
+static void
+add_patch (cairo_pattern_t *pattern,
+ cairo_point_double_t *center,
+ cairo_colr_gradient_patch_t *p)
+{
+ cairo_mesh_pattern_begin_patch (pattern);
+ cairo_mesh_pattern_move_to (pattern, center->x, center->y);
+ cairo_mesh_pattern_line_to (pattern, p->p0.x, p->p0.y);
+ cairo_mesh_pattern_curve_to (pattern,
+ p->c0.x, p->c0.y,
+ p->c1.x, p->c1.y,
+ p->p1.x, p->p1.y);
+ cairo_mesh_pattern_line_to (pattern, center->x, center->y);
+ cairo_mesh_pattern_set_corner_color_rgba (pattern, 0,
+ p->color0.red,
+ p->color0.green,
+ p->color0.blue,
+ p->color0.alpha);
+ cairo_mesh_pattern_set_corner_color_rgba (pattern, 1,
+ p->color0.red,
+ p->color0.green,
+ p->color0.blue,
+ p->color0.alpha);
+ cairo_mesh_pattern_set_corner_color_rgba (pattern, 2,
+ p->color1.red,
+ p->color1.green,
+ p->color1.blue,
+ p->color1.alpha);
+ cairo_mesh_pattern_set_corner_color_rgba (pattern, 3,
+ p->color1.red,
+ p->color1.green,
+ p->color1.blue,
+ p->color1.alpha);
+ cairo_mesh_pattern_end_patch (pattern);
+}
+
+#define MAX_ANGLE (M_PI / 8.)
+
+static void
+add_sweep_gradient_patches1 (cairo_point_double_t *center,
+ double radius,
+ double a0,
+ cairo_color_t *c0,
+ double a1,
+ cairo_color_t *c1,
+ cairo_pattern_t *pattern)
+{
+
+ int num_splits;
+ cairo_point_double_t p0;
+ cairo_color_t color0, color1;
+
+ num_splits = ceilf (fabs (a1 - a0) / MAX_ANGLE);
+ p0 = (cairo_point_double_t) { cosf (a0), sinf (a0) };
+ color0 = *c0;
+
+ for (int a = 0; a < num_splits; a++) {
+ double k = (a + 1.) / num_splits;
+ double angle1;
+ cairo_point_double_t p1;
+ cairo_point_double_t A, U;
+ cairo_point_double_t C0, C1;
+ cairo_colr_gradient_patch_t patch;
+
+ angle1 = interpolate (a0, a1, k);
+ interpolate_colors (c0, c1, k, &color1);
+
+ patch.color0 = color0;
+ patch.color1 = color1;
+
+ p1 = (cairo_point_double_t) { cosf (angle1), sinf (angle1) };
+ patch.p0 = sum (*center, scale (p0, radius));
+ patch.p1 = sum (*center, scale (p1, radius));
+
+ A = normalize (sum (p0, p1));
+ U = (cairo_point_double_t) { -A.y, A.x };
+ C0 = sum (A, scale (U, dot (difference (p0, A), p0) / dot (U, p0)));
+ C1 = sum (A, scale (U, dot (difference (p1, A), p1) / dot (U, p1)));
+ patch.c0 = sum (*center, scale (sum (C0, scale (difference (C0, p0), 0.33333)), radius));
+ patch.c1 = sum (*center, scale (sum (C1, scale (difference (C1, p1), 0.33333)), radius));
+
+ add_patch (pattern, center, &patch);
+
+ p0 = p1;
+ color0 = color1;
+ }
+}
+
+static void
+add_sweep_gradient_patches (cairo_colr_color_line_t *cl,
+ cairo_extend_t extend,
+ cairo_point_double_t *center,
+ double radius,
+ double start_angle,
+ double end_angle,
+ cairo_pattern_t *pattern)
+{
+ double *angles;
+ cairo_color_t color0, color1;
+
+ if (start_angle == end_angle) {
+ if (extend == CAIRO_EXTEND_PAD) {
+ if (start_angle > 0)
+ add_sweep_gradient_patches1 (center, radius,
+ 0., &cl->stops[0].color,
+ start_angle, &cl->stops[0].color,
+ pattern);
+ if (end_angle < 2 * M_PI)
+ add_sweep_gradient_patches1 (center, radius,
+ end_angle, &cl->stops[cl->n_stops - 1].color,
+ 2 * M_PI, &cl->stops[cl->n_stops - 1].color,
+ pattern);
+ }
+ return;
+ }
+
+ assert (start_angle != end_angle);
+
+ angles = alloca (sizeof (double) * cl->n_stops);
+
+ for (int i = 0; i < cl->n_stops; i++)
+ angles[i] = start_angle + cl->stops[i].position * (end_angle - start_angle);
+
+ /* handle directions */
+ if (end_angle < start_angle) {
+ for (int i = 0; i < cl->n_stops - 1 - i; i++) {
+ cairo_colr_color_stop_t stop = cl->stops[i];
+ double a = angles[i];
+ cl->stops[i] = cl->stops[cl->n_stops - 1 - i];
+ cl->stops[cl->n_stops - 1 - i] = stop;
+ angles[i] = angles[cl->n_stops - 1 - i];
+ angles[cl->n_stops - 1 - i] = a;
+ }
+ }
+
+ if (extend == CAIRO_EXTEND_PAD)
+ {
+ int pos;
+
+ color0 = cl->stops[0].color;
+ for (pos = 0; pos < cl->n_stops; pos++) {
+ if (angles[pos] >= 0) {
+ if (pos > 0) {
+ double k = (0 - angles[pos - 1]) / (angles[pos] - angles[pos - 1]);
+ interpolate_colors (&cl->stops[pos - 1].color, &cl->stops[pos].color, k, &color0);
+ }
+ break;
+ }
+ }
+ if (pos == cl->n_stops) {
+ /* everything is below 0 */
+ color0 = cl->stops[cl->n_stops - 1].color;
+ add_sweep_gradient_patches1 (center, radius,
+ 0., &color0,
+ 2 * M_PI, &color0,
+ pattern);
+ return;
+ }
+
+ add_sweep_gradient_patches1 (center, radius,
+ 0., &color0,
+ angles[pos], &cl->stops[pos].color,
+ pattern);
+
+ for (pos++; pos < cl->n_stops; pos++) {
+ if (angles[pos] <= 2 * M_PI) {
+ add_sweep_gradient_patches1 (center, radius,
+ angles[pos - 1], &cl->stops[pos - 1].color,
+ angles[pos], &cl->stops[pos].color,
+ pattern);
+ } else {
+ double k = (2 * M_PI - angles[pos - 1]) / (angles[pos] - angles[pos - 1]);
+ interpolate_colors (&cl->stops[pos - 1].color, &cl->stops[pos].color, k, &color1);
+ add_sweep_gradient_patches1 (center, radius,
+ angles[pos - 1], &cl->stops[pos - 1].color,
+ 2 * M_PI, &color1,
+ pattern);
+ break;
+ }
+ }
+
+ if (pos == cl->n_stops) {
+ /* everything is below 2*M_PI */
+ color0 = cl->stops[cl->n_stops - 1].color;
+ add_sweep_gradient_patches1 (center, radius,
+ angles[cl->n_stops - 1], &color0,
+ 2 * M_PI, &color0,
+ pattern);
+ return;
+ }
+ } else {
+ int k;
+ double span;
+
+ span = angles[cl->n_stops - 1] - angles[0];
+ k = 0;
+ if (angles[0] >= 0) {
+ double ss = angles[0];
+ while (ss > 0) {
+ if (span > 0) {
+ ss -= span;
+ k--;
+ } else {
+ ss += span;
+ k++;
+ }
+ }
+ }
+ else if (angles[0] < 0)
+ {
+ double ee = angles[cl->n_stops - 1];
+ while (ee < 0) {
+ if (span > 0) {
+ ee += span;
+ k++;
+ } else {
+ ee -= span;
+ k--;
+ }
+ }
+ }
+
+ //assert (angles[0] + k * span <= 0 && 0 < angles[cl->n_stops - 1] + k * span);
+
+ for (int l = k; TRUE; l++) {
+ for (int i = 1; i < cl->n_stops; i++) {
+ double a0, a1;
+ cairo_color_t *c0, *c1;
+
+ if ((l % 2 != 0) && (extend == CAIRO_EXTEND_REFLECT)) {
+ a0 = angles[0] + angles[cl->n_stops - 1] - angles[cl->n_stops - 1 - (i-1)] + l * span;
+ a1 = angles[0] + angles[cl->n_stops - 1] - angles[cl->n_stops - 1 - i] + l * span;
+ c0 = &cl->stops[cl->n_stops - 1 - (i-1)].color;
+ c1 = &cl->stops[cl->n_stops - 1 - i].color;
+ } else {
+ a0 = angles[i-1] + l * span;
+ a1 = angles[i] + l * span;
+ c0 = &cl->stops[i-1].color;
+ c1 = &cl->stops[i].color;
+ }
+
+ if (a1 < 0)
+ continue;
+
+ if (a0 < 0) {
+ cairo_color_t color;
+ double f = (0 - a0)/(a1 - a0);
+ interpolate_colors (c0, c1, f, &color);
+ add_sweep_gradient_patches1 (center, radius,
+ 0, &color,
+ a1, c1,
+ pattern);
+ } else if (a1 >= 2 * M_PI) {
+ cairo_color_t color;
+ double f = (2 * M_PI - a0)/(a1 - a0);
+ interpolate_colors (c0, c1, f, &color);
+ add_sweep_gradient_patches1 (center, radius,
+ a0, c0,
+ 2 * M_PI, &color,
+ pattern);
+ return;
+ } else {
+ add_sweep_gradient_patches1 (center, radius,
+ a0, c0,
+ a1, c1,
+ pattern);
+ }
+ }
+ }
+ }
+}
+
+static cairo_status_t
+draw_paint_sweep_gradient (cairo_colr_glyph_render_t *render,
+ FT_PaintSweepGradient *gradient,
+ cairo_t *cr)
+{
+ cairo_colr_color_line_t *cl;
+ cairo_point_double_t center;
+ double start_angle, end_angle;
+ double x1, y1, x2, y2;
+ double max_x, max_y, R;
+ cairo_pattern_t *pattern;
+ cairo_extend_t extend;
+
+#if DEBUG_COLR
+ printf ("%*sDraw PaintSweepGradient\n", 2 * render->level, "");
+#endif
+
+ cl = read_colorline (render, &gradient->colorline);
+ if (unlikely (cl == NULL))
+ return CAIRO_STATUS_NO_MEMORY;
+
+ center.x = double_from_16_16 (gradient->center.x);
+ center.y = double_from_16_16 (gradient->center.y);
+ start_angle = (double_from_16_16 (gradient->start_angle) + 1) * M_PI;
+ end_angle = (double_from_16_16 (gradient->end_angle) + 1) * M_PI;
+
+ pattern = cairo_pattern_create_mesh ();
+
+ cairo_clip_extents (cr, &x1, &y1, &x2, &y2);
+ max_x = MAX ((x1 - center.x) * (x1 - center.x), (x2 - center.x) * (x2 - center.x));
+ max_y = MAX ((y1 - center.y) * (y1 - center.y), (y2 - center.y) * (y2 - center.y));
+ R = sqrt (max_x + max_y);
+
+ extend = cairo_extend_from_ft_paint_extend (gradient->colorline.extend);
+
+ add_sweep_gradient_patches (cl, extend, &center, R, start_angle, end_angle, pattern);
+
+ cairo_set_source (cr, pattern);
+ cairo_paint (cr);
+
+ cairo_pattern_destroy (pattern);
+
+ free_colorline (cl);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+draw_paint_glyph (cairo_colr_glyph_render_t *render,
+ FT_PaintGlyph *glyph,
+ cairo_t *cr)
+{
+ cairo_path_fixed_t *path_fixed;
+ cairo_path_t *path;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ FT_Error error;
+
+#if DEBUG_COLR
+ printf ("%*sDraw PaintGlyph\n", 2 * render->level, "");
+#endif
+
+ error = FT_Load_Glyph (render->face, glyph->glyphID, FT_LOAD_DEFAULT);
+ status = _cairo_ft_to_cairo_error (error);
+ if (unlikely (status))
+ return status;
+
+ status = _cairo_ft_face_decompose_glyph_outline (render->face, &path_fixed);
+ if (unlikely (status))
+ return status;
+
+ cairo_save (cr);
+ cairo_identity_matrix (cr);
+ path = _cairo_path_create (path_fixed, cr);
+ _cairo_path_fixed_destroy (path_fixed);
+ cairo_restore (cr);
+
+ cairo_save (cr);
+
+ cairo_new_path (cr);
+ cairo_append_path (cr, path);
+ cairo_path_destroy (path);
+ cairo_clip (cr);
+
+ status = draw_paint (render, &glyph->paint, cr);
+
+ cairo_restore (cr);
+
+ return status;
+}
+
+static cairo_status_t draw_colr_glyph (cairo_colr_glyph_render_t *render,
+ unsigned long glyph,
+ FT_Color_Root_Transform root,
+ cairo_t *cr);
+
+static cairo_status_t
+draw_paint_colr_glyph (cairo_colr_glyph_render_t *render,
+ FT_PaintColrGlyph *colr_glyph,
+ cairo_t *cr)
+{
+#if DEBUG_COLR
+ printf ("%*sDraw PaintColrGlyph\n", 2 * render->level, "");
+#endif
+
+ return draw_colr_glyph (render, colr_glyph->glyphID, FT_COLOR_NO_ROOT_TRANSFORM, cr);
+}
+
+static cairo_status_t
+draw_paint_transform (cairo_colr_glyph_render_t *render,
+ FT_PaintTransform *transform,
+ cairo_t *cr)
+{
+ cairo_matrix_t t;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+#if DEBUG_COLR
+ printf ("%*sDraw PaintTransform\n", 2 * render->level, "");
+#endif
+
+ cairo_matrix_init (&t,
+ double_from_16_16 (transform->affine.xx),
+ double_from_16_16 (transform->affine.yx),
+ double_from_16_16 (transform->affine.xy),
+ double_from_16_16 (transform->affine.yy),
+ double_from_16_16 (transform->affine.dx),
+ double_from_16_16 (transform->affine.dy));
+
+ cairo_save (cr);
+
+ cairo_transform (cr, &t);
+ status = draw_paint (render, &transform->paint, cr);
+
+ cairo_restore (cr);
+
+ return status;
+}
+
+static cairo_status_t
+draw_paint_translate (cairo_colr_glyph_render_t *render,
+ FT_PaintTranslate *translate,
+ cairo_t *cr)
+{
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+#if DEBUG_COLR
+ printf ("%*sDraw PaintTranslate\n", 2 * render->level, "");
+#endif
+
+ cairo_save (cr);
+
+ cairo_translate (cr, double_from_16_16 (translate->dx), double_from_16_16 (translate->dy));
+ status = draw_paint (render, &translate->paint, cr);
+
+ cairo_restore (cr);
+
+ return status;
+}
+
+static cairo_status_t
+draw_paint_rotate (cairo_colr_glyph_render_t *render,
+ FT_PaintRotate *rotate,
+ cairo_t *cr)
+{
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+#if DEBUG_COLR
+ printf ("%*sDraw PaintRotate\n", 2 * render->level, "");
+#endif
+
+ cairo_save (cr);
+
+ cairo_translate (cr, double_from_16_16 (rotate->center_x), double_from_16_16 (rotate->center_y));
+ cairo_rotate (cr, double_from_16_16 (rotate->angle) * M_PI);
+ cairo_translate (cr, - double_from_16_16 (rotate->center_x), - double_from_16_16 (rotate->center_y));
+ status = draw_paint (render, &rotate->paint, cr);
+
+ cairo_restore (cr);
+
+ return status;
+}
+
+static cairo_status_t
+draw_paint_scale (cairo_colr_glyph_render_t *render,
+ FT_PaintScale *scale,
+ cairo_t *cr)
+{
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+#if DEBUG_COLR
+ printf ("%*sDraw PaintScale\n", 2 * render->level, "");
+#endif
+
+ cairo_save (cr);
+
+ cairo_translate (cr, double_from_16_16 (scale->center_x), double_from_16_16 (scale->center_y));
+ cairo_scale (cr, double_from_16_16 (scale->scale_x), double_from_16_16 (scale->scale_y));
+ cairo_translate (cr, - double_from_16_16 (scale->center_x), - double_from_16_16 (scale->center_y));
+ status = draw_paint (render, &scale->paint, cr);
+
+ cairo_restore (cr);
+
+ return status;
+}
+
+static cairo_status_t
+draw_paint_skew (cairo_colr_glyph_render_t *render,
+ FT_PaintSkew *skew,
+ cairo_t *cr)
+{
+ cairo_matrix_t s;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+#if DEBUG_COLR
+ printf ("%*sDraw PaintSkew\n", 2 * render->level, "");
+#endif
+
+ cairo_save (cr);
+
+ cairo_translate (cr, double_from_16_16 (skew->center_x), double_from_16_16 (skew->center_y));
+ cairo_matrix_init (&s, 1., tan (double_from_16_16 (skew->y_skew_angle) * M_PI), - tan (double_from_16_16 (skew->x_skew_angle) * M_PI), 1., 0., 0.);
+ cairo_transform (cr, &s);
+ cairo_translate (cr, - double_from_16_16 (skew->center_x), - double_from_16_16 (skew->center_y));
+ status = draw_paint (render, &skew->paint, cr);
+
+ cairo_restore (cr);
+
+ return status;
+}
+
+static cairo_status_t
+draw_paint_composite (cairo_colr_glyph_render_t *render,
+ FT_PaintComposite *composite,
+ cairo_t *cr)
+{
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+
+#if DEBUG_COLR
+ printf ("%*sDraw PaintComposite\n", 2 * render->level, "");
+#endif
+
+ cairo_save (cr);
+
+ status = draw_paint (render, &composite->backdrop_paint, cr);
+ if (unlikely (status)) {
+ cairo_pattern_destroy (cairo_pop_group (cr));
+ goto cleanup;
+ }
+
+ cairo_push_group (cr);
+ status = draw_paint (render, &composite->source_paint, cr);
+ if (unlikely (status)) {
+ cairo_pattern_destroy (cairo_pop_group (cr));
+ cairo_pattern_destroy (cairo_pop_group (cr));
+ goto cleanup;
+ }
+
+ cairo_pop_group_to_source (cr);
+ cairo_set_operator (cr, cairo_operator_from_ft_composite_mode (composite->composite_mode));
+ cairo_paint (cr);
+
+ cleanup:
+ cairo_restore (cr);
+
+ return status;
+}
+
+static cairo_status_t
+draw_paint (cairo_colr_glyph_render_t *render,
+ FT_OpaquePaint *paint,
+ cairo_t *cr)
+{
+ FT_COLR_Paint p;
+ FT_Size orig_size;
+ FT_Size unscaled_size;
+ FT_Matrix orig_transform;
+ FT_Vector orig_delta;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+ assert (cairo_status (cr) == CAIRO_STATUS_SUCCESS);
+
+ if (!FT_Get_Paint (render->face, *paint, &p))
+ return CAIRO_STATUS_NO_MEMORY;
+
+ if (render->level == 0) {
+ /* Now that the FT_Get_Paint call has applied the root transform,
+ * make the face unscaled and untransformed, so we can load glyph
+ * contours.
+ */
+
+ FT_Matrix transform;
+ FT_Vector delta;
+
+ orig_size = render->face->size;
+ FT_New_Size (render->face, &unscaled_size);
+ FT_Activate_Size (unscaled_size);
+ FT_Set_Char_Size (render->face, render->face->units_per_EM << 6, 0, 0, 0);
+
+ transform.xx = transform.yy = 1 << 16;
+ transform.xy = transform.yx = 0;
+ delta.x = delta.y = 0;
+
+ FT_Get_Transform (render->face, &orig_transform, &orig_delta);
+ FT_Set_Transform (render->face, &transform, &delta);
+ }
+
+ render->level++;
+
+ switch (p.format) {
+ case FT_COLR_PAINTFORMAT_COLR_LAYERS:
+ status = draw_paint_colr_layers (render, &p.u.colr_layers, cr);
+ break;
+ case FT_COLR_PAINTFORMAT_SOLID:
+ status = draw_paint_solid (render, &p.u.solid, cr);
+ break;
+ case FT_COLR_PAINTFORMAT_LINEAR_GRADIENT:
+ status = draw_paint_linear_gradient (render, &p.u.linear_gradient, cr);
+ break;
+ case FT_COLR_PAINTFORMAT_RADIAL_GRADIENT:
+ status = draw_paint_radial_gradient (render, &p.u.radial_gradient, cr);
+ break;
+ case FT_COLR_PAINTFORMAT_SWEEP_GRADIENT:
+ status = draw_paint_sweep_gradient (render, &p.u.sweep_gradient, cr);
+ break;
+ case FT_COLR_PAINTFORMAT_GLYPH:
+ status = draw_paint_glyph (render, &p.u.glyph, cr);
+ break;
+ case FT_COLR_PAINTFORMAT_COLR_GLYPH:
+ status = draw_paint_colr_glyph (render, &p.u.colr_glyph, cr);
+ break;
+ case FT_COLR_PAINTFORMAT_TRANSFORM:
+ status = draw_paint_transform (render, &p.u.transform, cr);
+ break;
+ case FT_COLR_PAINTFORMAT_TRANSLATE:
+ status = draw_paint_translate (render, &p.u.translate, cr);
+ break;
+ case FT_COLR_PAINTFORMAT_ROTATE:
+ status = draw_paint_rotate (render, &p.u.rotate, cr);
+ break;
+ case FT_COLR_PAINTFORMAT_SCALE:
+ status = draw_paint_scale (render, &p.u.scale, cr);
+ break;
+ case FT_COLR_PAINTFORMAT_SKEW:
+ status = draw_paint_skew (render, &p.u.skew, cr);
+ break;
+ case FT_COLR_PAINTFORMAT_COMPOSITE:
+ status = draw_paint_composite (render, &p.u.composite, cr);
+ break;
+ case FT_COLR_PAINT_FORMAT_MAX:
+ case FT_COLR_PAINTFORMAT_UNSUPPORTED:
+ default:
+ ASSERT_NOT_REACHED;
+ }
+
+ render->level--;
+
+ if (render->level == 0) {
+ FT_Set_Transform (render->face, &orig_transform, &orig_delta);
+ FT_Activate_Size (orig_size);
+ FT_Done_Size (unscaled_size);
+ }
+
+ return status;
+}
+
+static cairo_status_t
+draw_colr_glyph (cairo_colr_glyph_render_t *render,
+ unsigned long glyph,
+ FT_Color_Root_Transform root,
+ cairo_t *cr)
+{
+ FT_OpaquePaint paint = { NULL, 0 };
+ FT_ClipBox box;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+ cairo_save (cr);
+
+ if (FT_Get_Color_Glyph_ClipBox (render->face, glyph, &box)) {
+ double xmin, ymin, xmax, ymax;
+
+ xmin = double_from_26_6 (box.bottom_left.x);
+ ymin = double_from_26_6 (box.bottom_left.y);
+ xmax = double_from_26_6 (box.top_right.x);
+ ymax = double_from_26_6 (box.top_right.y);
+
+ cairo_new_path (cr);
+ cairo_rectangle (cr, xmin, ymin, xmax - xmin, ymax - ymin);
+ cairo_clip (cr);
+ }
+
+ if (FT_Get_Color_Glyph_Paint (render->face, glyph, root, &paint))
+ status = draw_paint (render, &paint, cr);
+
+ cairo_restore (cr);
+
+ return status;
+}
+
+/* Create an image surface and render the glyph onto it,
+ * using the given colors.
+ */
+cairo_status_t
+_cairo_render_colr_v1_glyph (FT_Face face,
+ unsigned long glyph,
+ FT_Color *palette,
+ int num_palette_entries,
+ cairo_t *cr,
+ cairo_pattern_t *foreground_source,
+ cairo_bool_t *foreground_source_used)
+{
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_colr_glyph_render_t colr_render;
+
+#if DEBUG_COLR
+ printf ("_cairo_render_colr_glyph glyph index: %ld\n", glyph);
+#endif
+
+ colr_render.face = face;
+ colr_render.palette = palette;
+ colr_render.num_palette_entries = num_palette_entries;
+ colr_render.foreground_marker = _cairo_pattern_create_foreground_marker ();
+ colr_render.foreground_source = cairo_pattern_reference (foreground_source);;
+ colr_render.foreground_source_used = FALSE;
+ colr_render.level = 0;
+
+ status = draw_colr_glyph (&colr_render,
+ glyph,
+ FT_COLOR_INCLUDE_ROOT_TRANSFORM,
+ cr);
+
+ cairo_pattern_destroy (colr_render.foreground_marker);
+ cairo_pattern_destroy (colr_render.foreground_source);
+ *foreground_source_used = colr_render.foreground_source_used;
+
+ return status;
+}
+
+#endif /* HAVE_FT_COLR_V1 */
diff --git a/src/cairo-debug.c b/src/cairo-debug.c
index a314eefbf..11777f04b 100644
--- a/src/cairo-debug.c
+++ b/src/cairo-debug.c
@@ -319,3 +319,102 @@ _cairo_debug_print_rect (FILE *file, const cairo_rectangle_int_t *rect)
rect->x, rect->y,
rect->width, rect->height);
}
+
+const char *
+_cairo_debug_operator_to_string (cairo_operator_t op)
+{
+ switch (op) {
+ case CAIRO_OPERATOR_CLEAR: return "CLEAR";
+ case CAIRO_OPERATOR_SOURCE: return "SOURCE";
+ case CAIRO_OPERATOR_OVER: return "OVER";
+ case CAIRO_OPERATOR_IN: return "IN";
+ case CAIRO_OPERATOR_OUT: return "OUT";
+ case CAIRO_OPERATOR_ATOP: return "ATOP";
+ case CAIRO_OPERATOR_DEST: return "DEST";
+ case CAIRO_OPERATOR_DEST_OVER: return "DEST_OVER";
+ case CAIRO_OPERATOR_DEST_IN: return "DEST_IN";
+ case CAIRO_OPERATOR_DEST_OUT: return "DEST_OUT";
+ case CAIRO_OPERATOR_DEST_ATOP: return "DEST_ATOP";
+ case CAIRO_OPERATOR_XOR: return "XOR";
+ case CAIRO_OPERATOR_ADD: return "ADD";
+ case CAIRO_OPERATOR_SATURATE: return "SATURATE";
+ case CAIRO_OPERATOR_MULTIPLY: return "MULTIPLY";
+ case CAIRO_OPERATOR_SCREEN: return "SCREEN";
+ case CAIRO_OPERATOR_OVERLAY: return "OVERLAY";
+ case CAIRO_OPERATOR_DARKEN: return "DARKEN";
+ case CAIRO_OPERATOR_LIGHTEN: return "LIGHTEN";
+ case CAIRO_OPERATOR_COLOR_DODGE: return "COLOR_DODGE";
+ case CAIRO_OPERATOR_COLOR_BURN: return "COLOR_BURN";
+ case CAIRO_OPERATOR_HARD_LIGHT: return "HARD_LIGHT";
+ case CAIRO_OPERATOR_SOFT_LIGHT: return "SOFT_LIGHT";
+ case CAIRO_OPERATOR_DIFFERENCE: return "DIFFERENCE";
+ case CAIRO_OPERATOR_EXCLUSION: return "EXCLUSION";
+ case CAIRO_OPERATOR_HSL_HUE: return "HSL_HUE";
+ case CAIRO_OPERATOR_HSL_SATURATION: return "HSL_SATURATION";
+ case CAIRO_OPERATOR_HSL_COLOR: return "HSL_COLOR";
+ case CAIRO_OPERATOR_HSL_LUMINOSITY: return "HSL_LUMINOSITY";
+ }
+ return "UNKNOWN";
+}
+
+const char *
+_cairo_debug_status_to_string (cairo_int_status_t status)
+{
+ switch (status) {
+ case CAIRO_INT_STATUS_SUCCESS: return "SUCCESS";
+ case CAIRO_INT_STATUS_NO_MEMORY: return "NO_MEMORY";
+ case CAIRO_INT_STATUS_INVALID_RESTORE: return "INVALID_RESTORE";
+ case CAIRO_INT_STATUS_INVALID_POP_GROUP: return "INVALID_POP_GROUP";
+ case CAIRO_INT_STATUS_NO_CURRENT_POINT: return "NO_CURRENT_POINT";
+ case CAIRO_INT_STATUS_INVALID_MATRIX: return "INVALID_MATRIX";
+ case CAIRO_INT_STATUS_INVALID_STATUS: return "INVALID_STATUS";
+ case CAIRO_INT_STATUS_NULL_POINTER: return "NULL_POINTER";
+ case CAIRO_INT_STATUS_INVALID_STRING: return "INVALID_STRING";
+ case CAIRO_INT_STATUS_INVALID_PATH_DATA: return "INVALID_PATH_DATA";
+ case CAIRO_INT_STATUS_READ_ERROR: return "READ_ERROR";
+ case CAIRO_INT_STATUS_WRITE_ERROR: return "WRITE_ERROR";
+ case CAIRO_INT_STATUS_SURFACE_FINISHED: return "SURFACE_FINISHED";
+ case CAIRO_INT_STATUS_SURFACE_TYPE_MISMATCH: return "SURFACE_TYPE_MISMATCH";
+ case CAIRO_INT_STATUS_PATTERN_TYPE_MISMATCH: return "PATTERN_TYPE_MISMATCH";
+ case CAIRO_INT_STATUS_INVALID_CONTENT: return "INVALID_CONTENT";
+ case CAIRO_INT_STATUS_INVALID_FORMAT: return "INVALID_FORMAT";
+ case CAIRO_INT_STATUS_INVALID_VISUAL: return "INVALID_VISUAL";
+ case CAIRO_INT_STATUS_FILE_NOT_FOUND: return "FILE_NOT_FOUND";
+ case CAIRO_INT_STATUS_INVALID_DASH: return "INVALID_DASH";
+ case CAIRO_INT_STATUS_INVALID_DSC_COMMENT: return "INVALID_DSC_COMMENT";
+ case CAIRO_INT_STATUS_INVALID_INDEX: return "INVALID_INDEX";
+ case CAIRO_INT_STATUS_CLIP_NOT_REPRESENTABLE: return "CLIP_NOT_REPRESENTABLE";
+ case CAIRO_INT_STATUS_TEMP_FILE_ERROR: return "TEMP_FILE_ERROR";
+ case CAIRO_INT_STATUS_INVALID_STRIDE: return "INVALID_STRIDE";
+ case CAIRO_INT_STATUS_FONT_TYPE_MISMATCH: return "FONT_TYPE_MISMATCH";
+ case CAIRO_INT_STATUS_USER_FONT_IMMUTABLE: return "USER_FONT_IMMUTABLE";
+ case CAIRO_INT_STATUS_USER_FONT_ERROR: return "USER_FONT_ERROR";
+ case CAIRO_INT_STATUS_NEGATIVE_COUNT: return "NEGATIVE_COUNT";
+ case CAIRO_INT_STATUS_INVALID_CLUSTERS: return "INVALID_CLUSTERS";
+ case CAIRO_INT_STATUS_INVALID_SLANT: return "INVALID_SLANT";
+ case CAIRO_INT_STATUS_INVALID_WEIGHT: return "INVALID_WEIGHT";
+ case CAIRO_INT_STATUS_INVALID_SIZE: return "INVALID_SIZE";
+ case CAIRO_INT_STATUS_USER_FONT_NOT_IMPLEMENTED: return "USER_FONT_NOT_IMPLEMENTED";
+ case CAIRO_INT_STATUS_DEVICE_TYPE_MISMATCH: return "DEVICE_TYPE_MISMATCH";
+ case CAIRO_INT_STATUS_DEVICE_ERROR: return "DEVICE_ERROR";
+ case CAIRO_INT_STATUS_INVALID_MESH_CONSTRUCTION: return "INVALID_MESH_CONSTRUCTION";
+ case CAIRO_INT_STATUS_DEVICE_FINISHED: return "DEVICE_FINISHED";
+ case CAIRO_INT_STATUS_JBIG2_GLOBAL_MISSING: return "JBIG2_GLOBAL_MISSING";
+ case CAIRO_INT_STATUS_PNG_ERROR: return "PNG_ERROR";
+ case CAIRO_INT_STATUS_FREETYPE_ERROR: return "FREETYPE_ERROR";
+ case CAIRO_INT_STATUS_WIN32_GDI_ERROR: return "WIN32_GDI_ERROR";
+ case CAIRO_INT_STATUS_TAG_ERROR: return "TAG_ERROR";
+ case CAIRO_INT_STATUS_DWRITE_ERROR: return "DWRITE_ERROR";
+ case CAIRO_INT_STATUS_SVG_FONT_ERROR: return "SVG_FONT_ERROR";
+
+ case CAIRO_INT_STATUS_LAST_STATUS: return "LAST_STATUS";
+
+ case CAIRO_INT_STATUS_UNSUPPORTED: return "UNSUPPORTED";
+ case CAIRO_INT_STATUS_DEGENERATE: return "DEGENERATE";
+ case CAIRO_INT_STATUS_NOTHING_TO_DO: return "NOTHING_TO_DO";
+ case CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY: return "FLATTEN_TRANSPARENCY";
+ case CAIRO_INT_STATUS_IMAGE_FALLBACK: return "IMAGE_FALLBACK";
+ case CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN: return "ANALYZE_RECORDING_SURFACE_PATTERN";
+ }
+ return "UNKNOWN";
+}
diff --git a/src/cairo-device.c b/src/cairo-device.c
index 50e7ee484..57b63a778 100644
--- a/src/cairo-device.c
+++ b/src/cairo-device.c
@@ -164,6 +164,7 @@ _cairo_device_create_in_error (cairo_status_t status)
case CAIRO_STATUS_WIN32_GDI_ERROR:
case CAIRO_STATUS_TAG_ERROR:
case CAIRO_STATUS_DWRITE_ERROR:
+ case CAIRO_STATUS_SVG_FONT_ERROR:
default:
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_device_t *) &_nil_device;
diff --git a/src/cairo-xml.h b/src/cairo-dwrite.h
index 9ae76e90a..b1ff718a0 100644
--- a/src/cairo-xml.h
+++ b/src/cairo-dwrite.h
@@ -1,6 +1,6 @@
/* cairo - a vector graphics library with display and print output
*
- * Copyright © 2009 Chris Wilson
+ * Copyright © 2023 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
@@ -27,41 +27,46 @@
*
* 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>
+ * Adrian Johnson <ajohnson@redneon.com>
*/
-#ifndef CAIRO_XML_H
-#define CAIRO_XML_H
+#ifndef _CAIRO_DWRITE_H_
+#define _CAIRO_DWRITE_H_
#include "cairo.h"
-#if CAIRO_HAS_XML_SURFACE
+#if CAIRO_HAS_DWRITE_FONT
+
+#ifdef __cplusplus
+
+#include <dwrite.h>
CAIRO_BEGIN_DECLS
-cairo_public cairo_device_t *
-cairo_xml_create (const char *filename);
+cairo_public cairo_font_face_t *
+cairo_dwrite_font_face_create_for_dwrite_fontface (IDWriteFontFace *dwrite_font_face);
-cairo_public cairo_device_t *
-cairo_xml_create_for_stream (cairo_write_func_t write_func,
- void *closure);
+cairo_public IDWriteRenderingParams *
+cairo_dwrite_font_face_get_rendering_params (cairo_font_face_t *font_face);
-cairo_public cairo_surface_t *
-cairo_xml_surface_create (cairo_device_t *xml,
- cairo_content_t content,
- double width, double height);
+cairo_public void
+cairo_dwrite_font_face_set_rendering_params (cairo_font_face_t *font_face, IDWriteRenderingParams *params);
-cairo_public cairo_status_t
-cairo_xml_for_recording_surface (cairo_device_t *xml,
- cairo_surface_t *surface);
+cairo_public DWRITE_MEASURING_MODE
+cairo_dwrite_font_face_get_measuring_mode (cairo_font_face_t *font_face);
+
+cairo_public void
+cairo_dwrite_font_face_set_measuring_mode (cairo_font_face_t *font_face, DWRITE_MEASURING_MODE mode);
CAIRO_END_DECLS
-#else /*CAIRO_HAS_XML_SURFACE*/
-# error Cairo was not compiled with support for the XML backend
-#endif /*CAIRO_HAS_XML_SURFACE*/
+#else /* __cplusplus */
+#error DWrite font backend requires C++
+#endif /* __cplusplus */
+
+#else /* CAIRO_HAS_DWRITE_FONT */
+# error Cairo was not compiled with support for DWrite font backend
+#endif /* CAIRO_HAS_DWRITE_FONT */
-#endif /*CAIRO_XML_H*/
+#endif /* _CAIRO_DWRITE_H_ */
diff --git a/src/cairo-egl-context.c b/src/cairo-egl-context.c
deleted file mode 100644
index bf704c630..000000000
--- a/src/cairo-egl-context.c
+++ /dev/null
@@ -1,317 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 Eric Anholt
- * Copyright © 2009 Chris Wilson
- * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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):
- * Carl Worth <cworth@cworth.org>
- * Chris Wilson <chris@chris-wilson.co.uk>
- */
-
-#include "cairoint.h"
-
-#include "cairo-gl-private.h"
-
-#include "cairo-error-private.h"
-
-typedef struct _cairo_egl_context {
- cairo_gl_context_t base;
-
- EGLDisplay display;
- EGLContext context;
-
- EGLSurface dummy_surface;
-
- EGLContext previous_context;
- EGLSurface previous_surface;
-} cairo_egl_context_t;
-
-typedef struct _cairo_egl_surface {
- cairo_gl_surface_t base;
-
- EGLSurface egl;
-} cairo_egl_surface_t;
-
-
-static cairo_bool_t
-_context_acquisition_changed_egl_state (cairo_egl_context_t *ctx,
- EGLSurface current_surface)
-{
- return ctx->previous_context != ctx->context ||
- ctx->previous_surface != current_surface;
-}
-
-static EGLSurface
-_egl_get_current_surface (cairo_egl_context_t *ctx)
-{
- if (ctx->base.current_target == NULL ||
- _cairo_gl_surface_is_texture (ctx->base.current_target)) {
- return ctx->dummy_surface;
- }
-
- return ((cairo_egl_surface_t *) ctx->base.current_target)->egl;
-}
-
-static void
-_egl_query_current_state (cairo_egl_context_t *ctx)
-{
- ctx->previous_surface = eglGetCurrentSurface (EGL_DRAW);
- ctx->previous_context = eglGetCurrentContext ();
-
- /* If any of the values were none, assume they are all none. Not all
- drivers seem well behaved when it comes to using these values across
- multiple threads. */
- if (ctx->previous_surface == EGL_NO_SURFACE ||
- ctx->previous_context == EGL_NO_CONTEXT) {
- ctx->previous_surface = EGL_NO_SURFACE;
- ctx->previous_context = EGL_NO_CONTEXT;
- }
-}
-
-static void
-_egl_acquire (void *abstract_ctx)
-{
- cairo_egl_context_t *ctx = abstract_ctx;
- EGLSurface current_surface = _egl_get_current_surface (ctx);
-
- _egl_query_current_state (ctx);
- if (!_context_acquisition_changed_egl_state (ctx, current_surface))
- return;
-
- eglMakeCurrent (ctx->display,
- current_surface, current_surface, ctx->context);
-}
-
-static void
-_egl_release (void *abstract_ctx)
-{
- cairo_egl_context_t *ctx = abstract_ctx;
- if (!ctx->base.thread_aware ||
- !_context_acquisition_changed_egl_state (ctx,
- _egl_get_current_surface (ctx))) {
- return;
- }
-
- eglMakeCurrent (ctx->display,
- EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-}
-
-static void
-_egl_make_current (void *abstract_ctx,
- cairo_gl_surface_t *abstract_surface)
-{
- cairo_egl_context_t *ctx = abstract_ctx;
- cairo_egl_surface_t *surface = (cairo_egl_surface_t *) abstract_surface;
-
- eglMakeCurrent(ctx->display, surface->egl, surface->egl, ctx->context);
-}
-
-static void
-_egl_swap_buffers (void *abstract_ctx,
- cairo_gl_surface_t *abstract_surface)
-{
- cairo_egl_context_t *ctx = abstract_ctx;
- cairo_egl_surface_t *surface = (cairo_egl_surface_t *) abstract_surface;
-
- eglSwapBuffers (ctx->display, surface->egl);
-}
-
-static void
-_egl_destroy (void *abstract_ctx)
-{
- cairo_egl_context_t *ctx = abstract_ctx;
-
- eglMakeCurrent (ctx->display,
- EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- if (ctx->dummy_surface != EGL_NO_SURFACE)
- eglDestroySurface (ctx->display, ctx->dummy_surface);
-}
-
-static cairo_bool_t
-_egl_make_current_surfaceless(cairo_egl_context_t *ctx)
-{
- const char *extensions;
-
- extensions = eglQueryString(ctx->display, EGL_EXTENSIONS);
- if (strstr(extensions, "EGL_KHR_surfaceless_context") == NULL &&
- strstr(extensions, "EGL_KHR_surfaceless_opengl") == NULL)
- return FALSE;
-
- if (!eglMakeCurrent(ctx->display,
- EGL_NO_SURFACE, EGL_NO_SURFACE, ctx->context))
- return FALSE;
-
- return TRUE;
-}
-
-cairo_device_t *
-cairo_egl_device_create (EGLDisplay dpy, EGLContext egl)
-{
- cairo_egl_context_t *ctx;
- cairo_status_t status;
- int attribs[] = {
- EGL_WIDTH, 1,
- EGL_HEIGHT, 1,
- EGL_NONE,
- };
- EGLConfig config;
- EGLint numConfigs;
-
- ctx = calloc (1, sizeof (cairo_egl_context_t));
- if (unlikely (ctx == NULL))
- return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
-
- ctx->display = dpy;
- ctx->context = egl;
-
- ctx->base.acquire = _egl_acquire;
- ctx->base.release = _egl_release;
- ctx->base.make_current = _egl_make_current;
- ctx->base.swap_buffers = _egl_swap_buffers;
- ctx->base.destroy = _egl_destroy;
-
- /* We are about the change the current state of EGL, so we should
- * query the pre-existing surface now instead of later. */
- _egl_query_current_state (ctx);
-
- if (!_egl_make_current_surfaceless (ctx)) {
- /* Fall back to dummy surface, meh. */
- EGLint config_attribs[] = {
- EGL_CONFIG_ID, 0,
- EGL_NONE
- };
-
- /*
- * In order to be able to make an egl context current when using a
- * pbuffer surface, that surface must have been created with a config
- * that is compatible with the context config. For Mesa, this means
- * that the configs must be the same.
- */
- eglQueryContext (dpy, egl, EGL_CONFIG_ID, &config_attribs[1]);
- eglChooseConfig (dpy, config_attribs, &config, 1, &numConfigs);
-
- ctx->dummy_surface = eglCreatePbufferSurface (dpy, config, attribs);
- if (ctx->dummy_surface == NULL) {
- free (ctx);
- return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- if (!eglMakeCurrent (dpy, ctx->dummy_surface, ctx->dummy_surface, egl)) {
- free (ctx);
- return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
- }
- }
-
- status = _cairo_gl_dispatch_init (&ctx->base.dispatch, eglGetProcAddress);
- if (unlikely (status)) {
- free (ctx);
- return _cairo_gl_context_create_in_error (status);
- }
-
- status = _cairo_gl_context_init (&ctx->base);
- if (unlikely (status)) {
- if (ctx->dummy_surface != EGL_NO_SURFACE)
- eglDestroySurface (dpy, ctx->dummy_surface);
- free (ctx);
- return _cairo_gl_context_create_in_error (status);
- }
-
- /* Tune the default VBO size to reduce overhead on embedded devices.
- * This smaller size means that flushing needs to be done more often,
- * but it is less demanding of scarce memory on embedded devices.
- */
- ctx->base.vbo_size = 16*1024;
-
- eglMakeCurrent (dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-
- return &ctx->base.base;
-}
-
-cairo_surface_t *
-cairo_gl_surface_create_for_egl (cairo_device_t *device,
- EGLSurface egl,
- int width,
- int height)
-{
- cairo_egl_surface_t *surface;
-
- if (unlikely (device->status))
- return _cairo_surface_create_in_error (device->status);
-
- if (device->backend->type != CAIRO_DEVICE_TYPE_GL)
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
-
- if (width <= 0 || height <= 0)
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
-
- surface = calloc (1, sizeof (cairo_egl_surface_t));
- if (unlikely (surface == NULL))
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
-
- _cairo_gl_surface_init (device, &surface->base,
- CAIRO_CONTENT_COLOR_ALPHA, width, height);
- surface->egl = egl;
-
- return &surface->base.base;
-}
-
-static cairo_bool_t is_egl_device (cairo_device_t *device)
-{
- return (device->backend != NULL &&
- device->backend->type == CAIRO_DEVICE_TYPE_GL);
-}
-
-static cairo_egl_context_t *to_egl_context (cairo_device_t *device)
-{
- return (cairo_egl_context_t *) device;
-}
-
-EGLDisplay
-cairo_egl_device_get_display (cairo_device_t *device)
-{
- if (! is_egl_device (device)) {
- _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
- return EGL_NO_DISPLAY;
- }
-
- return to_egl_context (device)->display;
-}
-
-cairo_public EGLContext
-cairo_egl_device_get_context (cairo_device_t *device)
-{
- if (! is_egl_device (device)) {
- _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
- return EGL_NO_CONTEXT;
- }
-
- return to_egl_context (device)->context;
-}
diff --git a/src/cairo-error-private.h b/src/cairo-error-private.h
index d84d4c23d..ba95db767 100644
--- a/src/cairo-error-private.h
+++ b/src/cairo-error-private.h
@@ -99,6 +99,7 @@ enum _cairo_int_status {
CAIRO_INT_STATUS_WIN32_GDI_ERROR,
CAIRO_INT_STATUS_TAG_ERROR,
CAIRO_INT_STATUS_DWRITE_ERROR,
+ CAIRO_INT_STATUS_SVG_FONT_ERROR,
CAIRO_INT_STATUS_LAST_STATUS,
diff --git a/src/cairo-features-uninstalled.pc.in b/src/cairo-features-uninstalled.pc.in
deleted file mode 100644
index b9cd9d3ad..000000000
--- a/src/cairo-features-uninstalled.pc.in
+++ /dev/null
@@ -1,7 +0,0 @@
-Name: @FEATURE_PC@
-Description: @FEATURE_NAME@ for cairo graphics library
-Version: @VERSION@
-
-Requires: @FEATURE_BASE@ @FEATURE_REQUIRES@
-Libs: @FEATURE_NONPKGCONFIG_LIBS@ @FEATURE_NONPKGCONFIG_EXTRA_LIBS@
-Cflags: -I${pc_top_builddir}/${pcfiledir}/@srcdir@/src @FEATURE_NONPKGCONFIG_CFLAGS@
diff --git a/src/cairo-features.pc.in b/src/cairo-features.pc.in
deleted file mode 100644
index 9a4b657c8..000000000
--- a/src/cairo-features.pc.in
+++ /dev/null
@@ -1,12 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: @FEATURE_PC@
-Description: @FEATURE_NAME@ for cairo graphics library
-Version: @VERSION@
-
-Requires: @FEATURE_BASE@ @FEATURE_REQUIRES@
-Libs: @FEATURE_NONPKGCONFIG_LIBS@ @FEATURE_NONPKGCONFIG_EXTRA_LIBS@
-Cflags: -I${includedir}/cairo @FEATURE_NONPKGCONFIG_CFLAGS@
diff --git a/src/cairo-font-options.c b/src/cairo-font-options.c
index 30d695894..33ee617b8 100644
--- a/src/cairo-font-options.c
+++ b/src/cairo-font-options.c
@@ -58,7 +58,8 @@ static const cairo_font_options_t _cairo_font_options_nil = {
CAIRO_ROUND_GLYPH_POS_DEFAULT,
NULL, /* variations */
CAIRO_COLOR_MODE_DEFAULT,
- CAIRO_COLOR_PALETTE_DEFAULT
+ CAIRO_COLOR_PALETTE_DEFAULT,
+ NULL, 0, /* custom palette */
};
/**
@@ -79,6 +80,8 @@ _cairo_font_options_init_default (cairo_font_options_t *options)
options->variations = NULL;
options->color_mode = CAIRO_COLOR_MODE_DEFAULT;
options->palette_index = CAIRO_COLOR_PALETTE_DEFAULT;
+ options->custom_palette = NULL;
+ options->custom_palette_size = 0;
}
void
@@ -94,6 +97,47 @@ _cairo_font_options_init_copy (cairo_font_options_t *options,
options->variations = other->variations ? strdup (other->variations) : NULL;
options->color_mode = other->color_mode;
options->palette_index = other->palette_index;
+ options->custom_palette_size = other->custom_palette_size;
+ options->custom_palette = NULL;
+ if (other->custom_palette) {
+ options->custom_palette = (cairo_palette_color_t *) malloc (sizeof (cairo_palette_color_t) * options->custom_palette_size);
+ memcpy (options->custom_palette, other->custom_palette, sizeof (cairo_palette_color_t) * options->custom_palette_size);
+ }
+}
+
+cairo_bool_t
+_cairo_font_options_compare (const cairo_font_options_t *a,
+ const cairo_font_options_t *b)
+{
+ if (a->antialias != b->antialias ||
+ a->subpixel_order != b->subpixel_order ||
+ a->lcd_filter != b->lcd_filter ||
+ a->hint_style != b->hint_style ||
+ a->hint_metrics != b->hint_metrics ||
+ a->round_glyph_positions != b->round_glyph_positions ||
+ a->color_mode != b->color_mode ||
+ a->palette_index != b->palette_index ||
+ a->custom_palette_size != b->custom_palette_size)
+ {
+ return FALSE;
+ }
+
+ if (a->variations && b->variations && strcmp (a->variations, b->variations) != 0)
+ return FALSE;
+ else if (a->variations != b->variations)
+ return FALSE;
+
+ if (a->custom_palette && b->custom_palette &&
+ memcmp (a->custom_palette, b->custom_palette, sizeof (cairo_palette_color_t) * a->custom_palette_size) != 0)
+ {
+ return FALSE;
+ }
+ else if (a->custom_palette != b->custom_palette)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
}
/**
@@ -164,6 +208,7 @@ void
_cairo_font_options_fini (cairo_font_options_t *options)
{
free (options->variations);
+ free (options->custom_palette);
}
/**
@@ -266,6 +311,12 @@ cairo_font_options_merge (cairo_font_options_t *options,
options->color_mode = other->color_mode;
if (other->palette_index != CAIRO_COLOR_PALETTE_DEFAULT)
options->palette_index = other->palette_index;
+ if (other->custom_palette) {
+ options->custom_palette_size = other->custom_palette_size;
+ free (options->custom_palette);
+ options->custom_palette = (cairo_palette_color_t *) malloc (sizeof (cairo_palette_color_t) * options->custom_palette_size);
+ memcpy (options->custom_palette, other->custom_palette, sizeof (cairo_palette_color_t) * options->custom_palette_size);
+ }
}
slim_hidden_def (cairo_font_options_merge);
@@ -304,7 +355,12 @@ cairo_font_options_equal (const cairo_font_options_t *options,
(options->variations != NULL && other->variations != NULL &&
strcmp (options->variations, other->variations) == 0)) &&
options->color_mode == other->color_mode &&
- options->palette_index == other->palette_index);
+ options->palette_index == other->palette_index &&
+ ((options->custom_palette == NULL && other->custom_palette == NULL) ||
+ (options->custom_palette != NULL && other->custom_palette != NULL &&
+ options->custom_palette_size == other->custom_palette_size &&
+ memcmp (options->custom_palette, other->custom_palette,
+ sizeof (cairo_palette_color_t) * options->custom_palette_size) == 0)));
}
slim_hidden_def (cairo_font_options_equal);
@@ -641,7 +697,7 @@ cairo_font_options_get_variations (cairo_font_options_t *options)
/**
* cairo_font_options_set_color_mode:
* @options: a #cairo_font_options_t
- * @font_color: the new color mode
+ * @color_mode: the new color mode
*
* Sets the color mode for the font options object. This controls
* whether color fonts are to be rendered in color or as outlines.
@@ -680,14 +736,26 @@ cairo_font_options_get_color_mode (const cairo_font_options_t *options)
}
/**
+ * CAIRO_COLOR_PALETTE_DEFAULT:
+ *
+ * The default color palette index.
+ *
+ * Since: 1.18
+ **/
+
+/**
* cairo_font_options_set_color_palette:
* @options: a #cairo_font_options_t
* @palette_index: the palette index in the CPAL table
*
* Sets the OpenType font color palette for the font options
* object. OpenType color fonts with a CPAL table may contain multiple
- * palettes. The default color palette index is %CAIRO_COLOR_PALETTE_DEFAULT. If
- * @palette_index is invalid, the default palette is used.
+ * palettes. The default color palette index is %CAIRO_COLOR_PALETTE_DEFAULT.
+ *
+ * If @palette_index is invalid, the default palette is used.
+ *
+ * Individual colors within the palette may be overriden with
+ * cairo_font_options_set_custom_palette_color().
*
* Since: 1.18
**/
@@ -705,7 +773,7 @@ cairo_font_options_set_color_palette (cairo_font_options_t *options,
* cairo_font_options_get_color_palette:
* @options: a #cairo_font_options_t
*
- * Gets the OpenType color font palette for the font options object.
+ * Gets the current OpenType color font palette for the font options object.
*
* Return value: the palette index
*
@@ -719,3 +787,94 @@ cairo_font_options_get_color_palette (const cairo_font_options_t *options)
return options->palette_index;
}
+
+/**
+ * cairo_font_options_set_custom_palette_color:
+ * @options: a #cairo_font_options_t
+ * @index: the index of the color to set
+ * @red: red component of color
+ * @green: green component of color
+ * @blue: blue component of color
+ * @alpha: alpha component of color
+ *
+ * Sets a custom palette color for the font options object. This
+ * overrides the palette color at the specified color index. This override is
+ * independent of the selected palette index and will remain in place
+ * even if cairo_font_options_set_color_palette() is called to change
+ * the palette index.
+ *
+ * It is only possible to override color indexes already in the font
+ * palette.
+ *
+ * Since: 1.18
+ */
+void
+cairo_font_options_set_custom_palette_color (cairo_font_options_t *options,
+ unsigned int index,
+ double red, double green,
+ double blue, double alpha)
+{
+ unsigned int idx;
+
+ for (idx = 0; idx < options->custom_palette_size; idx++) {
+ if (options->custom_palette[idx].index == index) {
+ break;
+ }
+ }
+
+ if (idx == options->custom_palette_size) {
+ options->custom_palette_size++;
+ options->custom_palette = (cairo_palette_color_t *)
+ _cairo_realloc_ab (options->custom_palette,
+ sizeof (cairo_palette_color_t),
+ options->custom_palette_size);
+ }
+
+ /* beware of holes */
+ memset (&options->custom_palette[idx], 0, sizeof (cairo_palette_color_t));
+
+ options->custom_palette[idx].index = index;
+ options->custom_palette[idx].red = red;
+ options->custom_palette[idx].green = green;
+ options->custom_palette[idx].blue = blue;
+ options->custom_palette[idx].alpha = alpha;
+}
+
+/**
+ * cairo_font_options_get_custom_palette_color:
+ * @options: a #cairo_font_options_t
+ * @index: the index of the color to get
+ * @red: return location for red component of color
+ * @green: return location for green component of color
+ * @blue: return location for blue component of color
+ * @alpha: return location for alpha component of color
+ *
+ * Gets the custom palette color for the color index for the font options object.
+ *
+ * Returns: `CAIRO_STATUS_SUCCESS` if a custom palette color is
+ * returned, `CAIRO_STATUS_INVALID_INDEX` if no custom color exists
+ * for the color index.
+ *
+ * Since: 1.18
+ */
+cairo_status_t
+cairo_font_options_get_custom_palette_color (cairo_font_options_t *options,
+ unsigned int index,
+ double *red, double *green,
+ double *blue, double *alpha)
+{
+ unsigned int idx;
+
+ for (idx = 0; idx < options->custom_palette_size; idx++) {
+ if (options->custom_palette[idx].index == index) {
+ *red = options->custom_palette[idx].red;
+ *green = options->custom_palette[idx].green;
+ *blue = options->custom_palette[idx].blue;
+ *alpha = options->custom_palette[idx].alpha;
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+
+ return CAIRO_STATUS_INVALID_INDEX;
+}
+slim_hidden_def (cairo_font_options_get_custom_palette_color);
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index cdb02ff65..22a6a622b 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -44,8 +44,11 @@
#include "cairo-error-private.h"
#include "cairo-image-surface-private.h"
#include "cairo-ft-private.h"
+#include "cairo-list-inline.h"
+#include "cairo-path-private.h"
#include "cairo-pattern-private.h"
#include "cairo-pixman-private.h"
+#include "cairo-recording-surface-private.h"
#include <float.h>
@@ -67,6 +70,10 @@
#include FT_LCD_FILTER_H
#endif
+#if HAVE_FT_SVG_DOCUMENT
+#include FT_OTSVG_H
+#endif
+
#if HAVE_UNISTD_H
#include <unistd.h>
#elif !defined(access)
@@ -241,17 +248,19 @@ _cairo_ft_resolve_pattern (FcPattern *pattern,
#endif
-static cairo_status_t
-_ft_to_cairo_error (FT_Error error)
+cairo_status_t
+_cairo_ft_to_cairo_error (FT_Error error)
{
/* Currently we don't get many (any?) useful statuses here.
* Populate as needed. */
switch (error)
{
- case FT_Err_Out_Of_Memory:
- return CAIRO_STATUS_NO_MEMORY;
- default:
- return CAIRO_STATUS_FREETYPE_ERROR;
+ case FT_Err_Ok:
+ return CAIRO_STATUS_SUCCESS;
+ case FT_Err_Out_Of_Memory:
+ return CAIRO_STATUS_NO_MEMORY;
+ default:
+ return CAIRO_STATUS_FREETYPE_ERROR;
}
}
@@ -751,7 +760,7 @@ _cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled)
{
unscaled->lock_count--;
CAIRO_MUTEX_UNLOCK (unscaled->mutex);
- _cairo_error_throw (_ft_to_cairo_error (error));
+ _cairo_error_throw (_cairo_ft_to_cairo_error (error));
return NULL;
}
@@ -908,7 +917,7 @@ _cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled,
sf.y_scale * 64.0 + .5,
0, 0);
if (error)
- return _cairo_error (_ft_to_cairo_error (error));
+ return _cairo_error (_cairo_ft_to_cairo_error (error));
return CAIRO_STATUS_SUCCESS;
}
@@ -1350,7 +1359,7 @@ _get_bitmap_surface (FT_Bitmap *bitmap,
error = FT_Bitmap_Convert( library, bitmap, &tmp, align );
if (error)
- return _cairo_error (_ft_to_cairo_error (error));
+ return _cairo_error (_cairo_ft_to_cairo_error (error));
FT_Bitmap_Done( library, bitmap );
*bitmap = tmp;
@@ -1558,7 +1567,7 @@ _render_glyph_outline (FT_Face face,
#endif
if (error)
- return _cairo_error (_ft_to_cairo_error (error));
+ return _cairo_error (_cairo_ft_to_cairo_error (error));
bitmap_size = _compute_xrender_bitmap_size (&bitmap,
face->glyph,
@@ -2261,10 +2270,9 @@ _cubic_to (FT_Vector *control1, FT_Vector *control2,
return 0;
}
-static cairo_status_t
-_decompose_glyph_outline (FT_Face face,
- cairo_font_options_t *options,
- cairo_path_fixed_t **pathp)
+cairo_status_t
+_cairo_ft_face_decompose_glyph_outline (FT_Face face,
+ cairo_path_fixed_t **pathp)
{
static const FT_Outline_Funcs outline_funcs = {
(FT_Outline_MoveToFunc)_move_to,
@@ -2486,6 +2494,110 @@ _cairo_ft_scaled_glyph_load_glyph (cairo_ft_scaled_font_t *scaled_font,
return CAIRO_STATUS_SUCCESS;
}
+typedef enum {
+ CAIRO_FT_GLYPH_TYPE_BITMAP,
+ CAIRO_FT_GLYPH_TYPE_OUTLINE,
+ CAIRO_FT_GLYPH_TYPE_SVG,
+ CAIRO_FT_GLYPH_TYPE_COLR_V0,
+ CAIRO_FT_GLYPH_TYPE_COLR_V1,
+} cairo_ft_glyph_format_t;
+
+typedef struct {
+ cairo_scaled_glyph_private_t base;
+
+ cairo_ft_glyph_format_t format;
+} cairo_ft_glyph_private_t;
+
+static void
+_cairo_ft_glyph_fini (cairo_scaled_glyph_private_t *glyph_private,
+ cairo_scaled_glyph_t *glyph,
+ cairo_scaled_font_t *font)
+{
+ cairo_list_del (&glyph_private->link);
+ free (glyph_private);
+}
+
+
+#ifdef HAVE_FT_PALETTE_SELECT
+static void
+_cairo_ft_scaled_glyph_set_palette (cairo_ft_scaled_font_t *scaled_font,
+ FT_Face face,
+ unsigned int *num_entries_ret,
+ FT_Color **entries_ret)
+{
+ FT_Palette_Data palette_data;
+ unsigned int num_entries;
+ FT_Color *entries;
+
+ num_entries = 0;
+ entries = NULL;
+
+ if (FT_Palette_Data_Get (face, &palette_data) == 0 && palette_data.num_palettes > 0) {
+ FT_UShort palette_index = CAIRO_COLOR_PALETTE_DEFAULT;
+ if (scaled_font->base.options.palette_index < palette_data.num_palettes)
+ palette_index = scaled_font->base.options.palette_index;
+
+ if (FT_Palette_Select (face, palette_index, &entries) == 0) {
+ num_entries = palette_data.num_palette_entries;
+
+ /* Overlay custom colors */
+ for (unsigned int i = 0; i < scaled_font->base.options.custom_palette_size; i++) {
+ cairo_palette_color_t *entry = &scaled_font->base.options.custom_palette[i];
+ if (entry->index < num_entries) {
+ entries[entry->index].red = 255 * entry->red;
+ entries[entry->index].green = 255 * entry->green;
+ entries[entry->index].blue = 255 * entry->blue;
+ entries[entry->index].alpha = 255 * entry->alpha;
+ }
+ }
+ }
+ }
+ if (num_entries_ret)
+ *num_entries_ret = num_entries;
+
+ if (entries_ret)
+ *entries_ret = entries;
+}
+#endif
+
+/* returns TRUE if foreground color used */
+static cairo_bool_t
+_cairo_ft_scaled_glyph_set_foreground_color (cairo_ft_scaled_font_t *scaled_font,
+ cairo_scaled_glyph_t *scaled_glyph,
+ FT_Face face,
+ const cairo_color_t *foreground_color)
+{
+ cairo_bool_t uses_foreground_color = FALSE;
+#ifdef HAVE_FT_PALETTE_SELECT
+ FT_LayerIterator iterator;
+ FT_UInt layer_glyph_index;
+ FT_UInt layer_color_index;
+ FT_Color color;
+
+ /* Check if there is a layer that uses the foreground color */
+ iterator.p = NULL;
+ while (FT_Get_Color_Glyph_Layer(face,
+ _cairo_scaled_glyph_index (scaled_glyph),
+ &layer_glyph_index,
+ &layer_color_index,
+ &iterator)) {
+ if (layer_color_index == 0xFFFF) {
+ uses_foreground_color = TRUE;
+ break;
+ }
+ }
+
+ if (uses_foreground_color) {
+ color.red = (FT_Byte)(foreground_color->red * 0xFF);
+ color.green = (FT_Byte)(foreground_color->green * 0xFF);
+ color.blue = (FT_Byte)(foreground_color->blue * 0xFF);
+ color.alpha = (FT_Byte)(foreground_color->alpha * 0xFF);
+ FT_Palette_Set_Foreground_Color (face, color);
+ }
+#endif
+ return uses_foreground_color;
+}
+
static cairo_int_status_t
_cairo_ft_scaled_glyph_init_surface (cairo_ft_scaled_font_t *scaled_font,
cairo_scaled_glyph_t *scaled_glyph,
@@ -2500,6 +2612,7 @@ _cairo_ft_scaled_glyph_init_surface (cairo_ft_scaled_font_t *scaled_font,
cairo_status_t status;
cairo_image_surface_t *surface;
cairo_bool_t uses_foreground_color = FALSE;
+ cairo_ft_glyph_private_t *glyph_priv = scaled_glyph->dev_private;
/* Only one info type at a time handled in this function */
assert (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE || info == CAIRO_SCALED_GLYPH_INFO_SURFACE);
@@ -2511,41 +2624,12 @@ _cairo_ft_scaled_glyph_init_surface (cairo_ft_scaled_font_t *scaled_font,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
+ uses_foreground_color = _cairo_ft_scaled_glyph_set_foreground_color (scaled_font,
+ scaled_glyph,
+ face,
+ foreground_color);
#ifdef HAVE_FT_PALETTE_SELECT
- FT_LayerIterator iterator;
- FT_UInt layer_glyph_index;
- FT_UInt layer_color_index;
- FT_Color color;
- FT_Palette_Data palette_data;
-
- /* Check if there is a layer that uses the foreground color */
- iterator.p = NULL;
- while (FT_Get_Color_Glyph_Layer(face,
- _cairo_scaled_glyph_index(scaled_glyph),
- &layer_glyph_index,
- &layer_color_index,
- &iterator)) {
- if (layer_color_index == 0xFFFF) {
- uses_foreground_color = TRUE;
- break;
- }
- }
-
- if (uses_foreground_color) {
- color.red = (FT_Byte)(foreground_color->red * 0xFF);
- color.green = (FT_Byte)(foreground_color->green * 0xFF);
- color.blue = (FT_Byte)(foreground_color->blue * 0xFF);
- color.alpha = (FT_Byte)(foreground_color->alpha * 0xFF);
- FT_Palette_Set_Foreground_Color (face, color);
- }
-
- if (FT_Palette_Data_Get(face, &palette_data) == 0 && palette_data.num_palettes > 0) {
- FT_UShort palette_index = CAIRO_COLOR_PALETTE_DEFAULT;
- if (scaled_font->base.options.palette_index < palette_data.num_palettes)
- palette_index = scaled_font->base.options.palette_index;
-
- FT_Palette_Select (face, palette_index, NULL);
- }
+ _cairo_ft_scaled_glyph_set_palette (scaled_font, face, NULL, NULL);
#endif
load_flags &= ~FT_LOAD_MONOCHROME;
@@ -2572,7 +2656,9 @@ _cairo_ft_scaled_glyph_init_surface (cairo_ft_scaled_font_t *scaled_font,
glyph = face->glyph;
- if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
+ if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V0 ||
+ glyph_priv->format == CAIRO_FT_GLYPH_TYPE_OUTLINE) {
+
status = _render_glyph_outline (face, &scaled_font->ft_options.base,
&surface);
} else {
@@ -2584,10 +2670,11 @@ _cairo_ft_scaled_glyph_init_surface (cairo_ft_scaled_font_t *scaled_font,
if (unlikely (status))
cairo_surface_destroy (&surface->base);
}
- if (unlikely (status))
- return status;
}
+ if (unlikely (status))
+ return status;
+
if (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) {
/* We tried loading a color glyph and can now check if we got
* a color glyph and set scaled_glyph->color_glyph
@@ -2598,7 +2685,7 @@ _cairo_ft_scaled_glyph_init_surface (cairo_ft_scaled_font_t *scaled_font,
_cairo_scaled_glyph_set_color_surface (scaled_glyph,
&scaled_font->base,
surface,
- uses_foreground_color);
+ uses_foreground_color ? foreground_color : NULL);
scaled_glyph->color_glyph = TRUE;
} else {
@@ -2621,22 +2708,712 @@ _cairo_ft_scaled_glyph_init_surface (cairo_ft_scaled_font_t *scaled_font,
}
static cairo_int_status_t
+_cairo_ft_scaled_glyph_init_record_colr_v0_glyph (cairo_ft_scaled_font_t *scaled_font,
+ cairo_scaled_glyph_t *scaled_glyph,
+ FT_Face face,
+ cairo_bool_t vertical_layout,
+ int load_flags)
+{
+#ifdef HAVE_FT_PALETTE_SELECT
+ cairo_surface_t *recording_surface;
+ cairo_t *cr;
+ cairo_status_t status;
+ FT_Color *palette;
+ unsigned int num_palette_entries;
+ FT_LayerIterator iterator;
+ FT_UInt layer_glyph_index;
+ FT_UInt layer_color_index;
+ cairo_path_fixed_t *path_fixed;
+ cairo_path_t *path;
+
+ _cairo_ft_scaled_glyph_set_palette (scaled_font, face, &num_palette_entries, &palette);
+
+ load_flags &= ~FT_LOAD_MONOCHROME;
+ /* clear load target mode */
+ load_flags &= ~(FT_LOAD_TARGET_(FT_LOAD_TARGET_MODE(load_flags)));
+ load_flags |= FT_LOAD_TARGET_NORMAL;
+ load_flags |= FT_LOAD_COLOR;
+
+ recording_surface =
+ cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL);
+
+ cr = cairo_create (recording_surface);
+
+ if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) {
+ cairo_matrix_t scale;
+ scale = scaled_font->base.scale;
+ scale.x0 = scale.y0 = 0.;
+ cairo_set_matrix (cr, &scale);
+ }
+
+ iterator.p = NULL;
+ while (FT_Get_Color_Glyph_Layer(face,
+ _cairo_scaled_glyph_index (scaled_glyph),
+ &layer_glyph_index,
+ &layer_color_index,
+ &iterator))
+ {
+ cairo_pattern_t *pattern;
+ if (layer_color_index == 0xFFFF) {
+ pattern = _cairo_pattern_create_foreground_marker ();
+ } else {
+ double r = 0, g = 0, b = 0, a = 1;
+ if (layer_color_index < num_palette_entries) {
+ FT_Color *color = &palette[layer_color_index];
+ r = color->red / 255.0;
+ g = color->green/ 255.0;
+ b = color->blue / 255.0;
+ a = color->alpha / 255.0;
+ }
+ pattern = cairo_pattern_create_rgba (r, g, b, a);
+ }
+ cairo_set_source (cr, pattern);
+ cairo_pattern_destroy (pattern);
+
+ if (FT_Load_Glyph (face, layer_glyph_index, load_flags) != 0) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
+ }
+
+ status = _cairo_ft_face_decompose_glyph_outline (face, &path_fixed);
+ if (unlikely (status))
+ return status;
+
+ path = _cairo_path_create (path_fixed, cr);
+ _cairo_path_fixed_destroy (path_fixed);
+ cairo_append_path(cr, path);
+ cairo_path_destroy (path);
+ cairo_fill (cr);
+ }
+
+ cleanup:
+ cairo_destroy (cr);
+
+ if (status) {
+ cairo_surface_destroy (recording_surface);
+ return status;
+ }
+
+ _cairo_scaled_glyph_set_recording_surface (scaled_glyph,
+ &scaled_font->base,
+ recording_surface,
+ NULL);
+ return status;
+#else
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+#endif
+}
+
+static cairo_int_status_t
+_cairo_ft_scaled_glyph_init_record_colr_v1_glyph (cairo_ft_scaled_font_t *scaled_font,
+ cairo_scaled_glyph_t *scaled_glyph,
+ FT_Face face,
+ const cairo_color_t *foreground_color,
+ cairo_text_extents_t *extents)
+{
+#if HAVE_FT_COLR_V1
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_surface_t *recording_surface;
+ cairo_t *cr;
+ FT_Color *palette;
+ unsigned int num_palette_entries;
+ cairo_bool_t foreground_source_used = FALSE;
+
+ recording_surface =
+ cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL);
+
+ cairo_surface_set_device_scale (recording_surface, 1, -1);
+
+ cr = cairo_create (recording_surface);
+
+ cairo_set_font_size (cr, 1.0);
+ cairo_set_font_options (cr, &scaled_font->base.options);
+
+ extents->x_bearing = DOUBLE_FROM_26_6(face->bbox.xMin);
+ extents->y_bearing = DOUBLE_FROM_26_6(face->bbox.yMin);
+ extents->width = DOUBLE_FROM_26_6(face->bbox.xMax) - extents->x_bearing;
+ extents->height = DOUBLE_FROM_26_6(face->bbox.yMax) - extents->y_bearing;
+
+ _cairo_ft_scaled_glyph_set_palette (scaled_font, face, &num_palette_entries, &palette);
+
+ if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) {
+ cairo_pattern_t *foreground_pattern = _cairo_pattern_create_solid (foreground_color);
+ status = _cairo_render_colr_v1_glyph (face,
+ _cairo_scaled_glyph_index (scaled_glyph),
+ palette,
+ num_palette_entries,
+ cr,
+ foreground_pattern,
+ &foreground_source_used);
+ cairo_pattern_destroy (foreground_pattern);
+ if (status == CAIRO_STATUS_SUCCESS)
+ status = cairo_status (cr);
+ }
+
+ cairo_destroy (cr);
+
+ if (status) {
+ cairo_surface_destroy (recording_surface);
+ scaled_glyph->color_glyph = FALSE;
+ scaled_glyph->color_glyph_set = TRUE;
+ return status;
+ }
+
+ _cairo_scaled_glyph_set_recording_surface (scaled_glyph,
+ &scaled_font->base,
+ recording_surface,
+ foreground_source_used ? foreground_color : NULL);
+
+ scaled_glyph->color_glyph = TRUE;
+ scaled_glyph->color_glyph_set = TRUE;
+
+ /* get metrics */
+
+ /* Copied from cairo-user-font.c */
+ cairo_matrix_t extent_scale;
+ double extent_x_scale;
+ double extent_y_scale;
+ double snap_x_scale;
+ double snap_y_scale;
+ double fixed_scale, x_scale, y_scale;
+
+ extent_scale = scaled_font->base.scale_inverse;
+ snap_x_scale = 1.0;
+ snap_y_scale = 1.0;
+ status = _cairo_matrix_compute_basis_scale_factors (&extent_scale,
+ &x_scale, &y_scale,
+ 1);
+ if (status == CAIRO_STATUS_SUCCESS) {
+ if (x_scale == 0)
+ x_scale = 1;
+ if (y_scale == 0)
+ y_scale = 1;
+
+ snap_x_scale = x_scale;
+ snap_y_scale = y_scale;
+
+ /* since glyphs are pretty much 1.0x1.0, we can reduce error by
+ * scaling to a larger square. say, 1024.x1024. */
+ fixed_scale = 1024;
+ x_scale /= fixed_scale;
+ y_scale /= fixed_scale;
+
+ cairo_matrix_scale (&extent_scale, 1.0 / x_scale, 1.0 / y_scale);
+
+ extent_x_scale = x_scale;
+ extent_y_scale = y_scale;
+ }
+
+ {
+ /* compute width / height */
+ cairo_box_t bbox;
+ double x1, y1, x2, y2;
+ double x_scale, y_scale;
+
+ /* Compute extents.x/y/width/height from recording_surface,
+ * in font space.
+ */
+ status = _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface,
+ &bbox,
+ &extent_scale);
+ if (unlikely (status))
+ return status;
+
+ _cairo_box_to_doubles (&bbox, &x1, &y1, &x2, &y2);
+
+ x_scale = extent_x_scale;
+ y_scale = extent_y_scale;
+ extents->x_bearing = x1 * x_scale;
+ extents->y_bearing = y1 * y_scale;
+ extents->width = (x2 - x1) * x_scale;
+ extents->height = (y2 - y1) * y_scale;
+ }
+
+ if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) {
+ extents->x_advance = _cairo_lround (extents->x_advance / snap_x_scale) * snap_x_scale;
+ extents->y_advance = _cairo_lround (extents->y_advance / snap_y_scale) * snap_y_scale;
+ }
+
+ return status;
+#else
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+#endif
+}
+
+static cairo_int_status_t
+_cairo_ft_scaled_glyph_init_record_svg_glyph (cairo_ft_scaled_font_t *scaled_font,
+ cairo_scaled_glyph_t *scaled_glyph,
+ FT_Face face,
+ const cairo_color_t *foreground_color,
+ cairo_text_extents_t *extents)
+{
+#if HAVE_FT_SVG_DOCUMENT
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_surface_t *recording_surface;
+ cairo_t *cr;
+ FT_SVG_Document svg_doc = face->glyph->other;
+ char *svg_document;
+ FT_Color *palette;
+ unsigned int num_palette_entries;
+ cairo_bool_t foreground_source_used = FALSE;
+
+ /* Create NULL terminated SVG document */
+ svg_document = _cairo_strndup ((const char*)svg_doc->svg_document, svg_doc->svg_document_length);
+
+ recording_surface =
+ cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL);
+
+ cr = cairo_create (recording_surface);
+
+ if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) {
+ cairo_matrix_t scale;
+ scale = scaled_font->base.scale;
+ scale.x0 = scale.y0 = 0.;
+ cairo_set_matrix (cr, &scale);
+ }
+
+ cairo_set_font_size (cr, 1.0);
+ cairo_set_font_options (cr, &scaled_font->base.options);
+
+ extents->x_bearing = DOUBLE_FROM_26_6(face->bbox.xMin);
+ extents->y_bearing = DOUBLE_FROM_26_6(face->bbox.yMin);
+ extents->width = DOUBLE_FROM_26_6(face->bbox.xMax) - extents->x_bearing;
+ extents->height = DOUBLE_FROM_26_6(face->bbox.yMax) - extents->y_bearing;
+
+ _cairo_ft_scaled_glyph_set_palette (scaled_font, face, &num_palette_entries, &palette);
+
+ if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) {
+ cairo_pattern_t *foreground_pattern = _cairo_pattern_create_solid (foreground_color);
+ status = _cairo_render_svg_glyph (svg_document,
+ svg_doc->start_glyph_id,
+ svg_doc->end_glyph_id,
+ _cairo_scaled_glyph_index(scaled_glyph),
+ svg_doc->units_per_EM,
+ palette,
+ num_palette_entries,
+ cr,
+ foreground_pattern,
+ &foreground_source_used);
+ cairo_pattern_destroy (foreground_pattern);
+ if (status == CAIRO_STATUS_SUCCESS)
+ status = cairo_status (cr);
+ }
+
+ cairo_destroy (cr);
+ free (svg_document);
+
+ if (status) {
+ cairo_surface_destroy (recording_surface);
+ scaled_glyph->color_glyph = FALSE;
+ scaled_glyph->color_glyph_set = TRUE;
+ return status;
+ }
+
+ _cairo_scaled_glyph_set_recording_surface (scaled_glyph,
+ &scaled_font->base,
+ recording_surface,
+ foreground_source_used ? foreground_color : NULL);
+
+ scaled_glyph->color_glyph = TRUE;
+ scaled_glyph->color_glyph_set = TRUE;
+
+ /* get metrics */
+
+ /* Copied from cairo-user-font.c */
+ cairo_matrix_t extent_scale;
+ double extent_x_scale;
+ double extent_y_scale;
+ double snap_x_scale;
+ double snap_y_scale;
+ double fixed_scale, x_scale, y_scale;
+
+ extent_scale = scaled_font->base.scale_inverse;
+ snap_x_scale = 1.0;
+ snap_y_scale = 1.0;
+ status = _cairo_matrix_compute_basis_scale_factors (&extent_scale,
+ &x_scale, &y_scale,
+ 1);
+ if (status == CAIRO_STATUS_SUCCESS) {
+ if (x_scale == 0)
+ x_scale = 1;
+ if (y_scale == 0)
+ y_scale = 1;
+
+ snap_x_scale = x_scale;
+ snap_y_scale = y_scale;
+
+ /* since glyphs are pretty much 1.0x1.0, we can reduce error by
+ * scaling to a larger square. say, 1024.x1024. */
+ fixed_scale = 1024;
+ x_scale /= fixed_scale;
+ y_scale /= fixed_scale;
+
+ cairo_matrix_scale (&extent_scale, 1.0 / x_scale, 1.0 / y_scale);
+
+ extent_x_scale = x_scale;
+ extent_y_scale = y_scale;
+ }
+
+ {
+ /* compute width / height */
+ cairo_box_t bbox;
+ double x1, y1, x2, y2;
+ double x_scale, y_scale;
+
+ /* Compute extents.x/y/width/height from recording_surface,
+ * in font space.
+ */
+ status = _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface,
+ &bbox,
+ &extent_scale);
+ if (unlikely (status))
+ return status;
+
+ _cairo_box_to_doubles (&bbox, &x1, &y1, &x2, &y2);
+
+ x_scale = extent_x_scale;
+ y_scale = extent_y_scale;
+ extents->x_bearing = x1 * x_scale;
+ extents->y_bearing = y1 * y_scale;
+ extents->width = (x2 - x1) * x_scale;
+ extents->height = (y2 - y1) * y_scale;
+ }
+
+ if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) {
+ extents->x_advance = _cairo_lround (extents->x_advance / snap_x_scale) * snap_x_scale;
+ extents->y_advance = _cairo_lround (extents->y_advance / snap_y_scale) * snap_y_scale;
+ }
+
+ return status;
+#else
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+#endif
+}
+
+static cairo_int_status_t
+_cairo_ft_scaled_glyph_init_surface_for_recording_surface (cairo_ft_scaled_font_t *scaled_font,
+ cairo_scaled_glyph_t *scaled_glyph,
+ const cairo_color_t *foreground_color)
+{
+ cairo_surface_t *surface;
+ int width, height;
+ cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_bool_t foreground_used;
+
+ width = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x) -
+ _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x);
+ height = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y) -
+ _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+
+ cairo_surface_set_device_offset (surface,
+ - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x),
+ - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y));
+
+ status = _cairo_recording_surface_replay_with_foreground_color (scaled_glyph->recording_surface,
+ surface,
+ foreground_color,
+ &foreground_used);
+ if (unlikely (status)) {
+ cairo_surface_destroy(surface);
+ return status;
+ }
+
+ _cairo_scaled_glyph_set_color_surface (scaled_glyph,
+ &scaled_font->base,
+ (cairo_image_surface_t *)surface,
+ foreground_used ? foreground_color : NULL);
+ surface = NULL;
+
+ if (surface)
+ cairo_surface_destroy (surface);
+
+ return status;
+}
+
+static void
+_cairo_ft_scaled_glyph_get_metrics (cairo_ft_scaled_font_t *scaled_font,
+ FT_Face face,
+ cairo_bool_t vertical_layout,
+ int load_flags,
+ cairo_text_extents_t *fs_metrics)
+{
+ FT_Glyph_Metrics *metrics;
+ double x_factor, y_factor;
+ cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled;
+ cairo_bool_t hint_metrics = scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF;
+ FT_GlyphSlot glyph = face->glyph;
+
+ /*
+ * Compute font-space metrics
+ */
+ metrics = &glyph->metrics;
+
+ if (unscaled->x_scale == 0)
+ x_factor = 0;
+ else
+ x_factor = 1 / unscaled->x_scale;
+
+ if (unscaled->y_scale == 0)
+ y_factor = 0;
+ else
+ y_factor = 1 / unscaled->y_scale;
+
+ /*
+ * Note: Y coordinates of the horizontal bearing need to be negated.
+ *
+ * Scale metrics back to glyph space from the scaled glyph space returned
+ * by FreeType
+ *
+ * If we want hinted metrics but aren't asking for hinted glyphs from
+ * FreeType, then we need to do the metric hinting ourselves.
+ */
+
+ if (hint_metrics && (load_flags & FT_LOAD_NO_HINTING))
+ {
+ FT_Pos x1, x2;
+ FT_Pos y1, y2;
+ FT_Pos advance;
+
+ if (!vertical_layout) {
+ x1 = (metrics->horiBearingX) & -64;
+ x2 = (metrics->horiBearingX + metrics->width + 63) & -64;
+ y1 = (-metrics->horiBearingY) & -64;
+ y2 = (-metrics->horiBearingY + metrics->height + 63) & -64;
+
+ advance = ((metrics->horiAdvance + 32) & -64);
+
+ fs_metrics->x_bearing = DOUBLE_FROM_26_6 (x1) * x_factor;
+ fs_metrics->y_bearing = DOUBLE_FROM_26_6 (y1) * y_factor;
+
+ fs_metrics->width = DOUBLE_FROM_26_6 (x2 - x1) * x_factor;
+ fs_metrics->height = DOUBLE_FROM_26_6 (y2 - y1) * y_factor;
+
+ fs_metrics->x_advance = DOUBLE_FROM_26_6 (advance) * x_factor;
+ fs_metrics->y_advance = 0;
+ } else {
+ x1 = (metrics->vertBearingX) & -64;
+ x2 = (metrics->vertBearingX + metrics->width + 63) & -64;
+ y1 = (metrics->vertBearingY) & -64;
+ y2 = (metrics->vertBearingY + metrics->height + 63) & -64;
+
+ advance = ((metrics->vertAdvance + 32) & -64);
+
+ fs_metrics->x_bearing = DOUBLE_FROM_26_6 (x1) * x_factor;
+ fs_metrics->y_bearing = DOUBLE_FROM_26_6 (y1) * y_factor;
+
+ fs_metrics->width = DOUBLE_FROM_26_6 (x2 - x1) * x_factor;
+ fs_metrics->height = DOUBLE_FROM_26_6 (y2 - y1) * y_factor;
+
+ fs_metrics->x_advance = 0;
+ fs_metrics->y_advance = DOUBLE_FROM_26_6 (advance) * y_factor;
+ }
+ } else {
+ fs_metrics->width = DOUBLE_FROM_26_6 (metrics->width) * x_factor;
+ fs_metrics->height = DOUBLE_FROM_26_6 (metrics->height) * y_factor;
+
+ if (!vertical_layout) {
+ fs_metrics->x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) * x_factor;
+ fs_metrics->y_bearing = DOUBLE_FROM_26_6 (-metrics->horiBearingY) * y_factor;
+
+ if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE)
+ fs_metrics->x_advance = DOUBLE_FROM_26_6 (metrics->horiAdvance) * x_factor;
+ else
+ fs_metrics->x_advance = DOUBLE_FROM_16_16 (glyph->linearHoriAdvance) * x_factor;
+ fs_metrics->y_advance = 0 * y_factor;
+ } else {
+ fs_metrics->x_bearing = DOUBLE_FROM_26_6 (metrics->vertBearingX) * x_factor;
+ fs_metrics->y_bearing = DOUBLE_FROM_26_6 (metrics->vertBearingY) * y_factor;
+
+ fs_metrics->x_advance = 0 * x_factor;
+ if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE)
+ fs_metrics->y_advance = DOUBLE_FROM_26_6 (metrics->vertAdvance) * y_factor;
+ else
+ fs_metrics->y_advance = DOUBLE_FROM_16_16 (glyph->linearVertAdvance) * y_factor;
+ }
+ }
+}
+
+static cairo_bool_t
+_cairo_ft_scaled_glyph_is_colr_v0 (cairo_ft_scaled_font_t *scaled_font,
+ cairo_scaled_glyph_t *scaled_glyph,
+ FT_Face face)
+{
+#ifdef HAVE_FT_PALETTE_SELECT
+ FT_LayerIterator iterator;
+ FT_UInt layer_glyph_index;
+ FT_UInt layer_color_index;
+
+ iterator.p = NULL;
+ if (FT_Get_Color_Glyph_Layer(face,
+ _cairo_scaled_glyph_index (scaled_glyph),
+ &layer_glyph_index,
+ &layer_color_index,
+ &iterator) == 1)
+ {
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
+static cairo_bool_t
+_cairo_ft_scaled_glyph_is_colr_v1 (cairo_ft_scaled_font_t *scaled_font,
+ cairo_scaled_glyph_t *scaled_glyph,
+ FT_Face face)
+{
+#if HAVE_FT_COLR_V1
+ FT_OpaquePaint paint = { NULL, 0 };
+
+ if (FT_Get_Color_Glyph_Paint (face,
+ _cairo_scaled_glyph_index (scaled_glyph),
+ FT_COLOR_INCLUDE_ROOT_TRANSFORM,
+ &paint) == 1)
+ {
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
+static const int ft_glyph_private_key;
+
+static cairo_int_status_t
+_cairo_ft_scaled_glyph_init_metrics (cairo_ft_scaled_font_t *scaled_font,
+ cairo_scaled_glyph_t *scaled_glyph,
+ FT_Face face,
+ cairo_bool_t vertical_layout,
+ int load_flags,
+ const cairo_color_t *foreground_color)
+{
+ cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
+ cairo_text_extents_t fs_metrics;
+ cairo_ft_glyph_private_t *glyph_priv;
+
+ cairo_bool_t hint_metrics = scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF;
+
+ /* _cairo_ft_scaled_glyph_init_metrics() is called once the first
+ * time a cairo_scaled_glyph_t is created. We first allocate the
+ * cairo_ft_glyph_private_t struct and determine the glyph type.
+ */
+
+ glyph_priv = _cairo_malloc (sizeof (*glyph_priv));
+ if (unlikely (glyph_priv == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ _cairo_scaled_glyph_attach_private (scaled_glyph, &glyph_priv->base,
+ &ft_glyph_private_key,
+ _cairo_ft_glyph_fini);
+ scaled_glyph->dev_private = glyph_priv;
+
+ /* We need to load color to determine if this is a color format. */
+ int color_flag = 0;
+
+#ifdef FT_LOAD_COLOR
+ if (scaled_font->unscaled->have_color && scaled_font->base.options.color_mode != CAIRO_COLOR_MODE_NO_COLOR)
+ color_flag = FT_LOAD_COLOR;
+#endif
+ status = _cairo_ft_scaled_glyph_load_glyph (scaled_font,
+ scaled_glyph,
+ face,
+ load_flags | color_flag,
+ !hint_metrics,
+ vertical_layout);
+ if (unlikely (status))
+ return status;
+
+ cairo_bool_t is_svg_format = FALSE;
+#if HAVE_FT_SVG_DOCUMENT
+ if (face->glyph->format == FT_GLYPH_FORMAT_SVG)
+ is_svg_format = TRUE;
+#endif
+
+ if (is_svg_format) {
+ glyph_priv->format = CAIRO_FT_GLYPH_TYPE_SVG;
+ } else if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
+ glyph_priv->format = CAIRO_FT_GLYPH_TYPE_OUTLINE;
+ if (color_flag) {
+ if (_cairo_ft_scaled_glyph_is_colr_v1 (scaled_font, scaled_glyph, face))
+ glyph_priv->format = CAIRO_FT_GLYPH_TYPE_COLR_V1;
+ else if (_cairo_ft_scaled_glyph_is_colr_v0 (scaled_font, scaled_glyph, face))
+ glyph_priv->format = CAIRO_FT_GLYPH_TYPE_COLR_V0;
+ }
+ } else {
+ /* For anything else we let FreeType render a bitmap. */
+ glyph_priv->format = CAIRO_FT_GLYPH_TYPE_BITMAP;
+ }
+
+ _cairo_ft_scaled_glyph_get_metrics (scaled_font,
+ face,
+ vertical_layout,
+ load_flags,
+ &fs_metrics);
+
+
+ /* SVG and COLRv1 glyphs require the bounding box to be obtained
+ * from the ink extents of the rendering. We need to render glyph
+ * to a recording surface to obtain these extents. But we also
+ * need the advance from _cairo_ft_scaled_glyph_get_metrics()
+ * before calling this function.
+ */
+
+ if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_SVG) {
+ status = (cairo_int_status_t)_cairo_ft_scaled_glyph_init_record_svg_glyph (scaled_font,
+ scaled_glyph,
+ face,
+ foreground_color,
+ &fs_metrics);
+ if (unlikely (status))
+ return status;
+ }
+
+ if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V1) {
+ if (!hint_metrics) {
+ status = _cairo_ft_scaled_glyph_load_glyph (scaled_font,
+ scaled_glyph,
+ face,
+ load_flags | color_flag,
+ FALSE,
+ vertical_layout);
+ if (unlikely (status))
+ return status;
+ }
+
+ status = (cairo_int_status_t)_cairo_ft_scaled_glyph_init_record_colr_v1_glyph (scaled_font,
+ scaled_glyph,
+ face,
+ foreground_color,
+ &fs_metrics);
+ if (unlikely (status))
+ return status;
+ }
+
+ _cairo_scaled_glyph_set_metrics (scaled_glyph,
+ &scaled_font->base,
+ &fs_metrics);
+
+ return status;
+}
+
+static cairo_int_status_t
_cairo_ft_scaled_glyph_init (void *abstract_font,
cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_glyph_info_t info,
const cairo_color_t *foreground_color)
{
- cairo_text_extents_t fs_metrics;
cairo_ft_scaled_font_t *scaled_font = abstract_font;
cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled;
- FT_GlyphSlot glyph;
FT_Face face;
int load_flags = scaled_font->ft_options.load_flags;
- FT_Glyph_Metrics *metrics;
- double x_factor, y_factor;
cairo_bool_t vertical_layout = FALSE;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
- cairo_bool_t scaled_glyph_loaded = FALSE;
+ cairo_ft_glyph_private_t *glyph_priv;
+ int color_flag = 0;
+
+#ifdef FT_LOAD_COLOR
+ color_flag = FT_LOAD_COLOR;
+#endif
face = _cairo_ft_unscaled_font_lock_face (unscaled);
if (!face)
@@ -2660,134 +3437,77 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
vertical_layout = TRUE;
}
+ /* Metrics will always be requested when a scaled glyph is created */
if (info & CAIRO_SCALED_GLYPH_INFO_METRICS) {
-
- cairo_bool_t hint_metrics = scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF;
-
- /* The font metrics for color glyphs should be the same as the
- * outline glyphs. But just in case there aren't, request the
- * color or outline metrics based on the font option and if
- * the font has color.
- */
- int color_flag = 0;
-#ifdef FT_LOAD_COLOR
- if (unscaled->have_color && scaled_font->base.options.color_mode != CAIRO_COLOR_MODE_NO_COLOR)
- color_flag = FT_LOAD_COLOR;
-#endif
- status = _cairo_ft_scaled_glyph_load_glyph (scaled_font,
- scaled_glyph,
- face,
- load_flags | color_flag,
- !hint_metrics,
- vertical_layout);
+ status = _cairo_ft_scaled_glyph_init_metrics (scaled_font,
+ scaled_glyph,
+ face,
+ vertical_layout,
+ load_flags,
+ foreground_color);
if (unlikely (status))
goto FAIL;
+ }
- glyph = face->glyph;
- scaled_glyph_loaded = hint_metrics;
-
- /*
- * Compute font-space metrics
- */
- metrics = &glyph->metrics;
-
- if (unscaled->x_scale == 0)
- x_factor = 0;
- else
- x_factor = 1 / unscaled->x_scale;
-
- if (unscaled->y_scale == 0)
- y_factor = 0;
- else
- y_factor = 1 / unscaled->y_scale;
-
- /*
- * Note: Y coordinates of the horizontal bearing need to be negated.
- *
- * Scale metrics back to glyph space from the scaled glyph space returned
- * by FreeType
- *
- * If we want hinted metrics but aren't asking for hinted glyphs from
- * FreeType, then we need to do the metric hinting ourselves.
- */
+ /* scaled_glyph->dev_private is intialized by _cairo_ft_scaled_glyph_init_metrics() */
+ glyph_priv = scaled_glyph->dev_private;
+ assert (glyph_priv != NULL);
- if (hint_metrics && (load_flags & FT_LOAD_NO_HINTING))
+ if (info & CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_SVG ||
+ glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V0 ||
+ glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V1)
{
- FT_Pos x1, x2;
- FT_Pos y1, y2;
- FT_Pos advance;
-
- if (!vertical_layout) {
- x1 = (metrics->horiBearingX) & -64;
- x2 = (metrics->horiBearingX + metrics->width + 63) & -64;
- y1 = (-metrics->horiBearingY) & -64;
- y2 = (-metrics->horiBearingY + metrics->height + 63) & -64;
-
- advance = ((metrics->horiAdvance + 32) & -64);
-
- fs_metrics.x_bearing = DOUBLE_FROM_26_6 (x1) * x_factor;
- fs_metrics.y_bearing = DOUBLE_FROM_26_6 (y1) * y_factor;
-
- fs_metrics.width = DOUBLE_FROM_26_6 (x2 - x1) * x_factor;
- fs_metrics.height = DOUBLE_FROM_26_6 (y2 - y1) * y_factor;
-
- fs_metrics.x_advance = DOUBLE_FROM_26_6 (advance) * x_factor;
- fs_metrics.y_advance = 0;
- } else {
- x1 = (metrics->vertBearingX) & -64;
- x2 = (metrics->vertBearingX + metrics->width + 63) & -64;
- y1 = (metrics->vertBearingY) & -64;
- y2 = (metrics->vertBearingY + metrics->height + 63) & -64;
-
- advance = ((metrics->vertAdvance + 32) & -64);
-
- fs_metrics.x_bearing = DOUBLE_FROM_26_6 (x1) * x_factor;
- fs_metrics.y_bearing = DOUBLE_FROM_26_6 (y1) * y_factor;
-
- fs_metrics.width = DOUBLE_FROM_26_6 (x2 - x1) * x_factor;
- fs_metrics.height = DOUBLE_FROM_26_6 (y2 - y1) * y_factor;
-
- fs_metrics.x_advance = 0;
- fs_metrics.y_advance = DOUBLE_FROM_26_6 (advance) * y_factor;
- }
- } else {
- fs_metrics.width = DOUBLE_FROM_26_6 (metrics->width) * x_factor;
- fs_metrics.height = DOUBLE_FROM_26_6 (metrics->height) * y_factor;
-
- if (!vertical_layout) {
- fs_metrics.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) * x_factor;
- fs_metrics.y_bearing = DOUBLE_FROM_26_6 (-metrics->horiBearingY) * y_factor;
-
- if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE)
- fs_metrics.x_advance = DOUBLE_FROM_26_6 (metrics->horiAdvance) * x_factor;
- else
- fs_metrics.x_advance = DOUBLE_FROM_16_16 (glyph->linearHoriAdvance) * x_factor;
- fs_metrics.y_advance = 0 * y_factor;
- } else {
- fs_metrics.x_bearing = DOUBLE_FROM_26_6 (metrics->vertBearingX) * x_factor;
- fs_metrics.y_bearing = DOUBLE_FROM_26_6 (metrics->vertBearingY) * y_factor;
+ status = _cairo_ft_scaled_glyph_load_glyph (scaled_font,
+ scaled_glyph,
+ face,
+ load_flags | color_flag,
+ FALSE,
+ vertical_layout);
+ if (unlikely (status))
+ goto FAIL;
- fs_metrics.x_advance = 0 * x_factor;
- if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE)
- fs_metrics.y_advance = DOUBLE_FROM_26_6 (metrics->vertAdvance) * y_factor;
- else
- fs_metrics.y_advance = DOUBLE_FROM_16_16 (glyph->linearVertAdvance) * y_factor;
+ if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_SVG) {
+ status = _cairo_ft_scaled_glyph_init_record_svg_glyph (scaled_font,
+ scaled_glyph,
+ face,
+ foreground_color,
+ &scaled_glyph->fs_metrics);
+ } else if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V1) {
+ status = _cairo_ft_scaled_glyph_init_record_colr_v1_glyph (scaled_font,
+ scaled_glyph,
+ face,
+ foreground_color,
+ &scaled_glyph->fs_metrics);
+ } else if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V0) {
+ status = _cairo_ft_scaled_glyph_init_record_colr_v0_glyph (scaled_font,
+ scaled_glyph,
+ face,
+ vertical_layout,
+ load_flags);
}
- }
-
- _cairo_scaled_glyph_set_metrics (scaled_glyph,
- &scaled_font->base,
- &fs_metrics);
+ }
+ if (status)
+ goto FAIL;
}
if (info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) {
- status = _cairo_ft_scaled_glyph_init_surface (scaled_font,
- scaled_glyph,
- CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE,
- face,
- foreground_color,
- vertical_layout,
- load_flags);
+ if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_SVG ||
+ glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V1)
+ {
+ status = _cairo_ft_scaled_glyph_init_surface_for_recording_surface (scaled_font,
+ scaled_glyph,
+ foreground_color);
+ } else {
+ status = _cairo_ft_scaled_glyph_init_surface (scaled_font,
+ scaled_glyph,
+ CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE,
+ face,
+ foreground_color,
+ vertical_layout,
+ load_flags);
+ }
if (unlikely (status))
goto FAIL;
}
@@ -2807,31 +3527,18 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
if (info & CAIRO_SCALED_GLYPH_INFO_PATH) {
cairo_path_fixed_t *path = NULL; /* hide compiler warning */
- /*
- * A kludge -- the above code will trash the outline,
- * so reload it. This will probably never occur though
- */
- if ((info & (CAIRO_SCALED_GLYPH_INFO_SURFACE | CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) != 0) {
- scaled_glyph_loaded = FALSE;
- load_flags |= FT_LOAD_NO_BITMAP;
- }
-
- if (!scaled_glyph_loaded) {
- status = _cairo_ft_scaled_glyph_load_glyph (scaled_font,
- scaled_glyph,
- face,
- load_flags,
- FALSE,
- vertical_layout);
- if (unlikely (status))
- goto FAIL;
-
- glyph = face->glyph;
- }
+ /* Load non-color glyph */
+ status = _cairo_ft_scaled_glyph_load_glyph (scaled_font,
+ scaled_glyph,
+ face,
+ load_flags,
+ FALSE,
+ vertical_layout);
+ if (unlikely (status))
+ goto FAIL;
- if (glyph->format == FT_GLYPH_FORMAT_OUTLINE)
- status = _decompose_glyph_outline (face, &scaled_font->ft_options.base,
- &path);
+ if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)
+ status = _cairo_ft_face_decompose_glyph_outline (face, &path);
else
status = CAIRO_INT_STATUS_UNSUPPORTED;
@@ -2971,7 +3678,7 @@ _cairo_ft_is_synthetic (void *abstract_font,
error = FT_Get_MM_Var (face, &mm_var);
if (error) {
- status = _cairo_error (_ft_to_cairo_error (error));
+ status = _cairo_error (_cairo_ft_to_cairo_error (error));
goto cleanup;
}
diff --git a/src/cairo-ft-private.h b/src/cairo-ft-private.h
index 0dc811472..836f7e523 100644
--- a/src/cairo-ft-private.h
+++ b/src/cairo-ft-private.h
@@ -1,3 +1,4 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
@@ -55,6 +56,41 @@ _cairo_scaled_font_is_ft (cairo_scaled_font_t *scaled_font);
cairo_private unsigned int
_cairo_ft_scaled_font_get_load_flags (cairo_scaled_font_t *scaled_font);
+cairo_private cairo_status_t
+_cairo_ft_to_cairo_error (FT_Error error);
+
+cairo_private cairo_status_t
+_cairo_ft_face_decompose_glyph_outline (FT_Face face,
+ cairo_path_fixed_t **pathp);
+
+#if HAVE_FT_SVG_DOCUMENT
+
+typedef struct FT_Color_ FT_Color;
+
+cairo_private cairo_status_t
+_cairo_render_svg_glyph (const char *svg_document,
+ unsigned long first_glyph,
+ unsigned long last_glyph,
+ unsigned long glyph,
+ double units_per_em,
+ FT_Color *palette,
+ int num_palette_entries,
+ cairo_t *cr,
+ cairo_pattern_t *foreground_source,
+ cairo_bool_t *foreground_source_used);
+#endif
+
+#if HAVE_FT_COLR_V1
+cairo_private cairo_status_t
+_cairo_render_colr_v1_glyph (FT_Face face,
+ unsigned long glyph,
+ FT_Color *palette,
+ int num_palette_entries,
+ cairo_t *cr,
+ cairo_pattern_t *foreground_source,
+ cairo_bool_t *foreground_source_used);
+#endif
+
CAIRO_END_DECLS
#endif /* CAIRO_HAS_FT_FONT */
diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
deleted file mode 100644
index 5477ef0d8..000000000
--- a/src/cairo-gl-composite.c
+++ /dev/null
@@ -1,1364 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 Eric Anholt
- * Copyright © 2009 Chris Wilson
- * Copyright © 2005,2010 Red Hat, Inc
- * Copyright © 2011 Linaro Limited
- * Copyright © 2011 Samsung Electronics
- *
- * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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):
- * Benjamin Otte <otte@gnome.org>
- * Carl Worth <cworth@cworth.org>
- * Chris Wilson <chris@chris-wilson.co.uk>
- * Eric Anholt <eric@anholt.net>
- * Alexandros Frantzis <alexandros.frantzis@linaro.org>
- * Henry Song <hsong@sisa.samsung.com>
- * Martin Robinson <mrobinson@igalia.com>
- */
-
-#include "cairoint.h"
-
-#include "cairo-gl-private.h"
-
-#include "cairo-composite-rectangles-private.h"
-#include "cairo-clip-private.h"
-#include "cairo-error-private.h"
-#include "cairo-image-surface-private.h"
-
-/* FIXME: Copy of same routine in cairo-gl-msaa-compositor.c */
-static cairo_int_status_t
-_draw_int_rect (cairo_gl_context_t *ctx,
- cairo_gl_composite_t *setup,
- cairo_rectangle_int_t *rect)
-{
- cairo_box_t box;
- cairo_point_t quad[4];
-
- _cairo_box_from_rectangle (&box, rect);
- quad[0].x = box.p1.x;
- quad[0].y = box.p1.y;
- quad[1].x = box.p1.x;
- quad[1].y = box.p2.y;
- quad[2].x = box.p2.x;
- quad[2].y = box.p2.y;
- quad[3].x = box.p2.x;
- quad[3].y = box.p1.y;
-
- return _cairo_gl_composite_emit_quad_as_tristrip (ctx, setup, quad);
-}
-
-static cairo_int_status_t
-_blit_texture_to_renderbuffer (cairo_gl_surface_t *surface)
-{
- cairo_gl_context_t *ctx = NULL;
- cairo_gl_composite_t setup;
- cairo_surface_pattern_t pattern;
- cairo_rectangle_int_t extents;
- cairo_int_status_t status;
-
- /* FIXME: This only permits blit when glesv3 is enabled. But note that
- glesv2 with the ANGLE extension should also be able to support this feature,
- so once the ANGLE support code is in place this check can be relaxed. */
- if (((cairo_gl_context_t *)surface->base.device)->gl_flavor != CAIRO_GL_FLAVOR_ES3)
- return CAIRO_INT_STATUS_SUCCESS;
-
- if (! surface->content_in_texture)
- return CAIRO_INT_STATUS_SUCCESS;
-
- memset (&setup, 0, sizeof (cairo_gl_composite_t));
-
- status = _cairo_gl_composite_set_operator (&setup,
- CAIRO_OPERATOR_SOURCE,
- FALSE);
-
- if (status)
- return status;
-
- setup.dst = surface;
- setup.clip_region = surface->clip_region;
-
- _cairo_pattern_init_for_surface (&pattern, &surface->base);
- status = _cairo_gl_composite_set_source (&setup, &pattern.base,
- NULL, NULL, FALSE);
- _cairo_pattern_fini (&pattern.base);
-
- if (unlikely (status))
- goto FAIL;
-
- _cairo_gl_composite_set_multisample (&setup);
-
- status = _cairo_gl_composite_begin (&setup, &ctx);
-
- if (unlikely (status))
- goto FAIL;
-
- extents.x = extents.y = 0;
- extents.width = surface->width;
- extents.height = surface->height;
-
- status = _draw_int_rect (ctx, &setup, &extents);
-
- if (status == CAIRO_INT_STATUS_SUCCESS)
- surface->content_in_texture = FALSE;
-
-FAIL:
- _cairo_gl_composite_fini (&setup);
-
- if (ctx) {
- _cairo_gl_composite_flush (ctx);
- status = _cairo_gl_context_release (ctx, status);
- }
-
- return status;
-}
-
-cairo_int_status_t
-_cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
- const cairo_pattern_t *pattern,
- const cairo_rectangle_int_t *sample,
- const cairo_rectangle_int_t *extents,
- cairo_bool_t use_texgen)
-{
- _cairo_gl_operand_destroy (&setup->src);
- return _cairo_gl_operand_init (&setup->src, pattern, setup->dst,
- sample, extents, use_texgen);
-}
-
-void
-_cairo_gl_composite_set_source_operand (cairo_gl_composite_t *setup,
- const cairo_gl_operand_t *source)
-{
- cairo_int_status_t status;
-
- _cairo_gl_operand_destroy (&setup->src);
- _cairo_gl_operand_copy (&setup->src, source);
-
- if (source->type == CAIRO_GL_OPERAND_TEXTURE)
- status = _cairo_gl_surface_resolve_multisampling (source->texture.surface);
-}
-
-void
-_cairo_gl_composite_set_solid_source (cairo_gl_composite_t *setup,
- const cairo_color_t *color)
-{
- _cairo_gl_operand_destroy (&setup->src);
- _cairo_gl_solid_operand_init (&setup->src, color);
-}
-
-cairo_int_status_t
-_cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
- const cairo_pattern_t *pattern,
- const cairo_rectangle_int_t *sample,
- const cairo_rectangle_int_t *extents,
- cairo_bool_t use_texgen)
-{
- _cairo_gl_operand_destroy (&setup->mask);
- if (pattern == NULL)
- return CAIRO_STATUS_SUCCESS;
-
- return _cairo_gl_operand_init (&setup->mask, pattern, setup->dst,
- sample, extents, use_texgen);
-}
-
-void
-_cairo_gl_composite_set_mask_operand (cairo_gl_composite_t *setup,
- const cairo_gl_operand_t *mask)
-{
- cairo_int_status_t status;
- _cairo_gl_operand_destroy (&setup->mask);
- if (mask) {
- _cairo_gl_operand_copy (&setup->mask, mask);
- if (mask->type == CAIRO_GL_OPERAND_TEXTURE)
- status = _cairo_gl_surface_resolve_multisampling (mask->texture.surface);
- }
-}
-
-void
-_cairo_gl_composite_set_spans (cairo_gl_composite_t *setup)
-{
- setup->spans = TRUE;
-}
-
-void
-_cairo_gl_composite_set_multisample (cairo_gl_composite_t *setup)
-{
- setup->multisample = TRUE;
-}
-
-void
-_cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
- cairo_region_t *clip_region)
-{
- setup->clip_region = clip_region;
-}
-
-void
-_cairo_gl_composite_set_clip (cairo_gl_composite_t *setup,
- cairo_clip_t *clip)
-{
- setup->clip = clip;
-}
-
-static void
-_cairo_gl_composite_bind_to_shader (cairo_gl_context_t *ctx,
- cairo_gl_composite_t *setup)
-{
- _cairo_gl_shader_bind_matrix4f(ctx, ctx->current_shader->mvp_location,
- ctx->modelviewprojection_matrix);
- _cairo_gl_operand_bind_to_shader (ctx, &setup->src, CAIRO_GL_TEX_SOURCE);
- _cairo_gl_operand_bind_to_shader (ctx, &setup->mask, CAIRO_GL_TEX_MASK);
-}
-
-static void
-_cairo_gl_texture_set_filter (cairo_gl_context_t *ctx,
- GLuint target,
- cairo_filter_t filter)
-{
- switch (filter) {
- case CAIRO_FILTER_FAST:
- case CAIRO_FILTER_NEAREST:
- glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- break;
- case CAIRO_FILTER_GOOD:
- case CAIRO_FILTER_BEST:
- case CAIRO_FILTER_BILINEAR:
- glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- break;
- default:
- case CAIRO_FILTER_GAUSSIAN:
- ASSERT_NOT_REACHED;
- }
-}
-
-static void
-_cairo_gl_texture_set_extend (cairo_gl_context_t *ctx,
- GLuint target,
- cairo_extend_t extend)
-{
- GLint wrap_mode;
- assert (! _cairo_gl_device_requires_power_of_two_textures (&ctx->base) ||
- (extend != CAIRO_EXTEND_REPEAT && extend != CAIRO_EXTEND_REFLECT));
-
- switch (extend) {
- case CAIRO_EXTEND_NONE:
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3 ||
- ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2)
- wrap_mode = GL_CLAMP_TO_EDGE;
- else
- wrap_mode = GL_CLAMP_TO_BORDER;
- break;
- case CAIRO_EXTEND_PAD:
- wrap_mode = GL_CLAMP_TO_EDGE;
- break;
- case CAIRO_EXTEND_REPEAT:
- if (ctx->has_npot_repeat)
- wrap_mode = GL_REPEAT;
- else
- wrap_mode = GL_CLAMP_TO_EDGE;
- break;
- case CAIRO_EXTEND_REFLECT:
- if (ctx->has_npot_repeat)
- wrap_mode = GL_MIRRORED_REPEAT;
- else
- wrap_mode = GL_CLAMP_TO_EDGE;
- break;
- default:
- wrap_mode = 0;
- }
-
- if (likely (wrap_mode)) {
- glTexParameteri (target, GL_TEXTURE_WRAP_S, wrap_mode);
- glTexParameteri (target, GL_TEXTURE_WRAP_T, wrap_mode);
- }
-}
-
-
-static void
-_cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
- cairo_gl_tex_t tex_unit,
- cairo_gl_operand_t *operand,
- unsigned int vertex_offset,
- cairo_bool_t vertex_size_changed)
-{
- cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
- cairo_bool_t needs_setup;
-
- /* XXX: we need to do setup when switching from shaders
- * to no shaders (or back) */
- needs_setup = vertex_size_changed;
- needs_setup |= _cairo_gl_operand_needs_setup (&ctx->operands[tex_unit],
- operand,
- vertex_offset);
-
- if (needs_setup) {
- _cairo_gl_composite_flush (ctx);
- _cairo_gl_context_destroy_operand (ctx, tex_unit);
- }
-
- memcpy (&ctx->operands[tex_unit], operand, sizeof (cairo_gl_operand_t));
- ctx->operands[tex_unit].vertex_offset = vertex_offset;
-
- if (! needs_setup)
- return;
-
- switch (operand->type) {
- default:
- case CAIRO_GL_OPERAND_COUNT:
- ASSERT_NOT_REACHED;
- case CAIRO_GL_OPERAND_NONE:
- break;
- /* fall through */
- case CAIRO_GL_OPERAND_CONSTANT:
- break;
- case CAIRO_GL_OPERAND_TEXTURE:
- glActiveTexture (GL_TEXTURE0 + tex_unit);
- glBindTexture (ctx->tex_target, operand->texture.tex);
- _cairo_gl_texture_set_extend (ctx, ctx->tex_target,
- operand->texture.attributes.extend);
- _cairo_gl_texture_set_filter (ctx, ctx->tex_target,
- operand->texture.attributes.filter);
-
- if (! operand->texture.texgen) {
- dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
- GL_FLOAT, GL_FALSE, ctx->vertex_size,
- ctx->vb + vertex_offset);
- dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
- }
- break;
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- glActiveTexture (GL_TEXTURE0 + tex_unit);
- glBindTexture (ctx->tex_target, operand->gradient.gradient->tex);
- _cairo_gl_texture_set_extend (ctx, ctx->tex_target, operand->gradient.extend);
- _cairo_gl_texture_set_filter (ctx, ctx->tex_target, CAIRO_FILTER_BILINEAR);
-
- if (! operand->gradient.texgen) {
- dispatch->VertexAttribPointer (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit, 2,
- GL_FLOAT, GL_FALSE, ctx->vertex_size,
- ctx->vb + vertex_offset);
- dispatch->EnableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
- }
- break;
- }
-}
-
-static void
-_cairo_gl_context_setup_spans (cairo_gl_context_t *ctx,
- cairo_bool_t spans_enabled,
- unsigned int vertex_size,
- unsigned int vertex_offset)
-{
- cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-
- if (! spans_enabled) {
- dispatch->DisableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
- ctx->spans = FALSE;
- return;
- }
-
- dispatch->VertexAttribPointer (CAIRO_GL_COLOR_ATTRIB_INDEX, 4,
- GL_UNSIGNED_BYTE, GL_TRUE, vertex_size,
- ctx->vb + vertex_offset);
- dispatch->EnableVertexAttribArray (CAIRO_GL_COLOR_ATTRIB_INDEX);
- ctx->spans = TRUE;
-}
-
-void
-_cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
- cairo_gl_tex_t tex_unit)
-{
- cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-
- if (!_cairo_gl_context_is_flushed (ctx))
- _cairo_gl_composite_flush (ctx);
-
- switch (ctx->operands[tex_unit].type) {
- default:
- case CAIRO_GL_OPERAND_COUNT:
- ASSERT_NOT_REACHED;
- case CAIRO_GL_OPERAND_NONE:
- break;
- /* fall through */
- case CAIRO_GL_OPERAND_CONSTANT:
- break;
- case CAIRO_GL_OPERAND_TEXTURE:
- dispatch->DisableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
- break;
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- dispatch->DisableVertexAttribArray (CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + tex_unit);
- break;
- }
-
- memset (&ctx->operands[tex_unit], 0, sizeof (cairo_gl_operand_t));
-}
-
-static void
-_cairo_gl_set_operator (cairo_gl_context_t *ctx,
- cairo_operator_t op,
- cairo_bool_t component_alpha)
-{
- struct {
- GLenum src;
- GLenum dst;
- } blend_factors[] = {
- { GL_ZERO, GL_ZERO }, /* Clear */
- { GL_ONE, GL_ZERO }, /* Source */
- { GL_ONE, GL_ONE_MINUS_SRC_ALPHA }, /* Over */
- { GL_DST_ALPHA, GL_ZERO }, /* In */
- { GL_ONE_MINUS_DST_ALPHA, GL_ZERO }, /* Out */
- { GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Atop */
-
- { GL_ZERO, GL_ONE }, /* Dest */
- { GL_ONE_MINUS_DST_ALPHA, GL_ONE }, /* DestOver */
- { GL_ZERO, GL_SRC_ALPHA }, /* DestIn */
- { GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }, /* DestOut */
- { GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA }, /* DestAtop */
-
- { GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }, /* Xor */
- { GL_ONE, GL_ONE }, /* Add */
- };
- GLenum src_factor, dst_factor;
-
- assert (op < ARRAY_LENGTH (blend_factors));
- /* different dst and component_alpha changes cause flushes elsewhere */
- if (ctx->current_operator != op)
- _cairo_gl_composite_flush (ctx);
- ctx->current_operator = op;
-
- src_factor = blend_factors[op].src;
- dst_factor = blend_factors[op].dst;
-
- /* Even when the user requests CAIRO_CONTENT_COLOR, we use GL_RGBA
- * due to texture filtering of GL_CLAMP_TO_BORDER. So fix those
- * bits in that case.
- */
- if (ctx->current_target->base.content == CAIRO_CONTENT_COLOR) {
- if (src_factor == GL_ONE_MINUS_DST_ALPHA)
- src_factor = GL_ZERO;
- if (src_factor == GL_DST_ALPHA)
- src_factor = GL_ONE;
- }
-
- if (component_alpha) {
- if (dst_factor == GL_ONE_MINUS_SRC_ALPHA)
- dst_factor = GL_ONE_MINUS_SRC_COLOR;
- if (dst_factor == GL_SRC_ALPHA)
- dst_factor = GL_SRC_COLOR;
- }
-
- if (ctx->current_target->base.content == CAIRO_CONTENT_ALPHA) {
- glBlendFuncSeparate (GL_ZERO, GL_ZERO, src_factor, dst_factor);
- } else if (ctx->current_target->base.content == CAIRO_CONTENT_COLOR) {
- glBlendFuncSeparate (src_factor, dst_factor, GL_ONE, GL_ONE);
- } else {
- glBlendFunc (src_factor, dst_factor);
- }
-}
-
-static cairo_status_t
-_cairo_gl_composite_begin_component_alpha (cairo_gl_context_t *ctx,
- cairo_gl_composite_t *setup)
-{
- cairo_gl_shader_t *pre_shader = NULL;
- cairo_status_t status;
-
- /* For CLEAR, cairo's rendering equation (quoting Owen's description in:
- * https://lists.cairographics.org/archives/cairo/2005-August/004992.html)
- * is:
- * mask IN clip ? src OP dest : dest
- * or more simply:
- * mask IN CLIP ? 0 : dest
- *
- * where the ternary operator A ? B : C is (A * B) + ((1 - A) * C).
- *
- * The model we use in _cairo_gl_set_operator() is Render's:
- * src IN mask IN clip OP dest
- * which would boil down to:
- * 0 (bounded by the extents of the drawing).
- *
- * However, we can do a Render operation using an opaque source
- * and DEST_OUT to produce:
- * 1 IN mask IN clip DEST_OUT dest
- * which is
- * mask IN clip ? 0 : dest
- */
- if (setup->op == CAIRO_OPERATOR_CLEAR) {
- _cairo_gl_solid_operand_init (&setup->src, CAIRO_COLOR_WHITE);
- setup->op = CAIRO_OPERATOR_DEST_OUT;
- }
-
- /*
- * implements component-alpha %CAIRO_OPERATOR_OVER using two passes of
- * the simpler operations %CAIRO_OPERATOR_DEST_OUT and %CAIRO_OPERATOR_ADD.
- *
- * From http://anholt.livejournal.com/32058.html:
- *
- * The trouble is that component-alpha rendering requires two different sources
- * for blending: one for the source value to the blender, which is the
- * per-channel multiplication of source and mask, and one for the source alpha
- * for multiplying with the destination channels, which is the multiplication
- * of the source channels by the mask alpha. So the equation for Over is:
- *
- * dst.A = src.A * mask.A + (1 - (src.A * mask.A)) * dst.A
- * dst.R = src.R * mask.R + (1 - (src.A * mask.R)) * dst.R
- * dst.G = src.G * mask.G + (1 - (src.A * mask.G)) * dst.G
- * dst.B = src.B * mask.B + (1 - (src.A * mask.B)) * dst.B
- *
- * But we can do some simpler operations, right? How about PictOpOutReverse,
- * which has a source factor of 0 and dest factor of (1 - source alpha). We
- * can get the source alpha value (srca.X = src.A * mask.X) out of the texture
- * blenders pretty easily. So we can do a component-alpha OutReverse, which
- * gets us:
- *
- * dst.A = 0 + (1 - (src.A * mask.A)) * dst.A
- * dst.R = 0 + (1 - (src.A * mask.R)) * dst.R
- * dst.G = 0 + (1 - (src.A * mask.G)) * dst.G
- * dst.B = 0 + (1 - (src.A * mask.B)) * dst.B
- *
- * OK. And if an op doesn't use the source alpha value for the destination
- * factor, then we can do the channel multiplication in the texture blenders
- * to get the source value, and ignore the source alpha that we wouldn't use.
- * We've supported this in the Radeon driver for a long time. An example would
- * be PictOpAdd, which does:
- *
- * dst.A = src.A * mask.A + dst.A
- * dst.R = src.R * mask.R + dst.R
- * dst.G = src.G * mask.G + dst.G
- * dst.B = src.B * mask.B + dst.B
- *
- * Hey, this looks good! If we do a PictOpOutReverse and then a PictOpAdd right
- * after it, we get:
- *
- * dst.A = src.A * mask.A + ((1 - (src.A * mask.A)) * dst.A)
- * dst.R = src.R * mask.R + ((1 - (src.A * mask.R)) * dst.R)
- * dst.G = src.G * mask.G + ((1 - (src.A * mask.G)) * dst.G)
- * dst.B = src.B * mask.B + ((1 - (src.A * mask.B)) * dst.B)
- *
- * This two-pass trickery could be avoided using a new GL extension that
- * lets two values come out of the shader and into the blend unit.
- */
- if (setup->op == CAIRO_OPERATOR_OVER) {
- setup->op = CAIRO_OPERATOR_ADD;
- status = _cairo_gl_get_shader_by_type (ctx,
- &setup->src,
- &setup->mask,
- setup->spans,
- CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
- &pre_shader);
- if (unlikely (status))
- return status;
- }
-
- if (ctx->pre_shader != pre_shader)
- _cairo_gl_composite_flush (ctx);
- ctx->pre_shader = pre_shader;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_scissor_to_doubles (cairo_gl_surface_t *surface,
- double x1, double y1,
- double x2, double y2)
-{
- double height;
-
- height = y2 - y1;
- if (_cairo_gl_surface_is_texture (surface) == FALSE)
- y1 = surface->height - (y1 + height);
- glScissor (x1, y1, x2 - x1, height);
- glEnable (GL_SCISSOR_TEST);
-}
-
-void
-_cairo_gl_scissor_to_rectangle (cairo_gl_surface_t *surface,
- const cairo_rectangle_int_t *r)
-{
- _scissor_to_doubles (surface, r->x, r->y, r->x+r->width, r->y+r->height);
-}
-
-static void
-_scissor_to_box (cairo_gl_surface_t *surface,
- const cairo_box_t *box)
-{
- double x1, y1, x2, y2;
- _cairo_box_to_doubles (box, &x1, &y1, &x2, &y2);
- _scissor_to_doubles (surface, x1, y1, x2, y2);
-}
-
-static cairo_bool_t
-_cairo_gl_composite_setup_vbo (cairo_gl_context_t *ctx,
- unsigned int size_per_vertex)
-{
- cairo_bool_t vertex_size_changed = ctx->vertex_size != size_per_vertex;
- if (vertex_size_changed) {
- ctx->vertex_size = size_per_vertex;
- _cairo_gl_composite_flush (ctx);
- }
-
- if (_cairo_gl_context_is_flushed (ctx)) {
- ctx->dispatch.VertexAttribPointer (CAIRO_GL_VERTEX_ATTRIB_INDEX, 2,
- GL_FLOAT, GL_FALSE, size_per_vertex,
- ctx->vb);
- ctx->dispatch.EnableVertexAttribArray (CAIRO_GL_VERTEX_ATTRIB_INDEX);
- }
-
- return vertex_size_changed;
-}
-
-static void
-_disable_stencil_buffer (void)
-{
- glDisable (GL_STENCIL_TEST);
- glDepthMask (GL_FALSE);
-}
-
-static cairo_int_status_t
-_cairo_gl_composite_setup_painted_clipping (cairo_gl_composite_t *setup,
- cairo_gl_context_t *ctx,
- int vertex_size)
-{
- cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
-
- cairo_gl_surface_t *dst = setup->dst;
- cairo_clip_t *clip = setup->clip;
-
- if (clip->num_boxes == 1 && clip->path == NULL) {
- _scissor_to_box (dst, &clip->boxes[0]);
- goto disable_stencil_buffer_and_return;
- }
-
- if (! _cairo_gl_ensure_stencil (ctx, setup->dst)) {
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- goto disable_stencil_buffer_and_return;
- }
-
- /* We only want to clear the part of the stencil buffer
- * that we are about to use. It also does not hurt to
- * scissor around the painted clip. */
- _cairo_gl_scissor_to_rectangle (dst, _cairo_clip_get_extents (clip));
-
- /* The clip is not rectangular, so use the stencil buffer. */
- glDepthMask (GL_TRUE);
- glEnable (GL_STENCIL_TEST);
-
- /* Texture surfaces have private depth/stencil buffers, so we can
- * rely on any previous clip being cached there. */
- if (_cairo_gl_surface_is_texture (setup->dst)) {
- cairo_clip_t *old_clip = setup->dst->clip_on_stencil_buffer;
- if (_cairo_clip_equal (old_clip, setup->clip))
- goto activate_stencil_buffer_and_return;
-
- if (old_clip) {
- _cairo_clip_destroy (setup->dst->clip_on_stencil_buffer);
- }
-
- setup->dst->clip_on_stencil_buffer = _cairo_clip_copy (setup->clip);
- }
-
- glClearStencil (0);
- glClear (GL_STENCIL_BUFFER_BIT);
-
- glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE);
- glStencilFunc (GL_EQUAL, 1, 0xffffffff);
- glColorMask (0, 0, 0, 0);
-
- status = _cairo_gl_msaa_compositor_draw_clip (ctx, setup, clip);
-
- if (unlikely (status)) {
- glColorMask (1, 1, 1, 1);
- goto disable_stencil_buffer_and_return;
- }
-
- /* We want to only render to the stencil buffer, so draw everything now.
- Flushing also unbinds the VBO, which we want to rebind for regular
- drawing. */
- _cairo_gl_composite_flush (ctx);
- _cairo_gl_composite_setup_vbo (ctx, vertex_size);
-
-activate_stencil_buffer_and_return:
- glColorMask (1, 1, 1, 1);
- glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
- glStencilFunc (GL_EQUAL, 1, 0xffffffff);
- return CAIRO_INT_STATUS_SUCCESS;
-
-disable_stencil_buffer_and_return:
- _disable_stencil_buffer ();
- return status;
-}
-
-static cairo_int_status_t
-_cairo_gl_composite_setup_clipping (cairo_gl_composite_t *setup,
- cairo_gl_context_t *ctx,
- int vertex_size)
-{
- cairo_bool_t clip_changing = TRUE;
- cairo_bool_t clip_region_changing = TRUE;
-
- if (! ctx->clip && ! setup->clip && ! setup->clip_region && ! ctx->clip_region)
- goto disable_all_clipping;
-
- clip_changing = ! _cairo_clip_equal (ctx->clip, setup->clip);
- clip_region_changing = ! cairo_region_equal (ctx->clip_region, setup->clip_region);
- if (! _cairo_gl_context_is_flushed (ctx) &&
- (clip_region_changing || clip_changing))
- _cairo_gl_composite_flush (ctx);
-
- assert (!setup->clip_region || !setup->clip);
-
- /* setup->clip is only used by the msaa compositor and setup->clip_region
- * only by the other compositors, so it's safe to wait to clean up obsolete
- * clips. */
- if (clip_region_changing) {
- cairo_region_destroy (ctx->clip_region);
- ctx->clip_region = cairo_region_reference (setup->clip_region);
- }
- if (clip_changing) {
- _cairo_clip_destroy (ctx->clip);
- ctx->clip = _cairo_clip_copy (setup->clip);
- }
-
- /* For clip regions, we scissor right before drawing. */
- if (setup->clip_region)
- goto disable_all_clipping;
-
- if (setup->clip)
- return _cairo_gl_composite_setup_painted_clipping (setup, ctx,
- vertex_size);
-disable_all_clipping:
- _disable_stencil_buffer ();
- glDisable (GL_SCISSOR_TEST);
- return CAIRO_INT_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gl_set_operands_and_operator (cairo_gl_composite_t *setup,
- cairo_gl_context_t *ctx)
-{
- unsigned int dst_size, src_size, mask_size, vertex_size;
- cairo_status_t status;
- cairo_gl_shader_t *shader;
- cairo_bool_t component_alpha;
- cairo_bool_t vertex_size_changed;
-
- component_alpha =
- setup->mask.type == CAIRO_GL_OPERAND_TEXTURE &&
- setup->mask.texture.attributes.has_component_alpha;
-
- /* Do various magic for component alpha */
- if (component_alpha) {
- status = _cairo_gl_composite_begin_component_alpha (ctx, setup);
- if (unlikely (status))
- return status;
- } else {
- if (ctx->pre_shader) {
- _cairo_gl_composite_flush (ctx);
- ctx->pre_shader = NULL;
- }
- }
-
- status = _cairo_gl_get_shader_by_type (ctx,
- &setup->src,
- &setup->mask,
- setup->spans,
- component_alpha ?
- CAIRO_GL_SHADER_IN_CA_SOURCE :
- CAIRO_GL_SHADER_IN_NORMAL,
- &shader);
- if (unlikely (status)) {
- ctx->pre_shader = NULL;
- return status;
- }
- if (ctx->current_shader != shader)
- _cairo_gl_composite_flush (ctx);
-
- status = CAIRO_STATUS_SUCCESS;
-
- dst_size = 2 * sizeof (GLfloat);
- src_size = _cairo_gl_operand_get_vertex_size (&setup->src);
- mask_size = _cairo_gl_operand_get_vertex_size (&setup->mask);
- vertex_size = dst_size + src_size + mask_size;
-
- if (setup->spans)
- vertex_size += sizeof (GLfloat);
-
- vertex_size_changed = _cairo_gl_composite_setup_vbo (ctx, vertex_size);
-
- _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_SOURCE, &setup->src, dst_size, vertex_size_changed);
- _cairo_gl_context_setup_operand (ctx, CAIRO_GL_TEX_MASK, &setup->mask, dst_size + src_size, vertex_size_changed);
-
- _cairo_gl_context_setup_spans (ctx, setup->spans, vertex_size,
- dst_size + src_size + mask_size);
-
- _cairo_gl_set_operator (ctx, setup->op, component_alpha);
-
- if (_cairo_gl_context_is_flushed (ctx)) {
- if (ctx->pre_shader) {
- _cairo_gl_set_shader (ctx, ctx->pre_shader);
- _cairo_gl_composite_bind_to_shader (ctx, setup);
- }
- _cairo_gl_set_shader (ctx, shader);
- _cairo_gl_composite_bind_to_shader (ctx, setup);
- }
-
- return status;
-}
-
-cairo_status_t
-_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
- cairo_gl_context_t **ctx_out)
-{
- cairo_gl_context_t *ctx;
- cairo_status_t status;
-
- assert (setup->dst);
-
- status = _cairo_gl_context_acquire (setup->dst->base.device, &ctx);
- if (unlikely (status))
- return status;
-
- _cairo_gl_context_set_destination (ctx, setup->dst, setup->multisample);
- glEnable (GL_BLEND);
-
- status = _cairo_gl_set_operands_and_operator (setup, ctx);
- if (unlikely (status))
- goto FAIL;
-
- status = _cairo_gl_composite_setup_clipping (setup, ctx, ctx->vertex_size);
- if (unlikely (status))
- goto FAIL;
-
- *ctx_out = ctx;
-
-FAIL:
- if (unlikely (status))
- status = _cairo_gl_context_release (ctx, status);
-
- return status;
-}
-
-static inline void
-_cairo_gl_composite_draw_tristrip (cairo_gl_context_t *ctx)
-{
- cairo_array_t* indices = &ctx->tristrip_indices;
- const unsigned short *indices_array = _cairo_array_index_const (indices, 0);
-
- if (ctx->pre_shader) {
- cairo_gl_shader_t *prev_shader = ctx->current_shader;
-
- _cairo_gl_set_shader (ctx, ctx->pre_shader);
- _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE);
- glDrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array);
-
- _cairo_gl_set_shader (ctx, prev_shader);
- _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
- }
-
- glDrawElements (GL_TRIANGLE_STRIP, _cairo_array_num_elements (indices), GL_UNSIGNED_SHORT, indices_array);
- _cairo_array_truncate (indices, 0);
-}
-
-static inline void
-_cairo_gl_composite_draw_triangles (cairo_gl_context_t *ctx,
- unsigned int count)
-{
- if (! ctx->pre_shader) {
- glDrawArrays (GL_TRIANGLES, 0, count);
- } else {
- cairo_gl_shader_t *prev_shader = ctx->current_shader;
-
- _cairo_gl_set_shader (ctx, ctx->pre_shader);
- _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_DEST_OUT, TRUE);
- glDrawArrays (GL_TRIANGLES, 0, count);
-
- _cairo_gl_set_shader (ctx, prev_shader);
- _cairo_gl_set_operator (ctx, CAIRO_OPERATOR_ADD, TRUE);
- glDrawArrays (GL_TRIANGLES, 0, count);
- }
-}
-
-static void
-_cairo_gl_composite_draw_triangles_with_clip_region (cairo_gl_context_t *ctx,
- unsigned int count)
-{
- int i, num_rectangles;
-
- if (!ctx->clip_region) {
- _cairo_gl_composite_draw_triangles (ctx, count);
- return;
- }
-
- num_rectangles = cairo_region_num_rectangles (ctx->clip_region);
- for (i = 0; i < num_rectangles; i++) {
- cairo_rectangle_int_t rect;
-
- cairo_region_get_rectangle (ctx->clip_region, i, &rect);
-
- _cairo_gl_scissor_to_rectangle (ctx->current_target, &rect);
- _cairo_gl_composite_draw_triangles (ctx, count);
- }
-}
-
-static void
-_cairo_gl_composite_unmap_vertex_buffer (cairo_gl_context_t *ctx)
-{
- ctx->vb_offset = 0;
-}
-
-void
-_cairo_gl_composite_flush (cairo_gl_context_t *ctx)
-{
- unsigned int count;
- int i;
-
- if (_cairo_gl_context_is_flushed (ctx))
- return;
-
- count = ctx->vb_offset / ctx->vertex_size;
- _cairo_gl_composite_unmap_vertex_buffer (ctx);
-
- if (ctx->primitive_type == CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS) {
- _cairo_gl_composite_draw_tristrip (ctx);
- } else {
- assert (ctx->primitive_type == CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
- _cairo_gl_composite_draw_triangles_with_clip_region (ctx, count);
- }
-
- for (i = 0; i < ARRAY_LENGTH (ctx->glyph_cache); i++)
- _cairo_gl_glyph_cache_unlock (&ctx->glyph_cache[i]);
-}
-
-static void
-_cairo_gl_composite_prepare_buffer (cairo_gl_context_t *ctx,
- unsigned int n_vertices,
- cairo_gl_primitive_type_t primitive_type)
-{
- if (ctx->primitive_type != primitive_type) {
- _cairo_gl_composite_flush (ctx);
- ctx->primitive_type = primitive_type;
- }
-
- assert(ctx->vbo_size > 0);
- if (ctx->vb_offset + n_vertices * ctx->vertex_size > ctx->vbo_size)
- _cairo_gl_composite_flush (ctx);
-}
-
-static inline void
-_cairo_gl_composite_emit_vertex (cairo_gl_context_t *ctx,
- GLfloat x, GLfloat y)
-{
- GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
-
- *vb++ = x;
- *vb++ = y;
-
- _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
- _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK ], &vb, x, y);
-
- ctx->vb_offset += ctx->vertex_size;
-}
-
-static inline void
-_cairo_gl_composite_emit_alpha_vertex (cairo_gl_context_t *ctx,
- GLfloat x, GLfloat y, uint8_t alpha)
-{
- GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
- union fi {
- float f;
- GLbyte bytes[4];
- } fi;
-
- *vb++ = x;
- *vb++ = y;
-
- _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
- _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_MASK ], &vb, x, y);
-
- fi.bytes[0] = 0;
- fi.bytes[1] = 0;
- fi.bytes[2] = 0;
- fi.bytes[3] = alpha;
- *vb++ = fi.f;
-
- ctx->vb_offset += ctx->vertex_size;
-}
-
-static void
-_cairo_gl_composite_emit_point (cairo_gl_context_t *ctx,
- const cairo_point_t *point)
-{
- _cairo_gl_composite_emit_vertex (ctx,
- _cairo_fixed_to_double (point->x),
- _cairo_fixed_to_double (point->y));
-}
-
-static void
-_cairo_gl_composite_emit_rect (cairo_gl_context_t *ctx,
- GLfloat x1, GLfloat y1,
- GLfloat x2, GLfloat y2)
-{
- _cairo_gl_composite_prepare_buffer (ctx, 6,
- CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
-
- _cairo_gl_composite_emit_vertex (ctx, x1, y1);
- _cairo_gl_composite_emit_vertex (ctx, x2, y1);
- _cairo_gl_composite_emit_vertex (ctx, x1, y2);
-
- _cairo_gl_composite_emit_vertex (ctx, x2, y1);
- _cairo_gl_composite_emit_vertex (ctx, x2, y2);
- _cairo_gl_composite_emit_vertex (ctx, x1, y2);
-}
-
-cairo_gl_emit_rect_t
-_cairo_gl_context_choose_emit_rect (cairo_gl_context_t *ctx)
-{
- return _cairo_gl_composite_emit_rect;
-}
-
-void
-_cairo_gl_context_emit_rect (cairo_gl_context_t *ctx,
- GLfloat x1, GLfloat y1,
- GLfloat x2, GLfloat y2)
-{
- _cairo_gl_composite_emit_rect (ctx, x1, y1, x2, y2);
-}
-
-static void
-_cairo_gl_composite_emit_span (cairo_gl_context_t *ctx,
- GLfloat x1, GLfloat y1,
- GLfloat x2, GLfloat y2,
- uint8_t alpha)
-{
- _cairo_gl_composite_prepare_buffer (ctx, 6,
- CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
-
- _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y1, alpha);
- _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y1, alpha);
- _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y2, alpha);
-
- _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y1, alpha);
- _cairo_gl_composite_emit_alpha_vertex (ctx, x2, y2, alpha);
- _cairo_gl_composite_emit_alpha_vertex (ctx, x1, y2, alpha);
-}
-
-static void
-_cairo_gl_composite_emit_solid_span (cairo_gl_context_t *ctx,
- GLfloat x1, GLfloat y1,
- GLfloat x2, GLfloat y2,
- uint8_t alpha)
-{
- GLfloat *v;
- union fi {
- float f;
- GLbyte bytes[4];
- } fi;
-
- _cairo_gl_composite_prepare_buffer (ctx, 6,
- CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
- v = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
-
- v[15] = v[ 6] = v[0] = x1;
- v[10] = v[ 4] = v[1] = y1;
- v[12] = v[ 9] = v[3] = x2;
- v[16] = v[13] = v[7] = y2;
-
- fi.bytes[0] = 0;
- fi.bytes[1] = 0;
- fi.bytes[2] = 0;
- fi.bytes[3] = alpha;
- v[17] =v[14] = v[11] = v[8] = v[5] = v[2] = fi.f;
-
- ctx->vb_offset += 6*3 * sizeof(GLfloat);
-}
-
-cairo_gl_emit_span_t
-_cairo_gl_context_choose_emit_span (cairo_gl_context_t *ctx)
-{
- if (ctx->operands[CAIRO_GL_TEX_MASK].type != CAIRO_GL_OPERAND_NONE) {
- switch (ctx->operands[CAIRO_GL_TEX_MASK].type) {
- default:
- case CAIRO_GL_OPERAND_COUNT:
- ASSERT_NOT_REACHED;
- case CAIRO_GL_OPERAND_NONE:
- case CAIRO_GL_OPERAND_CONSTANT:
- break;
-
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- if (!ctx->operands[CAIRO_GL_TEX_MASK].gradient.texgen)
- return _cairo_gl_composite_emit_span;
- break;
-
- case CAIRO_GL_OPERAND_TEXTURE:
- if (!ctx->operands[CAIRO_GL_TEX_MASK].texture.texgen)
- return _cairo_gl_composite_emit_span;
- break;
- }
- }
-
- switch (ctx->operands[CAIRO_GL_TEX_SOURCE].type) {
- default:
- case CAIRO_GL_OPERAND_COUNT:
- ASSERT_NOT_REACHED;
- case CAIRO_GL_OPERAND_NONE:
- case CAIRO_GL_OPERAND_CONSTANT:
- break;
-
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- if (!ctx->operands[CAIRO_GL_TEX_SOURCE].gradient.texgen)
- return _cairo_gl_composite_emit_span;
- break;
-
- case CAIRO_GL_OPERAND_TEXTURE:
- if (!ctx->operands[CAIRO_GL_TEX_SOURCE].texture.texgen)
- return _cairo_gl_composite_emit_span;
- }
-
- return _cairo_gl_composite_emit_solid_span;
-}
-
-static inline void
-_cairo_gl_composite_emit_glyph_vertex (cairo_gl_context_t *ctx,
- GLfloat x, GLfloat y,
- GLfloat glyph_x, GLfloat glyph_y)
-{
- GLfloat *vb = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
-
- *vb++ = x;
- *vb++ = y;
-
- _cairo_gl_operand_emit (&ctx->operands[CAIRO_GL_TEX_SOURCE], &vb, x, y);
-
- *vb++ = glyph_x;
- *vb++ = glyph_y;
-
- ctx->vb_offset += ctx->vertex_size;
-}
-
-static void
-_cairo_gl_composite_emit_glyph (cairo_gl_context_t *ctx,
- GLfloat x1, GLfloat y1,
- GLfloat x2, GLfloat y2,
- GLfloat glyph_x1, GLfloat glyph_y1,
- GLfloat glyph_x2, GLfloat glyph_y2)
-{
- _cairo_gl_composite_prepare_buffer (ctx, 6,
- CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
-
- _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y1, glyph_x1, glyph_y1);
- _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
- _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
-
- _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y1, glyph_x2, glyph_y1);
- _cairo_gl_composite_emit_glyph_vertex (ctx, x2, y2, glyph_x2, glyph_y2);
- _cairo_gl_composite_emit_glyph_vertex (ctx, x1, y2, glyph_x1, glyph_y2);
-}
-
-static void
-_cairo_gl_composite_emit_solid_glyph (cairo_gl_context_t *ctx,
- GLfloat x1, GLfloat y1,
- GLfloat x2, GLfloat y2,
- GLfloat glyph_x1, GLfloat glyph_y1,
- GLfloat glyph_x2, GLfloat glyph_y2)
-{
- GLfloat *v;
-
- _cairo_gl_composite_prepare_buffer (ctx, 6,
- CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES);
-
- v = (GLfloat *) (void *) &ctx->vb[ctx->vb_offset];
-
- v[20] = v[ 8] = v[0] = x1;
- v[13] = v[ 5] = v[1] = y1;
- v[22] = v[10] = v[2] = glyph_x1;
- v[15] = v[ 7] = v[3] = glyph_y1;
-
- v[16] = v[12] = v[4] = x2;
- v[18] = v[14] = v[6] = glyph_x2;
-
- v[21] = v[17] = v[ 9] = y2;
- v[23] = v[19] = v[11] = glyph_y2;
-
- ctx->vb_offset += 4 * 6 * sizeof (GLfloat);
-}
-
-cairo_gl_emit_glyph_t
-_cairo_gl_context_choose_emit_glyph (cairo_gl_context_t *ctx)
-{
- switch (ctx->operands[CAIRO_GL_TEX_SOURCE].type) {
- default:
- case CAIRO_GL_OPERAND_COUNT:
- ASSERT_NOT_REACHED;
- case CAIRO_GL_OPERAND_NONE:
- case CAIRO_GL_OPERAND_CONSTANT:
- return _cairo_gl_composite_emit_solid_glyph;
-
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- case CAIRO_GL_OPERAND_TEXTURE:
- return _cairo_gl_composite_emit_glyph;
- }
-}
-
-void
-_cairo_gl_composite_fini (cairo_gl_composite_t *setup)
-{
- _cairo_gl_operand_destroy (&setup->src);
- _cairo_gl_operand_destroy (&setup->mask);
-}
-
-cairo_status_t
-_cairo_gl_composite_set_operator (cairo_gl_composite_t *setup,
- cairo_operator_t op,
- cairo_bool_t assume_component_alpha)
-{
- if (assume_component_alpha) {
- if (op != CAIRO_OPERATOR_CLEAR &&
- op != CAIRO_OPERATOR_OVER &&
- op != CAIRO_OPERATOR_ADD)
- return UNSUPPORTED ("unsupported component alpha operator");
- } else {
- if (! _cairo_gl_operator_is_supported (op))
- return UNSUPPORTED ("unsupported operator");
- }
-
- setup->op = op;
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gl_composite_init (cairo_gl_composite_t *setup,
- cairo_operator_t op,
- cairo_gl_surface_t *dst,
- cairo_bool_t assume_component_alpha)
-{
- cairo_status_t status;
-
- status = _blit_texture_to_renderbuffer (dst);
-
- memset (setup, 0, sizeof (cairo_gl_composite_t));
-
- status = _cairo_gl_composite_set_operator (setup, op,
- assume_component_alpha);
- if (status)
- return status;
-
- setup->dst = dst;
- setup->clip_region = dst->clip_region;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_gl_composite_append_vertex_indices (cairo_gl_context_t *ctx,
- int number_of_new_indices)
-{
- cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
- cairo_array_t *indices = &ctx->tristrip_indices;
- int number_of_indices = _cairo_array_num_elements (indices);
- unsigned short current_vertex_index = 0;
- int i;
-
- assert (number_of_new_indices > 0);
-
- /* If any preexisting triangle triangle strip indices exist on this
- context, we insert a set of degenerate triangles from the last
- preexisting vertex to our first one. */
- if (number_of_indices > 0) {
- const unsigned short *indices_array = _cairo_array_index_const (indices, 0);
- current_vertex_index = indices_array[number_of_indices - 1];
-
- status = _cairo_array_append (indices, &current_vertex_index);
- if (unlikely (status))
- return status;
-
- current_vertex_index++;
- status =_cairo_array_append (indices, &current_vertex_index);
- if (unlikely (status))
- return status;
- }
-
- for (i = 0; i < number_of_new_indices; i++) {
- status = _cairo_array_append (indices, &current_vertex_index);
- current_vertex_index++;
- if (unlikely (status))
- return status;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_int_status_t
-_cairo_gl_composite_emit_quad_as_tristrip (cairo_gl_context_t *ctx,
- cairo_gl_composite_t *setup,
- const cairo_point_t quad[4])
-{
- _cairo_gl_composite_prepare_buffer (ctx, 4,
- CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
-
- _cairo_gl_composite_emit_point (ctx, &quad[0]);
- _cairo_gl_composite_emit_point (ctx, &quad[1]);
-
- /* Cairo stores quad vertices in counter-clockwise order, but we need to
- emit them from top to bottom in the triangle strip, so we need to reverse
- the order of the last two vertices. */
- _cairo_gl_composite_emit_point (ctx, &quad[3]);
- _cairo_gl_composite_emit_point (ctx, &quad[2]);
-
- return _cairo_gl_composite_append_vertex_indices (ctx, 4);
-}
-
-cairo_int_status_t
-_cairo_gl_composite_emit_triangle_as_tristrip (cairo_gl_context_t *ctx,
- cairo_gl_composite_t *setup,
- const cairo_point_t triangle[3])
-{
- _cairo_gl_composite_prepare_buffer (ctx, 3,
- CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS);
-
- _cairo_gl_composite_emit_point (ctx, &triangle[0]);
- _cairo_gl_composite_emit_point (ctx, &triangle[1]);
- _cairo_gl_composite_emit_point (ctx, &triangle[2]);
- return _cairo_gl_composite_append_vertex_indices (ctx, 3);
-}
diff --git a/src/cairo-gl-device.c b/src/cairo-gl-device.c
deleted file mode 100644
index 6f4c852a4..000000000
--- a/src/cairo-gl-device.c
+++ /dev/null
@@ -1,851 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 Eric Anholt
- * Copyright © 2009 Chris Wilson
- * Copyright © 2005,2010 Red Hat, Inc
- * Copyright © 2010 Linaro Limited
- *
- * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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):
- * Benjamin Otte <otte@gnome.org>
- * Carl Worth <cworth@cworth.org>
- * Chris Wilson <chris@chris-wilson.co.uk>
- * Eric Anholt <eric@anholt.net>
- * Alexandros Frantzis <alexandros.frantzis@linaro.org>
- */
-
-#include "cairoint.h"
-
-#include "cairo-error-private.h"
-#include "cairo-gl-private.h"
-
-#define MAX_MSAA_SAMPLES 4
-
-static void
-_gl_lock (void *device)
-{
- cairo_gl_context_t *ctx = (cairo_gl_context_t *) device;
-
- ctx->acquire (ctx);
-}
-
-static void
-_gl_unlock (void *device)
-{
- cairo_gl_context_t *ctx = (cairo_gl_context_t *) device;
-
- ctx->release (ctx);
-}
-
-static cairo_status_t
-_gl_flush (void *device)
-{
- cairo_gl_context_t *ctx;
- cairo_status_t status;
-
- status = _cairo_gl_context_acquire (device, &ctx);
- if (unlikely (status))
- return status;
-
- _cairo_gl_composite_flush (ctx);
-
- _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
- _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
-
- if (ctx->clip_region) {
- cairo_region_destroy (ctx->clip_region);
- ctx->clip_region = NULL;
- }
-
- ctx->current_target = NULL;
- ctx->current_operator = -1;
- ctx->vertex_size = 0;
- ctx->pre_shader = NULL;
- _cairo_gl_set_shader (ctx, NULL);
-
- ctx->dispatch.BindBuffer (GL_ARRAY_BUFFER, 0);
-
- glDisable (GL_SCISSOR_TEST);
- glDisable (GL_BLEND);
-
- return _cairo_gl_context_release (ctx, status);
-}
-
-static void
-_gl_finish (void *device)
-{
- cairo_gl_context_t *ctx = device;
- int n;
-
- _gl_lock (device);
-
- _cairo_cache_fini (&ctx->gradients);
-
- _cairo_gl_context_fini_shaders (ctx);
-
- for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
- _cairo_gl_glyph_cache_fini (ctx, &ctx->glyph_cache[n]);
-
- _gl_unlock (device);
-}
-
-static void
-_gl_destroy (void *device)
-{
- cairo_gl_context_t *ctx = device;
-
- ctx->acquire (ctx);
-
- while (! cairo_list_is_empty (&ctx->fonts)) {
- cairo_gl_font_t *font;
-
- font = cairo_list_first_entry (&ctx->fonts,
- cairo_gl_font_t,
- link);
-
- cairo_list_del (&font->base.link);
- cairo_list_del (&font->link);
- free (font);
- }
-
- _cairo_array_fini (&ctx->tristrip_indices);
-
- cairo_region_destroy (ctx->clip_region);
- _cairo_clip_destroy (ctx->clip);
-
- free (ctx->vb);
-
- ctx->destroy (ctx);
-
- free (ctx);
-}
-
-static const cairo_device_backend_t _cairo_gl_device_backend = {
- CAIRO_DEVICE_TYPE_GL,
-
- _gl_lock,
- _gl_unlock,
-
- _gl_flush, /* flush */
- _gl_finish,
- _gl_destroy,
-};
-
-static cairo_bool_t
-_cairo_gl_msaa_compositor_enabled (void)
-{
- const char *env = getenv ("CAIRO_GL_COMPOSITOR");
- return env && strcmp(env, "msaa") == 0;
-}
-
-static cairo_bool_t
-test_can_read_bgra (cairo_gl_flavor_t gl_flavor)
-{
- /* Desktop GL always supports BGRA formats. */
- if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
- return TRUE;
-
- assert (gl_flavor == CAIRO_GL_FLAVOR_ES3 ||
- gl_flavor == CAIRO_GL_FLAVOR_ES2);
-
- /* For OpenGL ES we have to look for the specific extension and BGRA only
- * matches cairo's integer packed bytes on little-endian machines. */
- if (!_cairo_is_little_endian())
- return FALSE;
- return _cairo_gl_has_extension ("EXT_read_format_bgra");
-}
-
-cairo_status_t
-_cairo_gl_context_init (cairo_gl_context_t *ctx)
-{
- cairo_status_t status;
- cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
- int gl_version = _cairo_gl_get_version ();
- cairo_gl_flavor_t gl_flavor = _cairo_gl_get_flavor ();
- int n;
-
- cairo_bool_t is_desktop = gl_flavor == CAIRO_GL_FLAVOR_DESKTOP;
- cairo_bool_t is_gles = (gl_flavor == CAIRO_GL_FLAVOR_ES3 ||
- gl_flavor == CAIRO_GL_FLAVOR_ES2);
-
- _cairo_device_init (&ctx->base, &_cairo_gl_device_backend);
-
- /* XXX The choice of compositor should be made automatically at runtime.
- * However, it is useful to force one particular compositor whilst
- * testing.
- */
- if (_cairo_gl_msaa_compositor_enabled ())
- ctx->compositor = _cairo_gl_msaa_compositor_get ();
- else
- ctx->compositor = _cairo_gl_span_compositor_get ();
-
-
- ctx->thread_aware = TRUE;
-
- memset (ctx->glyph_cache, 0, sizeof (ctx->glyph_cache));
- cairo_list_init (&ctx->fonts);
-
- /* Support only GL version >= 1.3 */
- if (gl_version < CAIRO_GL_VERSION_ENCODE (1, 3))
- return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
-
- /* Check for required extensions */
- if (is_desktop) {
- if (_cairo_gl_has_extension ("GL_ARB_texture_non_power_of_two")) {
- ctx->tex_target = GL_TEXTURE_2D;
- ctx->has_npot_repeat = TRUE;
- } else if (_cairo_gl_has_extension ("GL_ARB_texture_rectangle")) {
- ctx->tex_target = GL_TEXTURE_RECTANGLE;
- ctx->has_npot_repeat = FALSE;
- } else
- return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
- } else {
- ctx->tex_target = GL_TEXTURE_2D;
- if (_cairo_gl_has_extension ("GL_OES_texture_npot") ||
- _cairo_gl_has_extension ("GL_IMG_texture_npot"))
- ctx->has_npot_repeat = TRUE;
- else
- ctx->has_npot_repeat = FALSE;
- }
-
- if (is_desktop && gl_version < CAIRO_GL_VERSION_ENCODE (2, 1) &&
- ! _cairo_gl_has_extension ("GL_ARB_pixel_buffer_object"))
- return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
-
- if (is_gles && ! _cairo_gl_has_extension ("GL_EXT_texture_format_BGRA8888"))
- return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
-
- ctx->has_map_buffer =
- is_desktop || (is_gles && _cairo_gl_has_extension ("GL_OES_mapbuffer"));
-
- ctx->can_read_bgra = test_can_read_bgra (gl_flavor);
-
- ctx->has_mesa_pack_invert =
- _cairo_gl_has_extension ("GL_MESA_pack_invert");
-
- ctx->has_packed_depth_stencil =
- (is_desktop && _cairo_gl_has_extension ("GL_EXT_packed_depth_stencil")) ||
- (is_gles && _cairo_gl_has_extension ("GL_OES_packed_depth_stencil"));
-
- ctx->num_samples = 1;
-
-#if CAIRO_HAS_GL_SURFACE
- if (is_desktop && ctx->has_packed_depth_stencil &&
- (gl_version >= CAIRO_GL_VERSION_ENCODE (3, 0) ||
- _cairo_gl_has_extension ("GL_ARB_framebuffer_object") ||
- (_cairo_gl_has_extension ("GL_EXT_framebuffer_blit") &&
- _cairo_gl_has_extension ("GL_EXT_framebuffer_multisample")))) {
- glGetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples);
- }
-#endif
-
-#if CAIRO_HAS_GLESV3_SURFACE
- if (is_gles && ctx->has_packed_depth_stencil) {
- glGetIntegerv(GL_MAX_SAMPLES, &ctx->num_samples);
- }
-
-#elif CAIRO_HAS_GLESV2_SURFACE && defined(GL_MAX_SAMPLES_EXT)
- if (is_gles && ctx->has_packed_depth_stencil &&
- _cairo_gl_has_extension ("GL_EXT_multisampled_render_to_texture")) {
- glGetIntegerv(GL_MAX_SAMPLES_EXT, &ctx->num_samples);
- }
-
- if (is_gles && ctx->has_packed_depth_stencil &&
- _cairo_gl_has_extension ("GL_IMG_multisampled_render_to_texture")) {
- glGetIntegerv(GL_MAX_SAMPLES_IMG, &ctx->num_samples);
- }
-#endif
-
- /* we always use renderbuffer for rendering in glesv3 */
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
- ctx->supports_msaa = TRUE;
- else
- ctx->supports_msaa = ctx->num_samples > 1;
- if (ctx->num_samples > MAX_MSAA_SAMPLES)
- ctx->num_samples = MAX_MSAA_SAMPLES;
-
- ctx->current_operator = -1;
- ctx->gl_flavor = gl_flavor;
-
- status = _cairo_gl_context_init_shaders (ctx);
- if (unlikely (status))
- return status;
-
- status = _cairo_cache_init (&ctx->gradients,
- _cairo_gl_gradient_equal,
- NULL,
- (cairo_destroy_func_t) _cairo_gl_gradient_destroy,
- CAIRO_GL_GRADIENT_CACHE_SIZE);
- if (unlikely (status))
- return status;
-
- ctx->vbo_size = _cairo_gl_get_vbo_size();
-
- ctx->vb = _cairo_malloc (ctx->vbo_size);
- if (unlikely (ctx->vb == NULL)) {
- _cairo_cache_fini (&ctx->gradients);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- ctx->primitive_type = CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES;
- _cairo_array_init (&ctx->tristrip_indices, sizeof (unsigned short));
-
- /* PBO for any sort of texture upload */
- dispatch->GenBuffers (1, &ctx->texture_load_pbo);
-
- ctx->max_framebuffer_size = 0;
- glGetIntegerv (GL_MAX_RENDERBUFFER_SIZE, &ctx->max_framebuffer_size);
- ctx->max_texture_size = 0;
- glGetIntegerv (GL_MAX_TEXTURE_SIZE, &ctx->max_texture_size);
- ctx->max_textures = 0;
- glGetIntegerv (GL_MAX_TEXTURE_IMAGE_UNITS, &ctx->max_textures);
-
- for (n = 0; n < ARRAY_LENGTH (ctx->glyph_cache); n++)
- _cairo_gl_glyph_cache_init (&ctx->glyph_cache[n]);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-void
-_cairo_gl_context_activate (cairo_gl_context_t *ctx,
- cairo_gl_tex_t tex_unit)
-{
- if (ctx->max_textures <= (GLint) tex_unit) {
- if (tex_unit < 2) {
- _cairo_gl_composite_flush (ctx);
- _cairo_gl_context_destroy_operand (ctx, ctx->max_textures - 1);
- }
- glActiveTexture (ctx->max_textures - 1);
- } else {
- glActiveTexture (GL_TEXTURE0 + tex_unit);
- }
-}
-
-static GLenum
-_get_depth_stencil_format (cairo_gl_context_t *ctx)
-{
- /* This is necessary to properly handle the situation where both
- OpenGL and OpenGLES are active and returning a sane default. */
-#if CAIRO_HAS_GL_SURFACE
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
- return GL_DEPTH_STENCIL;
-#endif
-
-#if CAIRO_HAS_GLESV2_SURFACE && !CAIRO_HAS_GLESV3_SURFACE
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
- return GL_DEPTH24_STENCIL8_OES;
-#endif
-
-#if CAIRO_HAS_GL_SURFACE
- return GL_DEPTH_STENCIL;
-#elif CAIRO_HAS_GLESV3_SURFACE
- return GL_DEPTH24_STENCIL8;
-#elif CAIRO_HAS_GLESV2_SURFACE
- return GL_DEPTH24_STENCIL8_OES;
-#endif
-}
-
-#if CAIRO_HAS_GLESV2_SURFACE
-static void
-_cairo_gl_ensure_msaa_gles_framebuffer (cairo_gl_context_t *ctx,
- cairo_gl_surface_t *surface)
-{
- if (surface->msaa_active)
- return;
-
- ctx->dispatch.FramebufferTexture2DMultisample(GL_FRAMEBUFFER,
- GL_COLOR_ATTACHMENT0,
- ctx->tex_target,
- surface->tex,
- 0,
- ctx->num_samples);
-
- /* From now on MSAA will always be active on this surface. */
- surface->msaa_active = TRUE;
-}
-#endif
-
-void
-_cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
- cairo_gl_surface_t *surface)
-{
- GLenum status;
- cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-
- if (likely (surface->fb))
- return;
-
- /* Create a framebuffer object wrapping the texture so that we can render
- * to it.
- */
- dispatch->GenFramebuffers (1, &surface->fb);
- dispatch->BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
-
- /* Unlike for desktop GL we only maintain one multisampling framebuffer
- for OpenGLES since the EXT_multisampled_render_to_texture extension
- does not require an explicit multisample resolution. */
-#if CAIRO_HAS_GLESV2_SURFACE
- if (surface->supports_msaa && _cairo_gl_msaa_compositor_enabled () &&
- ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2) {
- _cairo_gl_ensure_msaa_gles_framebuffer (ctx, surface);
- } else
-#endif
- dispatch->FramebufferTexture2D (GL_FRAMEBUFFER,
- GL_COLOR_ATTACHMENT0,
- ctx->tex_target,
- surface->tex,
- 0);
-
-#if CAIRO_HAS_GL_SURFACE
- glDrawBuffer (GL_COLOR_ATTACHMENT0);
- glReadBuffer (GL_COLOR_ATTACHMENT0);
-#endif
-
- status = dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER);
- if (status != GL_FRAMEBUFFER_COMPLETE) {
- const char *str;
- switch (status) {
- //case GL_FRAMEBUFFER_UNDEFINED: str= "undefined"; break;
- case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: str= "incomplete attachment"; break;
- case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: str= "incomplete/missing attachment"; break;
- case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: str= "incomplete draw buffer"; break;
- case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: str= "incomplete read buffer"; break;
- case GL_FRAMEBUFFER_UNSUPPORTED: str= "unsupported"; break;
- case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: str= "incomplete multiple"; break;
- default: str = "unknown error"; break;
- }
-
- fprintf (stderr,
- "destination is framebuffer incomplete: %s [%#x]\n",
- str, status);
- }
-}
-#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV3_SURFACE
-static void
-_cairo_gl_ensure_multisampling (cairo_gl_context_t *ctx,
- cairo_gl_surface_t *surface)
-{
- assert (surface->supports_msaa);
- assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
- ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3);
-
- if (surface->msaa_fb)
- return;
-
- /* We maintain a separate framebuffer for multisampling operations.
- This allows us to do a fast paint to the non-multisampling framebuffer
- when mulitsampling is disabled. */
- ctx->dispatch.GenFramebuffers (1, &surface->msaa_fb);
- ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
- ctx->dispatch.GenRenderbuffers (1, &surface->msaa_rb);
- ctx->dispatch.BindRenderbuffer (GL_RENDERBUFFER, surface->msaa_rb);
-
- /* FIXME: For now we assume that textures passed from the outside have GL_RGBA
- format, but eventually we need to expose a way for the API consumer to pass
- this information. */
- ctx->dispatch.RenderbufferStorageMultisample (GL_RENDERBUFFER,
- ctx->num_samples,
-#if CAIRO_HAS_GLESV3_SURFACE
- GL_RGBA8,
-#else
- GL_RGBA,
-#endif
- surface->width,
- surface->height);
- ctx->dispatch.FramebufferRenderbuffer (GL_FRAMEBUFFER,
- GL_COLOR_ATTACHMENT0,
- GL_RENDERBUFFER,
- surface->msaa_rb);
-
- /* Cairo surfaces start out initialized to transparent (black) */
- glDisable (GL_SCISSOR_TEST);
- glClearColor (0, 0, 0, 0);
- glClear (GL_COLOR_BUFFER_BIT);
-
- /* for glesv3 with multisample renderbuffer, we always render to
- this renderbuffer */
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
- surface->msaa_active = TRUE;
-}
-#endif
-
-static cairo_bool_t
-_cairo_gl_ensure_msaa_depth_stencil_buffer (cairo_gl_context_t *ctx,
- cairo_gl_surface_t *surface)
-{
- cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
- if (surface->msaa_depth_stencil)
- return TRUE;
-
- _cairo_gl_ensure_framebuffer (ctx, surface);
-#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV3_SURFACE
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
- ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
- _cairo_gl_ensure_multisampling (ctx, surface);
-#endif
-
- dispatch->GenRenderbuffers (1, &surface->msaa_depth_stencil);
- dispatch->BindRenderbuffer (GL_RENDERBUFFER,
- surface->msaa_depth_stencil);
-
- dispatch->RenderbufferStorageMultisample (GL_RENDERBUFFER,
- ctx->num_samples,
- _get_depth_stencil_format (ctx),
- surface->width,
- surface->height);
-
-#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV3_SURFACE
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
- ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3) {
- dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
- GL_DEPTH_STENCIL_ATTACHMENT,
- GL_RENDERBUFFER,
- surface->msaa_depth_stencil);
- }
-#endif
-
-#if CAIRO_HAS_GLESV2_SURFACE
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2) {
- dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
- GL_DEPTH_ATTACHMENT,
- GL_RENDERBUFFER,
- surface->msaa_depth_stencil);
- dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER,
- GL_STENCIL_ATTACHMENT,
- GL_RENDERBUFFER,
- surface->msaa_depth_stencil);
- }
-#endif
-
- if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
- dispatch->DeleteRenderbuffers (1, &surface->msaa_depth_stencil);
- surface->msaa_depth_stencil = 0;
- return FALSE;
- }
-
- return TRUE;
-}
-
-static cairo_bool_t
-_cairo_gl_ensure_depth_stencil_buffer (cairo_gl_context_t *ctx,
- cairo_gl_surface_t *surface)
-{
- cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
-
- if (surface->depth_stencil)
- return TRUE;
-
- _cairo_gl_ensure_framebuffer (ctx, surface);
-
- dispatch->GenRenderbuffers (1, &surface->depth_stencil);
- dispatch->BindRenderbuffer (GL_RENDERBUFFER, surface->depth_stencil);
- dispatch->RenderbufferStorage (GL_RENDERBUFFER,
- _get_depth_stencil_format (ctx),
- surface->width, surface->height);
-
- dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
- GL_RENDERBUFFER, surface->depth_stencil);
- dispatch->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
- GL_RENDERBUFFER, surface->depth_stencil);
- if (dispatch->CheckFramebufferStatus (GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
- dispatch->DeleteRenderbuffers (1, &surface->depth_stencil);
- surface->depth_stencil = 0;
- return FALSE;
- }
-
- return TRUE;
-}
-
-cairo_bool_t
-_cairo_gl_ensure_stencil (cairo_gl_context_t *ctx,
- cairo_gl_surface_t *surface)
-{
- if (! _cairo_gl_surface_is_texture (surface))
- return TRUE; /* best guess for now, will check later */
- if (! ctx->has_packed_depth_stencil)
- return FALSE;
-
- if (surface->msaa_active)
- return _cairo_gl_ensure_msaa_depth_stencil_buffer (ctx, surface);
- else
- return _cairo_gl_ensure_depth_stencil_buffer (ctx, surface);
-}
-
-/*
- * Stores a parallel projection transformation in matrix 'm',
- * using column-major order.
- *
- * This is equivalent to:
- *
- * glLoadIdentity()
- * gluOrtho2D()
- *
- * The calculation for the ortho transformation was taken from the
- * mesa source code.
- */
-static void
-_gl_identity_ortho (GLfloat *m,
- GLfloat left, GLfloat right,
- GLfloat bottom, GLfloat top)
-{
-#define M(row,col) m[col*4+row]
- M(0,0) = 2.f / (right - left);
- M(0,1) = 0.f;
- M(0,2) = 0.f;
- M(0,3) = -(right + left) / (right - left);
-
- M(1,0) = 0.f;
- M(1,1) = 2.f / (top - bottom);
- M(1,2) = 0.f;
- M(1,3) = -(top + bottom) / (top - bottom);
-
- M(2,0) = 0.f;
- M(2,1) = 0.f;
- M(2,2) = -1.f;
- M(2,3) = 0.f;
-
- M(3,0) = 0.f;
- M(3,1) = 0.f;
- M(3,2) = 0.f;
- M(3,3) = 1.f;
-#undef M
-}
-
-#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV3_SURFACE
-static void
-bind_multisample_framebuffer (cairo_gl_context_t *ctx,
- cairo_gl_surface_t *surface)
-{
- cairo_bool_t stencil_test_enabled;
- cairo_bool_t scissor_test_enabled;
-
- assert (surface->supports_msaa);
- assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
- ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3);
-
- _cairo_gl_ensure_framebuffer (ctx, surface);
- _cairo_gl_ensure_multisampling (ctx, surface);
-
- if (surface->msaa_active) {
-#if CAIRO_HAS_GL_SURFACE
- glEnable (GL_MULTISAMPLE);
-#endif
- ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
- surface->content_in_texture = FALSE;
- return;
- }
-
- _cairo_gl_composite_flush (ctx);
-
- stencil_test_enabled = glIsEnabled (GL_STENCIL_TEST);
- scissor_test_enabled = glIsEnabled (GL_SCISSOR_TEST);
- glDisable (GL_STENCIL_TEST);
- glDisable (GL_SCISSOR_TEST);
-
-#if CAIRO_HAS_GL_SURFACE
- glEnable (GL_MULTISAMPLE);
-#endif
-
- /* The last time we drew to the surface, we were not using multisampling,
- so we need to blit from the non-multisampling framebuffer into the
- multisampling framebuffer. */
- ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER, surface->msaa_fb);
- ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER, surface->fb);
- ctx->dispatch.BlitFramebuffer (0, 0, surface->width, surface->height,
- 0, 0, surface->width, surface->height,
- GL_COLOR_BUFFER_BIT
-#if CAIRO_HAS_GL_SURFACE
- | GL_STENCIL_BUFFER_BIT
-#endif
- ,
- GL_NEAREST);
- ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->msaa_fb);
-
- if (stencil_test_enabled)
- glEnable (GL_STENCIL_TEST);
- if (scissor_test_enabled)
- glEnable (GL_SCISSOR_TEST);
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
- surface->content_in_texture = FALSE;
-}
-#endif
-
-#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV3_SURFACE
-static void
-bind_singlesample_framebuffer (cairo_gl_context_t *ctx,
- cairo_gl_surface_t *surface)
-{
- cairo_bool_t stencil_test_enabled;
- cairo_bool_t scissor_test_enabled;
-
- assert (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
- ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3);
- _cairo_gl_ensure_framebuffer (ctx, surface);
-
- if (! surface->msaa_active) {
-#if CAIRO_HAS_GL_SURFACE
- glDisable (GL_MULTISAMPLE);
-#endif
-
- ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
- return;
- }
-
- _cairo_gl_composite_flush (ctx);
-
- stencil_test_enabled = glIsEnabled (GL_STENCIL_TEST);
- scissor_test_enabled = glIsEnabled (GL_SCISSOR_TEST);
- glDisable (GL_STENCIL_TEST);
- glDisable (GL_SCISSOR_TEST);
-
-#if CAIRO_HAS_GL_SURFACE
- glDisable (GL_MULTISAMPLE);
-#endif
-
- /* The last time we drew to the surface, we were using multisampling,
- so we need to blit from the multisampling framebuffer into the
- non-multisampling framebuffer. */
- ctx->dispatch.BindFramebuffer (GL_DRAW_FRAMEBUFFER, surface->fb);
- ctx->dispatch.BindFramebuffer (GL_READ_FRAMEBUFFER, surface->msaa_fb);
- ctx->dispatch.BlitFramebuffer (0, 0, surface->width, surface->height,
- 0, 0, surface->width, surface->height,
- GL_COLOR_BUFFER_BIT, GL_NEAREST);
- ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
-
- if (stencil_test_enabled)
- glEnable (GL_STENCIL_TEST);
- if (scissor_test_enabled)
- glEnable (GL_SCISSOR_TEST);
-}
-#endif
-
-void
-_cairo_gl_context_bind_framebuffer (cairo_gl_context_t *ctx,
- cairo_gl_surface_t *surface,
- cairo_bool_t multisampling)
-{
- if (_cairo_gl_surface_is_texture (surface)) {
- /* OpenGL ES surfaces only have either a multisample framebuffer or a
- * singlesample framebuffer, so we cannot switch back and forth. */
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2) {
- _cairo_gl_ensure_framebuffer (ctx, surface);
- ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
- return;
- }
-
-#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV3_SURFACE
- if (multisampling)
- bind_multisample_framebuffer (ctx, surface);
- else
- bind_singlesample_framebuffer (ctx, surface);
-#endif
- } else {
- ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, 0);
-
-#if CAIRO_HAS_GL_SURFACE
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP) {
- if (multisampling)
- glEnable (GL_MULTISAMPLE);
- else
- glDisable (GL_MULTISAMPLE);
- }
-#endif
- }
-
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
- surface->msaa_active = multisampling;
-}
-
-void
-_cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
- cairo_gl_surface_t *surface,
- cairo_bool_t multisampling)
-{
- cairo_bool_t changing_surface, changing_sampling;
-
- /* The decision whether or not to use multisampling happens when
- * we create an OpenGL ES surface, so we can never switch modes. */
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2)
- multisampling = surface->msaa_active;
- /* For GLESV3, we always use renderbuffer for drawing */
- else if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
- multisampling = TRUE;
-
- changing_surface = ctx->current_target != surface || surface->needs_update;
- changing_sampling = (surface->msaa_active != multisampling ||
- surface->content_in_texture);
- if (! changing_surface && ! changing_sampling)
- return;
-
- if (! changing_surface) {
- _cairo_gl_composite_flush (ctx);
- _cairo_gl_context_bind_framebuffer (ctx, surface, multisampling);
- return;
- }
-
- _cairo_gl_composite_flush (ctx);
-
- ctx->current_target = surface;
- surface->needs_update = FALSE;
-
- if (! _cairo_gl_surface_is_texture (surface)) {
- ctx->make_current (ctx, surface);
- }
-
- _cairo_gl_context_bind_framebuffer (ctx, surface, multisampling);
-
- if (! _cairo_gl_surface_is_texture (surface)) {
-#if CAIRO_HAS_GL_SURFACE
- glDrawBuffer (GL_BACK_LEFT);
- glReadBuffer (GL_BACK_LEFT);
-#endif
- }
-
- glDisable (GL_DITHER);
- glViewport (0, 0, surface->width, surface->height);
-
- if (_cairo_gl_surface_is_texture (surface))
- _gl_identity_ortho (ctx->modelviewprojection_matrix,
- 0, surface->width, 0, surface->height);
- else
- _gl_identity_ortho (ctx->modelviewprojection_matrix,
- 0, surface->width, surface->height, 0);
-}
-
-void
-cairo_gl_device_set_thread_aware (cairo_device_t *device,
- cairo_bool_t thread_aware)
-{
- if (device->backend->type != CAIRO_DEVICE_TYPE_GL) {
- _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
- return;
- }
- ((cairo_gl_context_t *) device)->thread_aware = thread_aware;
-}
diff --git a/src/cairo-gl-dispatch-private.h b/src/cairo-gl-dispatch-private.h
deleted file mode 100644
index cabf76f0d..000000000
--- a/src/cairo-gl-dispatch-private.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2010 Linaro Limited
- *
- * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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.
- *
- * Contributor(s):
- * Alexandros Frantzis <alexandros.frantzis@linaro.org>
- */
-
-#ifndef CAIRO_GL_DISPATCH_PRIVATE_H
-#define CAIRO_GL_DISPATCH_PRIVATE_H
-
-#include "cairo-gl-private.h"
-#include <stddef.h>
-
-typedef enum _cairo_gl_dispatch_name {
- CAIRO_GL_DISPATCH_NAME_CORE,
- CAIRO_GL_DISPATCH_NAME_EXT,
- CAIRO_GL_DISPATCH_NAME_ES,
- CAIRO_GL_DISPATCH_NAME_COUNT
-} cairo_gl_dispatch_name_t;
-
-typedef struct _cairo_gl_dispatch_entry {
- const char *name[CAIRO_GL_DISPATCH_NAME_COUNT];
- size_t offset;
-} cairo_gl_dispatch_entry_t;
-
-#define DISPATCH_ENTRY_ARB(name) { { "gl"#name, "gl"#name"ARB", "gl"#name }, \
- offsetof(cairo_gl_dispatch_t, name) }
-#define DISPATCH_ENTRY_EXT(name) { { "gl"#name, "gl"#name"EXT", "gl"#name }, \
- offsetof(cairo_gl_dispatch_t, name) }
-#define DISPATCH_ENTRY_ARB_OES(name) { { "gl"#name, "gl"#name"ARB", "gl"#name"OES" }, \
- offsetof(cairo_gl_dispatch_t, name) }
-#define DISPATCH_ENTRY_EXT_IMG(name) { { "gl"#name, "gl"#name"EXT", "gl"#name"IMG" }, \
- offsetof(cairo_gl_dispatch_t, name) }
-#define DISPATCH_ENTRY_CUSTOM(name, name2) { { "gl"#name, "gl"#name2, "gl"#name }, \
- offsetof(cairo_gl_dispatch_t, name)}
-#define DISPATCH_ENTRY_LAST { { NULL, NULL, NULL }, 0 }
-
-cairo_private cairo_gl_dispatch_entry_t dispatch_buffers_entries[] = {
- DISPATCH_ENTRY_ARB (GenBuffers),
- DISPATCH_ENTRY_ARB (BindBuffer),
- DISPATCH_ENTRY_ARB (BufferData),
- DISPATCH_ENTRY_ARB_OES (MapBuffer),
- DISPATCH_ENTRY_ARB_OES (UnmapBuffer),
- DISPATCH_ENTRY_LAST
-};
-
-cairo_private cairo_gl_dispatch_entry_t dispatch_shaders_entries[] = {
- /* Shaders */
- DISPATCH_ENTRY_CUSTOM (CreateShader, CreateShaderObjectARB),
- DISPATCH_ENTRY_ARB (ShaderSource),
- DISPATCH_ENTRY_ARB (CompileShader),
- DISPATCH_ENTRY_CUSTOM (GetShaderiv, GetObjectParameterivARB),
- DISPATCH_ENTRY_CUSTOM (GetShaderInfoLog, GetInfoLogARB),
- DISPATCH_ENTRY_CUSTOM (DeleteShader, DeleteObjectARB),
-
- /* Programs */
- DISPATCH_ENTRY_CUSTOM (CreateProgram, CreateProgramObjectARB),
- DISPATCH_ENTRY_CUSTOM (AttachShader, AttachObjectARB),
- DISPATCH_ENTRY_CUSTOM (DeleteProgram, DeleteObjectARB),
- DISPATCH_ENTRY_ARB (LinkProgram),
- DISPATCH_ENTRY_CUSTOM (UseProgram, UseProgramObjectARB),
- DISPATCH_ENTRY_CUSTOM (GetProgramiv, GetObjectParameterivARB),
- DISPATCH_ENTRY_CUSTOM (GetProgramInfoLog, GetInfoLogARB),
-
- /* Uniforms */
- DISPATCH_ENTRY_ARB (GetUniformLocation),
- DISPATCH_ENTRY_ARB (Uniform1f),
- DISPATCH_ENTRY_ARB (Uniform2f),
- DISPATCH_ENTRY_ARB (Uniform3f),
- DISPATCH_ENTRY_ARB (Uniform4f),
- DISPATCH_ENTRY_ARB (UniformMatrix3fv),
- DISPATCH_ENTRY_ARB (UniformMatrix4fv),
- DISPATCH_ENTRY_ARB (Uniform1i),
-
- /* Attributes */
- DISPATCH_ENTRY_ARB (BindAttribLocation),
- DISPATCH_ENTRY_ARB (VertexAttribPointer),
- DISPATCH_ENTRY_ARB (EnableVertexAttribArray),
- DISPATCH_ENTRY_ARB (DisableVertexAttribArray),
-
- DISPATCH_ENTRY_LAST
-};
-
-cairo_private cairo_gl_dispatch_entry_t dispatch_fbo_entries[] = {
- DISPATCH_ENTRY_EXT (GenFramebuffers),
- DISPATCH_ENTRY_EXT (BindFramebuffer),
- DISPATCH_ENTRY_EXT (FramebufferTexture2D),
- DISPATCH_ENTRY_EXT (CheckFramebufferStatus),
- DISPATCH_ENTRY_EXT (DeleteFramebuffers),
- DISPATCH_ENTRY_EXT (GenRenderbuffers),
- DISPATCH_ENTRY_EXT (BindRenderbuffer),
- DISPATCH_ENTRY_EXT (RenderbufferStorage),
- DISPATCH_ENTRY_EXT (FramebufferRenderbuffer),
- DISPATCH_ENTRY_EXT (DeleteRenderbuffers),
- DISPATCH_ENTRY_EXT (BlitFramebuffer),
- DISPATCH_ENTRY_LAST
-};
-
-cairo_private cairo_gl_dispatch_entry_t dispatch_multisampling_entries[] = {
- DISPATCH_ENTRY_EXT_IMG (RenderbufferStorageMultisample),
- DISPATCH_ENTRY_EXT_IMG (FramebufferTexture2DMultisample),
- DISPATCH_ENTRY_LAST
-};
-
-#endif /* CAIRO_GL_DISPATCH_PRIVATE_H */
diff --git a/src/cairo-gl-dispatch.c b/src/cairo-gl-dispatch.c
deleted file mode 100644
index a49199dbb..000000000
--- a/src/cairo-gl-dispatch.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2010 Linaro Limited
- *
- * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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.
- *
- * Contributor(s):
- * Alexandros Frantzis <alexandros.frantzis@linaro.org>
- */
-
-#include "cairoint.h"
-#include "cairo-gl-private.h"
-#include "cairo-gl-dispatch-private.h"
-#if CAIRO_HAS_DLSYM
-#include <dlfcn.h>
-#endif
-
-#if CAIRO_HAS_DLSYM
-static void *
-_cairo_gl_dispatch_open_lib (void)
-{
- return dlopen (NULL, RTLD_LAZY);
-}
-
-static void
-_cairo_gl_dispatch_close_lib (void *handle)
-{
- dlclose (handle);
-}
-
-static cairo_gl_generic_func_t
-_cairo_gl_dispatch_get_proc_addr (void *handle, const char *name)
-{
- return (cairo_gl_generic_func_t) dlsym (handle, name);
-}
-#else
-static void *
-_cairo_gl_dispatch_open_lib (void)
-{
- return NULL;
-}
-
-static void
-_cairo_gl_dispatch_close_lib (void *handle)
-{
- return;
-}
-
-static cairo_gl_generic_func_t
-_cairo_gl_dispatch_get_proc_addr (void *handle, const char *name)
-{
- return NULL;
-}
-#endif /* CAIRO_HAS_DLSYM */
-
-
-static void
-_cairo_gl_dispatch_init_entries (cairo_gl_dispatch_t *dispatch,
- cairo_gl_get_proc_addr_func_t get_proc_addr,
- cairo_gl_dispatch_entry_t *entries,
- cairo_gl_dispatch_name_t dispatch_name)
-{
- cairo_gl_dispatch_entry_t *entry = entries;
- void *handle = _cairo_gl_dispatch_open_lib ();
-
- while (entry->name[CAIRO_GL_DISPATCH_NAME_CORE] != NULL) {
- void *dispatch_ptr = &((char *) dispatch)[entry->offset];
- const char *name = entry->name[dispatch_name];
-
- /*
- * In strictly conforming EGL implementations, eglGetProcAddress() can
- * be used only to get extension functions, but some of the functions
- * we want belong to core GL(ES). If the *GetProcAddress function
- * provided by the context fails, try to get the address of the wanted
- * GL function using standard system facilities (eg dlsym() in *nix
- * systems).
- */
- cairo_gl_generic_func_t func = get_proc_addr (name);
- if (func == NULL)
- func = _cairo_gl_dispatch_get_proc_addr (handle, name);
-
- *((cairo_gl_generic_func_t *) dispatch_ptr) = func;
-
- ++entry;
- }
-
- _cairo_gl_dispatch_close_lib (handle);
-}
-
-static cairo_status_t
-_cairo_gl_dispatch_init_buffers (cairo_gl_dispatch_t *dispatch,
- cairo_gl_get_proc_addr_func_t get_proc_addr,
- int gl_version, cairo_gl_flavor_t gl_flavor)
-{
- cairo_gl_dispatch_name_t dispatch_name;
-
- if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
- {
- if (gl_version >= CAIRO_GL_VERSION_ENCODE (1, 5))
- dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
- else if (_cairo_gl_has_extension ("GL_ARB_vertex_buffer_object"))
- dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT;
- else
- return CAIRO_STATUS_DEVICE_ERROR;
- }
- else if (gl_flavor == CAIRO_GL_FLAVOR_ES3)
- {
- dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
- }
- else if (gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
- gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
- {
- dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
- }
- else
- {
- return CAIRO_STATUS_DEVICE_ERROR;
- }
-
- _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr,
- dispatch_buffers_entries, dispatch_name);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_dispatch_init_shaders (cairo_gl_dispatch_t *dispatch,
- cairo_gl_get_proc_addr_func_t get_proc_addr,
- int gl_version, cairo_gl_flavor_t gl_flavor)
-{
- cairo_gl_dispatch_name_t dispatch_name;
-
- if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
- {
- if (gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
- dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
- else if (_cairo_gl_has_extension ("GL_ARB_shader_objects"))
- dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT;
- else
- return CAIRO_STATUS_DEVICE_ERROR;
- }
- else if (gl_flavor == CAIRO_GL_FLAVOR_ES3)
- {
- dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
- }
- else if (gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
- gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
- {
- dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
- }
- else
- {
- return CAIRO_STATUS_DEVICE_ERROR;
- }
-
- _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr,
- dispatch_shaders_entries, dispatch_name);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_dispatch_init_fbo (cairo_gl_dispatch_t *dispatch,
- cairo_gl_get_proc_addr_func_t get_proc_addr,
- int gl_version, cairo_gl_flavor_t gl_flavor)
-{
- cairo_gl_dispatch_name_t dispatch_name;
-
- if (gl_flavor == CAIRO_GL_FLAVOR_DESKTOP)
- {
- if (gl_version >= CAIRO_GL_VERSION_ENCODE (3, 0) ||
- _cairo_gl_has_extension ("GL_ARB_framebuffer_object"))
- dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
- else if (_cairo_gl_has_extension ("GL_EXT_framebuffer_object"))
- dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT;
- else
- return CAIRO_STATUS_DEVICE_ERROR;
- }
- else if (gl_flavor == CAIRO_GL_FLAVOR_ES3)
- {
- dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
- }
- else if (gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
- gl_version >= CAIRO_GL_VERSION_ENCODE (2, 0))
- {
- dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
- }
- else
- {
- return CAIRO_STATUS_DEVICE_ERROR;
- }
-
- _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr,
- dispatch_fbo_entries, dispatch_name);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_dispatch_init_multisampling (cairo_gl_dispatch_t *dispatch,
- cairo_gl_get_proc_addr_func_t get_proc_addr,
- int gl_version,
- cairo_gl_flavor_t gl_flavor)
-{
- /* For the multisampling table, there are two GLES versions of the
- * extension, so we put one in the EXT slot and one in the real ES slot.*/
- cairo_gl_dispatch_name_t dispatch_name = CAIRO_GL_DISPATCH_NAME_CORE;
- if (gl_flavor == CAIRO_GL_FLAVOR_ES2) {
- if (_cairo_gl_has_extension ("GL_EXT_multisampled_render_to_texture"))
- dispatch_name = CAIRO_GL_DISPATCH_NAME_EXT;
- else if (_cairo_gl_has_extension ("GL_IMG_multisampled_render_to_texture"))
- dispatch_name = CAIRO_GL_DISPATCH_NAME_ES;
- }
- _cairo_gl_dispatch_init_entries (dispatch, get_proc_addr,
- dispatch_multisampling_entries,
- dispatch_name);
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_status_t
-_cairo_gl_dispatch_init (cairo_gl_dispatch_t *dispatch,
- cairo_gl_get_proc_addr_func_t get_proc_addr)
-{
- cairo_status_t status;
- int gl_version;
- cairo_gl_flavor_t gl_flavor;
-
- gl_version = _cairo_gl_get_version ();
- gl_flavor = _cairo_gl_get_flavor ();
-
- status = _cairo_gl_dispatch_init_buffers (dispatch, get_proc_addr,
- gl_version, gl_flavor);
- if (status != CAIRO_STATUS_SUCCESS)
- return status;
-
- status = _cairo_gl_dispatch_init_shaders (dispatch, get_proc_addr,
- gl_version, gl_flavor);
- if (status != CAIRO_STATUS_SUCCESS)
- return status;
-
- status = _cairo_gl_dispatch_init_fbo (dispatch, get_proc_addr,
- gl_version, gl_flavor);
- if (status != CAIRO_STATUS_SUCCESS)
- return status;
-
- status = _cairo_gl_dispatch_init_multisampling (dispatch, get_proc_addr,
- gl_version, gl_flavor);
- if (status != CAIRO_STATUS_SUCCESS)
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
diff --git a/src/cairo-gl-ext-def-private.h b/src/cairo-gl-ext-def-private.h
deleted file mode 100644
index a261947be..000000000
--- a/src/cairo-gl-ext-def-private.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2010 Linaro Limited
- *
- * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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.
- *
- * Contributor(s):
- * Alexandros Frantzis <alexandros.frantzis@linaro.org>
- */
-
-#ifndef CAIRO_GL_EXT_DEF_PRIVATE_H
-#define CAIRO_GL_EXT_DEF_PRIVATE_H
-
-#ifndef GL_TEXTURE_RECTANGLE
-#define GL_TEXTURE_RECTANGLE 0x84F5
-#endif
-
-#ifndef GL_ARRAY_BUFFER
-#define GL_ARRAY_BUFFER 0x8892
-#endif
-
-#ifndef GL_STREAM_DRAW
-#define GL_STREAM_DRAW 0x88E0
-#endif
-
-#ifndef GL_WRITE_ONLY
-#define GL_WRITE_ONLY 0x88B9
-#endif
-
-#ifndef GL_PIXEL_UNPACK_BUFFER
-#define GL_PIXEL_UNPACK_BUFFER 0x88EC
-#endif
-
-#ifndef GL_FRAMEBUFFER
-#define GL_FRAMEBUFFER 0x8D40
-#endif
-
-#ifndef GL_COLOR_ATTACHMENT0
-#define GL_COLOR_ATTACHMENT0 0x8CE0
-#endif
-
-#ifndef GL_FRAMEBUFFER_COMPLETE
-#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
-#endif
-
-#ifndef GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
-#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
-#endif
-
-#ifndef GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
-#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
-#endif
-
-#ifndef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
-#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
-#endif
-
-#ifndef GL_FRAMEBUFFER_INCOMPLETE_FORMATS
-#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS 0x8CDA
-#endif
-
-#ifndef GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER
-#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB
-#endif
-
-#ifndef GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER
-#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC
-#endif
-
-#ifndef GL_FRAMEBUFFER_UNSUPPORTED
-#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
-#endif
-
-#ifndef GL_PACK_INVERT_MESA
-#define GL_PACK_INVERT_MESA 0x8758
-#endif
-
-#ifndef GL_CLAMP_TO_BORDER
-#define GL_CLAMP_TO_BORDER 0x812D
-#endif
-
-#ifndef GL_BGR
-#define GL_BGR 0x80E0
-#endif
-
-#ifndef GL_BGRA
-#define GL_BGRA 0x80E1
-#endif
-
-#ifndef GL_RGBA8
-#define GL_RGBA8 0x8058
-#endif
-
-#ifndef GL_UNSIGNED_INT_8_8_8_8
-#define GL_UNSIGNED_INT_8_8_8_8 0x8035
-#endif
-
-#ifndef GL_UNSIGNED_SHORT_5_6_5_REV
-#define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364
-#endif
-
-#ifndef GL_UNSIGNED_SHORT_1_5_5_5_REV
-#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
-#endif
-
-#ifndef GL_UNSIGNED_INT_8_8_8_8_REV
-#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
-#endif
-
-#ifndef GL_PACK_ROW_LENGTH
-#define GL_PACK_ROW_LENGTH 0x0D02
-#endif
-
-#ifndef GL_UNPACK_ROW_LENGTH
-#define GL_UNPACK_ROW_LENGTH 0x0CF2
-#endif
-
-#ifndef GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE
-#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56
-#endif
-
-#endif /* CAIRO_GL_EXT_DEF_PRIVATE_H */
diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
deleted file mode 100644
index f6f5ec096..000000000
--- a/src/cairo-gl-glyphs.c
+++ /dev/null
@@ -1,507 +0,0 @@
-/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
-/* Cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 Chris Wilson
- * Copyright © 2010 Intel Corporation
- * Copyright © 2010 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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.
- *
- * Contributors:
- * Benjamin Otte <otte@gnome.org>
- * Chris Wilson <chris@chris-wilson.co.uk>
- */
-
-#include "cairoint.h"
-
-#include "cairo-gl-private.h"
-
-#include "cairo-compositor-private.h"
-#include "cairo-composite-rectangles-private.h"
-#include "cairo-error-private.h"
-#include "cairo-image-surface-private.h"
-#include "cairo-rtree-private.h"
-
-#define GLYPH_CACHE_WIDTH 1024
-#define GLYPH_CACHE_HEIGHT 1024
-#define GLYPH_CACHE_MIN_SIZE 4
-#define GLYPH_CACHE_MAX_SIZE 128
-
-typedef struct _cairo_gl_glyph {
- cairo_rtree_node_t node;
- cairo_scaled_glyph_private_t base;
- cairo_scaled_glyph_t *glyph;
- cairo_gl_glyph_cache_t *cache;
- struct { float x, y; } p1, p2;
-} cairo_gl_glyph_t;
-
-static void
-_cairo_gl_node_destroy (cairo_rtree_node_t *node)
-{
- cairo_gl_glyph_t *priv = cairo_container_of (node, cairo_gl_glyph_t, node);
- cairo_scaled_glyph_t *glyph;
-
- glyph = priv->glyph;
- if (glyph == NULL)
- return;
-
- if (glyph->dev_private_key == priv->cache) {
- glyph->dev_private = NULL;
- glyph->dev_private_key = NULL;
- }
- cairo_list_del (&priv->base.link);
- priv->glyph = NULL;
-}
-
-static void
-_cairo_gl_glyph_fini (cairo_scaled_glyph_private_t *glyph_private,
- cairo_scaled_glyph_t *scaled_glyph,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_gl_glyph_t *priv = cairo_container_of (glyph_private,
- cairo_gl_glyph_t,
- base);
-
- assert (priv->glyph);
-
- _cairo_gl_node_destroy (&priv->node);
-
- /* XXX thread-safety? Probably ok due to the frozen scaled-font. */
- if (! priv->node.pinned)
- _cairo_rtree_node_remove (&priv->cache->rtree, &priv->node);
-
- assert (priv->glyph == NULL);
-}
-
-static cairo_int_status_t
-_cairo_gl_glyph_cache_add_glyph (cairo_gl_context_t *ctx,
- cairo_gl_glyph_cache_t *cache,
- cairo_scaled_glyph_t *scaled_glyph)
-{
- cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
- cairo_gl_glyph_t *glyph_private;
- cairo_rtree_node_t *node = NULL;
- cairo_int_status_t status;
- int width, height;
-
- width = glyph_surface->width;
- if (width < GLYPH_CACHE_MIN_SIZE)
- width = GLYPH_CACHE_MIN_SIZE;
- height = glyph_surface->height;
- if (height < GLYPH_CACHE_MIN_SIZE)
- height = GLYPH_CACHE_MIN_SIZE;
-
- /* search for an available slot */
- status = _cairo_rtree_insert (&cache->rtree, width, height, &node);
- /* search for an unlocked slot */
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- status = _cairo_rtree_evict_random (&cache->rtree,
- width, height, &node);
- if (status == CAIRO_INT_STATUS_SUCCESS) {
- status = _cairo_rtree_node_insert (&cache->rtree,
- node, width, height, &node);
- }
- }
- if (status)
- return status;
-
- /* XXX: Make sure we use the mask texture. This should work automagically somehow */
- glActiveTexture (GL_TEXTURE1);
- status = _cairo_gl_surface_draw_image (cache->surface, glyph_surface,
- 0, 0,
- glyph_surface->width, glyph_surface->height,
- node->x, node->y, FALSE);
- if (unlikely (status))
- return status;
-
- glyph_private = (cairo_gl_glyph_t *) node;
- glyph_private->cache = cache;
- glyph_private->glyph = scaled_glyph;
- _cairo_scaled_glyph_attach_private (scaled_glyph,
- &glyph_private->base,
- cache,
- _cairo_gl_glyph_fini);
-
- scaled_glyph->dev_private = glyph_private;
- scaled_glyph->dev_private_key = cache;
-
- /* compute tex coords */
- glyph_private->p1.x = node->x;
- glyph_private->p1.y = node->y;
- glyph_private->p2.x = node->x + glyph_surface->width;
- glyph_private->p2.y = node->y + glyph_surface->height;
- if (! _cairo_gl_device_requires_power_of_two_textures (&ctx->base)) {
- glyph_private->p1.x /= GLYPH_CACHE_WIDTH;
- glyph_private->p2.x /= GLYPH_CACHE_WIDTH;
- glyph_private->p1.y /= GLYPH_CACHE_HEIGHT;
- glyph_private->p2.y /= GLYPH_CACHE_HEIGHT;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_gl_glyph_t *
-_cairo_gl_glyph_cache_lock (cairo_gl_glyph_cache_t *cache,
- cairo_scaled_glyph_t *scaled_glyph)
-{
- return _cairo_rtree_pin (&cache->rtree, scaled_glyph->dev_private);
-}
-
-static cairo_status_t
-cairo_gl_context_get_glyph_cache (cairo_gl_context_t *ctx,
- cairo_format_t format,
- cairo_gl_glyph_cache_t **cache_out)
-{
- cairo_gl_glyph_cache_t *cache;
- cairo_content_t content;
-
- switch (format) {
- case CAIRO_FORMAT_RGBA128F:
- case CAIRO_FORMAT_RGB96F:
- case CAIRO_FORMAT_RGB30:
- case CAIRO_FORMAT_RGB16_565:
- case CAIRO_FORMAT_ARGB32:
- case CAIRO_FORMAT_RGB24:
- cache = &ctx->glyph_cache[0];
- content = CAIRO_CONTENT_COLOR_ALPHA;
- break;
- case CAIRO_FORMAT_A8:
- case CAIRO_FORMAT_A1:
- cache = &ctx->glyph_cache[1];
- content = CAIRO_CONTENT_ALPHA;
- break;
- default:
- case CAIRO_FORMAT_INVALID:
- ASSERT_NOT_REACHED;
- return _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
- }
-
- if (unlikely (cache->surface == NULL)) {
- cairo_surface_t *surface;
-
- surface = _cairo_gl_surface_create_scratch_for_caching (ctx,
- content,
- GLYPH_CACHE_WIDTH,
- GLYPH_CACHE_HEIGHT);
- if (unlikely (surface->status))
- return surface->status;
-
- _cairo_surface_release_device_reference (surface);
-
- cache->surface = (cairo_gl_surface_t *)surface;
- cache->surface->operand.texture.attributes.has_component_alpha =
- content == CAIRO_CONTENT_COLOR_ALPHA;
- }
-
- *cache_out = cache;
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-render_glyphs (cairo_gl_surface_t *dst,
- int dst_x, int dst_y,
- cairo_operator_t op,
- cairo_surface_t *source,
- cairo_composite_glyphs_info_t *info,
- cairo_bool_t *has_component_alpha,
- cairo_clip_t *clip)
-{
- cairo_format_t last_format = CAIRO_FORMAT_INVALID;
- cairo_gl_glyph_cache_t *cache = NULL;
- cairo_gl_context_t *ctx;
- cairo_gl_emit_glyph_t emit = NULL;
- cairo_gl_composite_t setup;
- cairo_int_status_t status;
- int i = 0;
-
- TRACE ((stderr, "%s (%d, %d)x(%d, %d)\n", __FUNCTION__,
- info->extents.x, info->extents.y,
- info->extents.width, info->extents.height));
-
- *has_component_alpha = FALSE;
-
- status = _cairo_gl_context_acquire (dst->base.device, &ctx);
- if (unlikely (status))
- return status;
-
- status = _cairo_gl_composite_init (&setup, op, dst, TRUE);
- if (unlikely (status))
- goto FINISH;
-
- if (source == NULL) {
- _cairo_gl_composite_set_solid_source (&setup, CAIRO_COLOR_WHITE);
- } else {
- _cairo_gl_composite_set_source_operand (&setup,
- source_to_operand (source));
-
- }
-
- _cairo_gl_composite_set_clip (&setup, clip);
-
- for (i = 0; i < info->num_glyphs; i++) {
- cairo_scaled_glyph_t *scaled_glyph;
- cairo_gl_glyph_t *glyph;
- double x_offset, y_offset;
- double x1, x2, y1, y2;
-
- status = _cairo_scaled_glyph_lookup (info->font,
- info->glyphs[i].index,
- CAIRO_SCALED_GLYPH_INFO_SURFACE,
- NULL, /* foreground color */
- &scaled_glyph);
- if (unlikely (status))
- goto FINISH;
-
- if (scaled_glyph->surface->width == 0 ||
- scaled_glyph->surface->height == 0)
- {
- continue;
- }
- if (scaled_glyph->surface->format != last_format) {
- status = cairo_gl_context_get_glyph_cache (ctx,
- scaled_glyph->surface->format,
- &cache);
- if (unlikely (status))
- goto FINISH;
-
- last_format = scaled_glyph->surface->format;
-
- _cairo_gl_composite_set_mask_operand (&setup, &cache->surface->operand);
- *has_component_alpha |= cache->surface->operand.texture.attributes.has_component_alpha;
-
- /* XXX Shoot me. */
- status = _cairo_gl_composite_begin (&setup, &ctx);
- status = _cairo_gl_context_release (ctx, status);
- if (unlikely (status))
- goto FINISH;
-
- emit = _cairo_gl_context_choose_emit_glyph (ctx);
- }
-
- if (scaled_glyph->dev_private_key != cache) {
- cairo_scaled_glyph_private_t *priv;
-
- priv = _cairo_scaled_glyph_find_private (scaled_glyph, cache);
- if (priv) {
- scaled_glyph->dev_private_key = cache;
- scaled_glyph->dev_private = cairo_container_of (priv,
- cairo_gl_glyph_t,
- base);
- } else {
- status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
-
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- /* Cache is full, so flush existing prims and try again. */
- _cairo_gl_composite_flush (ctx);
- _cairo_gl_glyph_cache_unlock (cache);
- status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
- }
-
- if (unlikely (_cairo_int_status_is_error (status)))
- goto FINISH;
- }
- }
-
- x_offset = scaled_glyph->surface->base.device_transform.x0;
- y_offset = scaled_glyph->surface->base.device_transform.y0;
-
- x1 = _cairo_lround (info->glyphs[i].x - x_offset - dst_x);
- y1 = _cairo_lround (info->glyphs[i].y - y_offset - dst_y);
- x2 = x1 + scaled_glyph->surface->width;
- y2 = y1 + scaled_glyph->surface->height;
-
- glyph = _cairo_gl_glyph_cache_lock (cache, scaled_glyph);
- assert (emit);
- emit (ctx,
- x1, y1, x2, y2,
- glyph->p1.x, glyph->p1.y,
- glyph->p2.x, glyph->p2.y);
- }
-
- status = CAIRO_STATUS_SUCCESS;
- FINISH:
- status = _cairo_gl_context_release (ctx, status);
-
- _cairo_gl_composite_fini (&setup);
- return status;
-}
-
-static cairo_int_status_t
-render_glyphs_via_mask (cairo_gl_surface_t *dst,
- int dst_x, int dst_y,
- cairo_operator_t op,
- cairo_surface_t *source,
- cairo_composite_glyphs_info_t *info,
- cairo_clip_t *clip)
-{
- cairo_surface_t *mask;
- cairo_status_t status;
- cairo_bool_t has_component_alpha;
-
- TRACE ((stderr, "%s\n", __FUNCTION__));
-
- /* XXX: For non-CA, this should be CAIRO_CONTENT_ALPHA to save memory */
- mask = cairo_gl_surface_create (dst->base.device,
- CAIRO_CONTENT_COLOR_ALPHA,
- info->extents.width,
- info->extents.height);
- if (unlikely (mask->status))
- return mask->status;
-
- status = render_glyphs ((cairo_gl_surface_t *) mask,
- info->extents.x, info->extents.y,
- CAIRO_OPERATOR_ADD, NULL,
- info, &has_component_alpha, NULL);
- if (likely (status == CAIRO_STATUS_SUCCESS)) {
- cairo_surface_pattern_t mask_pattern;
- cairo_surface_pattern_t source_pattern;
- cairo_rectangle_int_t clip_extents;
-
- mask->is_clear = FALSE;
- _cairo_pattern_init_for_surface (&mask_pattern, mask);
- mask_pattern.base.has_component_alpha = has_component_alpha;
- mask_pattern.base.filter = CAIRO_FILTER_NEAREST;
- mask_pattern.base.extend = CAIRO_EXTEND_NONE;
-
- cairo_matrix_init_translate (&mask_pattern.base.matrix,
- dst_x-info->extents.x, dst_y-info->extents.y);
-
- _cairo_pattern_init_for_surface (&source_pattern, source);
- cairo_matrix_init_translate (&source_pattern.base.matrix,
- dst_x-info->extents.x, dst_y-info->extents.y);
-
- clip = _cairo_clip_copy (clip);
- clip_extents.x = info->extents.x - dst_x;
- clip_extents.y = info->extents.y - dst_y;
- clip_extents.width = info->extents.width;
- clip_extents.height = info->extents.height;
- clip = _cairo_clip_intersect_rectangle (clip, &clip_extents);
-
- status = _cairo_surface_mask (&dst->base, op,
- &source_pattern.base,
- &mask_pattern.base,
- clip);
-
- _cairo_clip_destroy (clip);
-
- _cairo_pattern_fini (&mask_pattern.base);
- _cairo_pattern_fini (&source_pattern.base);
- }
-
- cairo_surface_destroy (mask);
-
- return status;
-}
-
-cairo_int_status_t
-_cairo_gl_check_composite_glyphs (const cairo_composite_rectangles_t *extents,
- cairo_scaled_font_t *scaled_font,
- cairo_glyph_t *glyphs,
- int *num_glyphs)
-{
- if (! _cairo_gl_operator_is_supported (extents->op))
- return UNSUPPORTED ("unsupported operator");
-
- /* XXX use individual masks for large glyphs? */
- if (ceil (scaled_font->max_scale) >= GLYPH_CACHE_MAX_SIZE)
- return UNSUPPORTED ("glyphs too large");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_int_status_t
-_cairo_gl_composite_glyphs_with_clip (void *_dst,
- cairo_operator_t op,
- cairo_surface_t *_src,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- cairo_composite_glyphs_info_t *info,
- cairo_clip_t *clip)
-{
- cairo_gl_surface_t *dst = _dst;
- cairo_bool_t has_component_alpha;
-
- TRACE ((stderr, "%s\n", __FUNCTION__));
-
- /* If any of the glyphs require component alpha, we have to go through
- * a mask, since only _cairo_gl_surface_composite() currently supports
- * component alpha.
- */
- if (!dst->base.is_clear && ! info->use_mask && op != CAIRO_OPERATOR_OVER &&
- (info->font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL ||
- info->font->options.antialias == CAIRO_ANTIALIAS_BEST))
- {
- info->use_mask = TRUE;
- }
-
- if (info->use_mask) {
- return render_glyphs_via_mask (dst, dst_x, dst_y,
- op, _src, info, clip);
- } else {
- return render_glyphs (dst, dst_x, dst_y,
- op, _src, info,
- &has_component_alpha,
- clip);
- }
-
-}
-
-cairo_int_status_t
-_cairo_gl_composite_glyphs (void *_dst,
- cairo_operator_t op,
- cairo_surface_t *_src,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- cairo_composite_glyphs_info_t *info)
-{
- return _cairo_gl_composite_glyphs_with_clip (_dst, op, _src, src_x, src_y,
- dst_x, dst_y, info, NULL);
-}
-
-void
-_cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache)
-{
- _cairo_rtree_init (&cache->rtree,
- GLYPH_CACHE_WIDTH,
- GLYPH_CACHE_HEIGHT,
- GLYPH_CACHE_MIN_SIZE,
- sizeof (cairo_gl_glyph_t),
- _cairo_gl_node_destroy);
-}
-
-void
-_cairo_gl_glyph_cache_fini (cairo_gl_context_t *ctx,
- cairo_gl_glyph_cache_t *cache)
-{
- _cairo_rtree_fini (&cache->rtree);
- cairo_surface_destroy (&cache->surface->base);
-}
diff --git a/src/cairo-gl-gradient-private.h b/src/cairo-gl-gradient-private.h
deleted file mode 100644
index 0d9f41f54..000000000
--- a/src/cairo-gl-gradient-private.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 Eric Anholt
- * Copyright © 2009 Chris Wilson
- * Copyright © 2005,2010 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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):
- * Benjamin Otte <otte@gnome.org>
- * Carl Worth <cworth@cworth.org>
- * Chris Wilson <chris@chris-wilson.co.uk>
- * Eric Anholt <eric@anholt.net>
- */
-
-#ifndef CAIRO_GL_GRADIENT_PRIVATE_H
-#define CAIRO_GL_GRADIENT_PRIVATE_H
-
-#define GL_GLEXT_PROTOTYPES
-
-#include "cairo-cache-private.h"
-#include "cairo-device-private.h"
-#include "cairo-reference-count-private.h"
-#include "cairo-pattern-private.h"
-#include "cairo-types-private.h"
-
-#include "cairo-gl.h"
-
-#if CAIRO_HAS_GLESV3_SURFACE
-#include <GLES3/gl3.h>
-#include <GLES3/gl3ext.h>
-#elif CAIRO_HAS_GLESV2_SURFACE
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#elif CAIRO_HAS_GL_SURFACE
-#include <GL/gl.h>
-#include <GL/glext.h>
-#endif
-
-#define CAIRO_GL_GRADIENT_CACHE_SIZE 4096
-
-/* XXX: Declare in a better place */
-typedef struct _cairo_gl_context cairo_gl_context_t;
-
-typedef struct _cairo_gl_gradient {
- cairo_cache_entry_t cache_entry;
- cairo_reference_count_t ref_count;
- cairo_device_t *device; /* NB: we don't hold a reference */
- GLuint tex;
- unsigned int n_stops;
- const cairo_gradient_stop_t *stops;
- cairo_gradient_stop_t stops_embedded[1];
-} cairo_gl_gradient_t;
-
-cairo_private cairo_int_status_t
-_cairo_gl_gradient_create (cairo_gl_context_t *ctx,
- unsigned int n_stops,
- const cairo_gradient_stop_t *stops,
- cairo_gl_gradient_t **gradient_out);
-
-cairo_private_no_warn cairo_gl_gradient_t *
-_cairo_gl_gradient_reference (cairo_gl_gradient_t *gradient);
-
-cairo_private void
-_cairo_gl_gradient_destroy (cairo_gl_gradient_t *gradient);
-
-cairo_private cairo_bool_t
-_cairo_gl_gradient_equal (const void *key_a, const void *key_b);
-
-
-#endif /* CAIRO_GL_GRADIENT_PRIVATE_H */
diff --git a/src/cairo-gl-gradient.c b/src/cairo-gl-gradient.c
deleted file mode 100644
index 293d4e30e..000000000
--- a/src/cairo-gl-gradient.c
+++ /dev/null
@@ -1,339 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 Eric Anholt
- * Copyright © 2009 Chris Wilson
- * Copyright © 2005,2010 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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):
- * Benjamin Otte <otte@gnome.org>
- * Carl Worth <cworth@cworth.org>
- * Chris Wilson <chris@chris-wilson.co.uk>
- * Eric Anholt <eric@anholt.net>
- */
-
-#include "cairoint.h"
-#include <stdint.h>
-#include "cairo-error-private.h"
-#include "cairo-gl-gradient-private.h"
-#include "cairo-gl-private.h"
-
-
-static int
-_cairo_gl_gradient_sample_width (unsigned int n_stops,
- const cairo_gradient_stop_t *stops)
-{
- unsigned int n;
- int width;
-
- width = 8;
- for (n = 1; n < n_stops; n++) {
- double dx = stops[n].offset - stops[n-1].offset;
- double delta, max;
- int ramp;
-
- if (dx == 0)
- return 1024; /* we need to emulate an infinitely sharp step */
-
- max = fabs (stops[n].color.red - stops[n-1].color.red);
-
- delta = fabs (stops[n].color.green - stops[n-1].color.green);
- if (delta > max)
- max = delta;
-
- delta = fabs (stops[n].color.blue - stops[n-1].color.blue);
- if (delta > max)
- max = delta;
-
- delta = fabs (stops[n].color.alpha - stops[n-1].color.alpha);
- if (delta > max)
- max = delta;
-
- ramp = 128 * max / dx;
- if (ramp > width)
- width = ramp;
- }
-
- return (width + 7) & -8;
-}
-
-static uint8_t premultiply(double c, double a)
-{
- int v = c * a * 256;
- return v - (v >> 8);
-}
-
-static uint32_t color_stop_to_pixel(const cairo_gradient_stop_t *stop)
-{
- uint8_t a, r, g, b;
-
- a = stop->color.alpha_short >> 8;
- r = premultiply(stop->color.red, stop->color.alpha);
- g = premultiply(stop->color.green, stop->color.alpha);
- b = premultiply(stop->color.blue, stop->color.alpha);
-
- if (_cairo_is_little_endian ())
- return (uint32_t)a << 24 | r << 16 | g << 8 | b << 0;
- else
- return a << 0 | r << 8 | g << 16 | (uint32_t)b << 24;
-}
-
-static cairo_status_t
-_cairo_gl_gradient_render (const cairo_gl_context_t *ctx,
- unsigned int n_stops,
- const cairo_gradient_stop_t *stops,
- void *bytes,
- int width)
-{
- pixman_image_t *gradient, *image;
- pixman_gradient_stop_t pixman_stops_stack[32];
- pixman_gradient_stop_t *pixman_stops;
- pixman_point_fixed_t p1, p2;
- unsigned int i;
- pixman_format_code_t gradient_pixman_format;
-
- /*
- * Ensure that the order of the gradient's components in memory is BGRA.
- * This is done so that the gradient's pixel data is always suitable for
- * texture upload using format=GL_BGRA and type=GL_UNSIGNED_BYTE.
- */
- if (_cairo_is_little_endian ())
- gradient_pixman_format = PIXMAN_a8r8g8b8;
- else
- gradient_pixman_format = PIXMAN_b8g8r8a8;
-
- pixman_stops = pixman_stops_stack;
- if (unlikely (n_stops > ARRAY_LENGTH (pixman_stops_stack))) {
- pixman_stops = _cairo_malloc_ab (n_stops,
- sizeof (pixman_gradient_stop_t));
- if (unlikely (pixman_stops == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- for (i = 0; i < n_stops; i++) {
- pixman_stops[i].x = _cairo_fixed_16_16_from_double (stops[i].offset);
- pixman_stops[i].color.red = stops[i].color.red_short;
- pixman_stops[i].color.green = stops[i].color.green_short;
- pixman_stops[i].color.blue = stops[i].color.blue_short;
- pixman_stops[i].color.alpha = stops[i].color.alpha_short;
- }
-
- p1.x = _cairo_fixed_16_16_from_double (0.5);
- p1.y = 0;
- p2.x = _cairo_fixed_16_16_from_double (width - 0.5);
- p2.y = 0;
-
- gradient = pixman_image_create_linear_gradient (&p1, &p2,
- pixman_stops,
- n_stops);
- if (pixman_stops != pixman_stops_stack)
- free (pixman_stops);
-
- if (unlikely (gradient == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- pixman_image_set_filter (gradient, PIXMAN_FILTER_BILINEAR, NULL, 0);
- pixman_image_set_repeat (gradient, PIXMAN_REPEAT_PAD);
-
- image = pixman_image_create_bits (gradient_pixman_format, width, 1,
- bytes, sizeof(uint32_t)*width);
- if (unlikely (image == NULL)) {
- pixman_image_unref (gradient);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- pixman_image_composite32 (PIXMAN_OP_SRC,
- gradient, NULL, image,
- 0, 0,
- 0, 0,
- 0, 0,
- width, 1);
-
- pixman_image_unref (gradient);
- pixman_image_unref (image);
-
- /* We need to fudge pixel 0 to hold the left-most color stop and not
- * the neareset stop to the zeroth pixel centre in order to correctly
- * populate the border color. For completeness, do both edges.
- */
- ((uint32_t*)bytes)[0] = color_stop_to_pixel(&stops[0]);
- ((uint32_t*)bytes)[width-1] = color_stop_to_pixel(&stops[n_stops-1]);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static uintptr_t
-_cairo_gl_gradient_hash (unsigned int n_stops,
- const cairo_gradient_stop_t *stops)
-{
- return _cairo_hash_bytes (n_stops,
- stops,
- sizeof (cairo_gradient_stop_t) * n_stops);
-}
-
-static cairo_gl_gradient_t *
-_cairo_gl_gradient_lookup (cairo_gl_context_t *ctx,
- uintptr_t hash,
- unsigned int n_stops,
- const cairo_gradient_stop_t *stops)
-{
- cairo_gl_gradient_t lookup;
-
- lookup.cache_entry.hash = hash,
- lookup.n_stops = n_stops;
- lookup.stops = stops;
-
- return _cairo_cache_lookup (&ctx->gradients, &lookup.cache_entry);
-}
-
-cairo_bool_t
-_cairo_gl_gradient_equal (const void *key_a, const void *key_b)
-{
- const cairo_gl_gradient_t *a = key_a;
- const cairo_gl_gradient_t *b = key_b;
-
- if (a->n_stops != b->n_stops)
- return FALSE;
-
- return memcmp (a->stops, b->stops, a->n_stops * sizeof (cairo_gradient_stop_t)) == 0;
-}
-
-cairo_int_status_t
-_cairo_gl_gradient_create (cairo_gl_context_t *ctx,
- unsigned int n_stops,
- const cairo_gradient_stop_t *stops,
- cairo_gl_gradient_t **gradient_out)
-{
- uintptr_t hash;
- cairo_gl_gradient_t *gradient;
- cairo_status_t status;
- int tex_width;
- GLint internal_format;
- void *data;
-
- if ((unsigned int) ctx->max_texture_size / 2 <= n_stops)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- hash = _cairo_gl_gradient_hash (n_stops, stops);
-
- gradient = _cairo_gl_gradient_lookup (ctx, hash, n_stops, stops);
- if (gradient) {
- *gradient_out = _cairo_gl_gradient_reference (gradient);
- return CAIRO_STATUS_SUCCESS;
- }
-
- gradient = _cairo_malloc (sizeof (cairo_gl_gradient_t) + sizeof (cairo_gradient_stop_t) * (n_stops - 1));
- if (gradient == NULL)
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- tex_width = _cairo_gl_gradient_sample_width (n_stops, stops);
- if (tex_width > ctx->max_texture_size)
- tex_width = ctx->max_texture_size;
-
- CAIRO_REFERENCE_COUNT_INIT (&gradient->ref_count, 2);
- gradient->cache_entry.hash = hash;
- gradient->cache_entry.size = tex_width;
- gradient->device = &ctx->base;
- gradient->n_stops = n_stops;
- gradient->stops = gradient->stops_embedded;
- memcpy (gradient->stops_embedded, stops, n_stops * sizeof (cairo_gradient_stop_t));
-
- glGenTextures (1, &gradient->tex);
- _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
- glBindTexture (ctx->tex_target, gradient->tex);
-
- data = _cairo_malloc_ab (tex_width, sizeof (uint32_t));
- if (unlikely (data == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto cleanup_gradient;
- }
-
- status = _cairo_gl_gradient_render (ctx, n_stops, stops, data, tex_width);
- if (unlikely (status))
- goto cleanup_data;
-
- /*
- * In OpenGL ES 2.0 no format conversion is allowed i.e. 'internalFormat'
- * must match 'format' in glTexImage2D.
- */
- if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES3 ||
- _cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES2)
- internal_format = GL_BGRA;
- else
- internal_format = GL_RGBA;
-
- glTexImage2D (ctx->tex_target, 0, internal_format, tex_width, 1, 0,
- GL_BGRA, GL_UNSIGNED_BYTE, data);
-
- free (data);
-
- /* we ignore errors here and just return an uncached gradient */
- if (unlikely (_cairo_cache_insert (&ctx->gradients, &gradient->cache_entry)))
- CAIRO_REFERENCE_COUNT_INIT (&gradient->ref_count, 1);
-
- *gradient_out = gradient;
- return CAIRO_STATUS_SUCCESS;
-
-cleanup_data:
- free (data);
-cleanup_gradient:
- free (gradient);
- return status;
-}
-
-cairo_gl_gradient_t *
-_cairo_gl_gradient_reference (cairo_gl_gradient_t *gradient)
-{
- assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&gradient->ref_count));
-
- _cairo_reference_count_inc (&gradient->ref_count);
-
- return gradient;
-}
-
-void
-_cairo_gl_gradient_destroy (cairo_gl_gradient_t *gradient)
-{
- cairo_gl_context_t *ctx;
- cairo_status_t ignore;
-
- assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&gradient->ref_count));
-
- if (! _cairo_reference_count_dec_and_test (&gradient->ref_count))
- return;
-
- if (_cairo_gl_context_acquire (gradient->device, &ctx) == CAIRO_STATUS_SUCCESS) {
- /* The gradient my still be active in the last operation, so flush */
- _cairo_gl_composite_flush (ctx);
- glDeleteTextures (1, &gradient->tex);
- ignore = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
- }
-
- free (gradient);
-}
diff --git a/src/cairo-gl-info.c b/src/cairo-gl-info.c
deleted file mode 100644
index c655b962e..000000000
--- a/src/cairo-gl-info.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2010 Linaro Limited
- *
- * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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.
- *
- * Contributor(s):
- * Alexandros Frantzis <alexandros.frantzis@linaro.org>
- * Heiko Lewin <heiko.lewin@gmx.de>
- */
-
-#include "cairoint.h"
-#include "cairo-gl-private.h"
-
-#include <errno.h>
-
-int
-_cairo_gl_get_version (void)
-{
- int major, minor;
- const char *version = (const char *) glGetString (GL_VERSION);
- const char *dot = version == NULL ? NULL : strchr (version, '.');
- const char *major_start = dot;
-
- /* Sanity check */
- if (dot == NULL || dot == version || *(dot + 1) == '\0') {
- major = 0;
- minor = 0;
- } else {
- /* Find the start of the major version in the string */
- while (major_start > version && *major_start != ' ')
- --major_start;
- major = strtol (major_start, NULL, 10);
- minor = strtol (dot + 1, NULL, 10);
- }
-
- return CAIRO_GL_VERSION_ENCODE (major, minor);
-}
-
-
-static cairo_gl_flavor_t
-_cairo_gl_degrade_flavor_by_build_features (cairo_gl_flavor_t flavor)
-{
- switch(flavor) {
- case CAIRO_GL_FLAVOR_DESKTOP:
-#if CAIRO_HAS_GL_SURFACE
- return CAIRO_GL_FLAVOR_DESKTOP;
-#else
- return CAIRO_GL_FLAVOR_NONE;
-#endif
-
- case CAIRO_GL_FLAVOR_ES3:
-#if CAIRO_HAS_GLESV3_SURFACE
- return CAIRO_GL_FLAVOR_ES3;
-#else
- /* intentional fall through: degrade to GLESv2 if GLESv3-surfaces are not available */
-#endif
-
- case CAIRO_GL_FLAVOR_ES2:
-#if CAIRO_HAS_GLESV2_SURFACE
- return CAIRO_GL_FLAVOR_ES2;
-#else
- /* intentional fall through: no OpenGL in first place or no surfaces for it's version */
-#endif
-
- case CAIRO_GL_FLAVOR_NONE:
- default:
- return CAIRO_GL_FLAVOR_NONE;
- }
-}
-
-cairo_gl_flavor_t
-_cairo_gl_get_flavor (void)
-{
- const char *version = (const char *) glGetString (GL_VERSION);
- cairo_gl_flavor_t flavor;
-
- if (version == NULL) {
- flavor = CAIRO_GL_FLAVOR_NONE;
- } else if (strstr (version, "OpenGL ES 3") != NULL) {
- flavor = CAIRO_GL_FLAVOR_ES3;
- } else if (strstr (version, "OpenGL ES 2") != NULL) {
- flavor = CAIRO_GL_FLAVOR_ES2;
- } else {
- flavor = CAIRO_GL_FLAVOR_DESKTOP;
- }
-
- return _cairo_gl_degrade_flavor_by_build_features(flavor);
-}
-
-unsigned long
-_cairo_gl_get_vbo_size (void)
-{
- unsigned long vbo_size;
-
- const char *env = getenv ("CAIRO_GL_VBO_SIZE");
- if (env == NULL) {
- vbo_size = CAIRO_GL_VBO_SIZE_DEFAULT;
- } else {
- errno = 0;
- vbo_size = strtol (env, NULL, 10);
- assert (errno == 0);
- assert (vbo_size > 0);
- }
-
- return vbo_size;
-}
-
-cairo_bool_t
-_cairo_gl_has_extension (const char *ext)
-{
- const char *extensions = (const char *) glGetString (GL_EXTENSIONS);
- size_t len = strlen (ext);
- const char *ext_ptr = extensions;
-
- if (unlikely (ext_ptr == NULL))
- return 0;
-
- while ((ext_ptr = strstr (ext_ptr, ext)) != NULL) {
- if (ext_ptr[len] == ' ' || ext_ptr[len] == '\0')
- break;
- ext_ptr += len;
- }
-
- return (ext_ptr != NULL);
-}
diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c
deleted file mode 100644
index 7a83dd219..000000000
--- a/src/cairo-gl-msaa-compositor.c
+++ /dev/null
@@ -1,956 +0,0 @@
-/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2002 University of Southern California
- * Copyright © 2005 Red Hat, Inc.
- * Copyright © 2011 Intel Corporation
- * Copyright © 2011 Samsung Electronics
- *
- * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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 University of Southern
- * California.
- *
- * Contributor(s):
- * Henry Song <hsong@sisa.samsung.com>
- * Martin Robinson <mrobinson@igalia.com>
- */
-
-#include "cairoint.h"
-
-#include "cairo-clip-inline.h"
-#include "cairo-composite-rectangles-private.h"
-#include "cairo-compositor-private.h"
-#include "cairo-gl-private.h"
-#include "cairo-path-private.h"
-#include "cairo-traps-private.h"
-
-static cairo_bool_t
-can_use_msaa_compositor (cairo_gl_surface_t *surface,
- cairo_antialias_t antialias);
-
-static void
-query_surface_capabilities (cairo_gl_surface_t *surface);
-
-struct _tristrip_composite_info {
- cairo_gl_composite_t setup;
- cairo_gl_context_t *ctx;
-};
-
-static cairo_int_status_t
-_draw_trap (cairo_gl_context_t *ctx,
- cairo_gl_composite_t *setup,
- cairo_trapezoid_t *trap)
-{
- cairo_point_t quad[4];
-
- quad[0].x = _cairo_edge_compute_intersection_x_for_y (&trap->left.p1,
- &trap->left.p2,
- trap->top);
- quad[0].y = trap->top;
-
- quad[1].x = _cairo_edge_compute_intersection_x_for_y (&trap->left.p1,
- &trap->left.p2,
- trap->bottom);
- quad[1].y = trap->bottom;
-
- quad[2].x = _cairo_edge_compute_intersection_x_for_y (&trap->right.p1,
- &trap->right.p2,
- trap->bottom);
- quad[2].y = trap->bottom;
-
- quad[3].x = _cairo_edge_compute_intersection_x_for_y (&trap->right.p1,
- &trap->right.p2,
- trap->top);
- quad[3].y = trap->top;
- return _cairo_gl_composite_emit_quad_as_tristrip (ctx, setup, quad);
-}
-
-static cairo_int_status_t
-_draw_traps (cairo_gl_context_t *ctx,
- cairo_gl_composite_t *setup,
- cairo_traps_t *traps)
-{
- cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
- int i;
-
- for (i = 0; i < traps->num_traps; i++) {
- cairo_trapezoid_t *trap = traps->traps + i;
- if (unlikely ((status = _draw_trap (ctx, setup, trap))))
- return status;
- }
-
- return status;
-}
-
-static cairo_int_status_t
-_draw_int_rect (cairo_gl_context_t *ctx,
- cairo_gl_composite_t *setup,
- cairo_rectangle_int_t *rect)
-{
- cairo_box_t box;
- cairo_point_t quad[4];
-
- _cairo_box_from_rectangle (&box, rect);
- quad[0].x = box.p1.x;
- quad[0].y = box.p1.y;
- quad[1].x = box.p1.x;
- quad[1].y = box.p2.y;
- quad[2].x = box.p2.x;
- quad[2].y = box.p2.y;
- quad[3].x = box.p2.x;
- quad[3].y = box.p1.y;
-
- return _cairo_gl_composite_emit_quad_as_tristrip (ctx, setup, quad);
-}
-
-static cairo_int_status_t
-_draw_triangle_fan (cairo_gl_context_t *ctx,
- cairo_gl_composite_t *setup,
- const cairo_point_t *midpt,
- const cairo_point_t *points,
- int npoints)
-{
- int i;
-
- /* Our strategy here is to not even try to build a triangle fan, but to
- draw each triangle as if it was an unconnected member of a triangle strip. */
- for (i = 1; i < npoints; i++) {
- cairo_int_status_t status;
- cairo_point_t triangle[3];
-
- triangle[0] = *midpt;
- triangle[1] = points[i - 1];
- triangle[2] = points[i];
-
- status = _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle);
- if (unlikely (status))
- return status;
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_clip_to_traps (cairo_clip_t *clip,
- cairo_traps_t *traps)
-{
- cairo_int_status_t status;
- cairo_polygon_t polygon;
- cairo_antialias_t antialias;
- cairo_fill_rule_t fill_rule;
-
- _cairo_traps_init (traps);
-
- if (clip->num_boxes == 1 && clip->path == NULL) {
- cairo_boxes_t boxes;
- _cairo_boxes_init_for_array (&boxes, clip->boxes, clip->num_boxes);
- return _cairo_traps_init_boxes (traps, &boxes);
- }
-
- status = _cairo_clip_get_polygon (clip, &polygon, &fill_rule, &antialias);
- if (unlikely (status))
- return status;
-
- /* We ignore the antialias mode of the clip here, since the user requested
- * unantialiased rendering of their path and we expect that this stencil
- * based rendering of the clip to be a reasonable approximation to
- * the intersection between that clip and the path.
- *
- * In other words, what the user expects when they try to perform
- * a geometric intersection between an unantialiased polygon and an
- * antialiased polygon is open to interpretation. And we choose the fast
- * option.
- */
-
- _cairo_traps_init (traps);
- status = _cairo_bentley_ottmann_tessellate_polygon (traps,
- &polygon,
- fill_rule);
- _cairo_polygon_fini (&polygon);
-
- return status;
-}
-
-cairo_int_status_t
-_cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx,
- cairo_gl_composite_t *setup,
- cairo_clip_t *clip)
-{
- cairo_int_status_t status;
- cairo_traps_t traps;
-
- status = _clip_to_traps (clip, &traps);
- if (unlikely (status))
- return status;
- status = _draw_traps (ctx, setup, &traps);
-
- _cairo_traps_fini (&traps);
- return status;
-}
-
-static cairo_bool_t
-_should_use_unbounded_surface (cairo_composite_rectangles_t *composite)
-{
- cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
- cairo_rectangle_int_t *source = &composite->source;
-
- if (composite->is_bounded)
- return FALSE;
-
- /* This isn't just an optimization. It also detects when painting is used
- to paint back the unbounded surface, preventing infinite recursion. */
- return ! (source->x <= 0 && source->y <= 0 &&
- source->height + source->y >= dst->height &&
- source->width + source->x >= dst->width);
-}
-
-static cairo_surface_t*
-_prepare_unbounded_surface (cairo_gl_surface_t *dst)
-{
-
- cairo_surface_t* surface = cairo_gl_surface_create (dst->base.device,
- dst->base.content,
- dst->width,
- dst->height);
- if (surface == NULL)
- return NULL;
- if (unlikely (surface->status)) {
- cairo_surface_destroy (surface);
- return NULL;
- }
- return surface;
-}
-
-static cairo_int_status_t
-_paint_back_unbounded_surface (const cairo_compositor_t *compositor,
- cairo_composite_rectangles_t *composite,
- cairo_surface_t *surface)
-{
- cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
- cairo_int_status_t status;
-
- cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface);
- if (unlikely (pattern->status)) {
- status = pattern->status;
- goto finish;
- }
-
- status = _cairo_compositor_paint (compositor, &dst->base,
- composite->op, pattern,
- composite->clip);
-
-finish:
- cairo_pattern_destroy (pattern);
- cairo_surface_destroy (surface);
- return status;
-}
-
-static cairo_bool_t
-can_use_msaa_compositor (cairo_gl_surface_t *surface,
- cairo_antialias_t antialias)
-{
- cairo_gl_flavor_t gl_flavor = ((cairo_gl_context_t *) surface->base.device)->gl_flavor;
-
- query_surface_capabilities (surface);
- if (! surface->supports_stencil)
- return FALSE;
-
- /* Multisampling OpenGL ES surfaces only maintain one multisampling
- framebuffer and thus must use the spans compositor to do non-antialiased
- rendering. */
- if ((gl_flavor == CAIRO_GL_FLAVOR_ES3 ||
- gl_flavor == CAIRO_GL_FLAVOR_ES2)
- && surface->supports_msaa
- && surface->num_samples > 1
- && antialias == CAIRO_ANTIALIAS_NONE)
- return FALSE;
-
- /* The MSAA compositor has a single-sample mode, so we can
- support non-antialiased rendering. */
- if (antialias == CAIRO_ANTIALIAS_NONE)
- return TRUE;
-
- if (antialias == CAIRO_ANTIALIAS_FAST || antialias == CAIRO_ANTIALIAS_DEFAULT)
- return surface->supports_msaa;
- return FALSE;
-}
-
-static void
-_cairo_gl_msaa_compositor_set_clip (cairo_composite_rectangles_t *composite,
- cairo_gl_composite_t *setup)
-{
- if (_cairo_composite_rectangles_can_reduce_clip (composite, composite->clip))
- return;
- _cairo_gl_composite_set_clip (setup, composite->clip);
-}
-
-/* Masking with the SOURCE operator requires two passes. In the first
- * pass we use the mask as the source to get:
- * result = (1 - ma) * dst
- * In the second pass we use the add operator to achieve:
- * result = (src * ma) + dst
- * Combined this produces:
- * result = (src * ma) + (1 - ma) * dst
- */
-static cairo_int_status_t
-_cairo_gl_msaa_compositor_mask_source_operator (const cairo_compositor_t *compositor,
- cairo_composite_rectangles_t *composite)
-{
- cairo_gl_composite_t setup;
- cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
- cairo_gl_context_t *ctx = NULL;
- cairo_int_status_t status;
-
- cairo_clip_t *clip = composite->clip;
- cairo_traps_t traps;
-
- /* If we have a non-rectangular clip, we can avoid using the stencil buffer
- * for clipping and just draw the clip polygon. */
- if (clip) {
- status = _clip_to_traps (clip, &traps);
- if (unlikely (status)) {
- _cairo_traps_fini (&traps);
- return status;
- }
- }
-
- status = _cairo_gl_composite_init (&setup,
- CAIRO_OPERATOR_DEST_OUT,
- dst,
- FALSE /* assume_component_alpha */);
- if (unlikely (status))
- return status;
- status = _cairo_gl_composite_set_source (&setup,
- &composite->mask_pattern.base,
- &composite->mask_sample_area,
- &composite->bounded,
- FALSE);
- if (unlikely (status))
- goto finish;
- _cairo_gl_composite_set_multisample (&setup);
- status = _cairo_gl_composite_begin (&setup, &ctx);
- if (unlikely (status))
- goto finish;
-
- if (! clip)
- status = _draw_int_rect (ctx, &setup, &composite->bounded);
- else
- status = _draw_traps (ctx, &setup, &traps);
- if (unlikely (status))
- goto finish;
-
- /* Now draw the second pass. */
- status = _cairo_gl_composite_set_operator (&setup, CAIRO_OPERATOR_ADD,
- FALSE /* assume_component_alpha */);
- if (unlikely (status))
- goto finish;
- status = _cairo_gl_composite_set_source (&setup,
- &composite->source_pattern.base,
- &composite->source_sample_area,
- &composite->bounded,
- FALSE);
- if (unlikely (status))
- goto finish;
- status = _cairo_gl_composite_set_mask (&setup,
- &composite->mask_pattern.base,
- &composite->source_sample_area,
- &composite->bounded,
- FALSE);
- if (unlikely (status))
- goto finish;
-
- _cairo_gl_context_set_destination (ctx, dst, setup.multisample);
-
- status = _cairo_gl_set_operands_and_operator (&setup, ctx);
- if (unlikely (status))
- goto finish;
-
- if (! clip)
- status = _draw_int_rect (ctx, &setup, &composite->bounded);
- else
- status = _draw_traps (ctx, &setup, &traps);
-
-finish:
- _cairo_gl_composite_fini (&setup);
- if (ctx)
- status = _cairo_gl_context_release (ctx, status);
- if (clip)
- _cairo_traps_fini (&traps);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_gl_msaa_compositor_mask (const cairo_compositor_t *compositor,
- cairo_composite_rectangles_t *composite)
-{
- cairo_gl_composite_t setup;
- cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
- cairo_gl_context_t *ctx = NULL;
- cairo_int_status_t status;
- cairo_operator_t op = composite->op;
- cairo_clip_t *clip = composite->clip;
-
- if (! can_use_msaa_compositor (dst, CAIRO_ANTIALIAS_DEFAULT))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (composite->op == CAIRO_OPERATOR_CLEAR &&
- composite->original_mask_pattern != NULL)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* GL compositing operators cannot properly represent a mask operation
- using the SOURCE compositing operator in one pass. This only matters if
- there actually is a mask (there isn't in a paint operation) and if the
- mask isn't totally opaque. */
- if (op == CAIRO_OPERATOR_SOURCE &&
- composite->original_mask_pattern != NULL &&
- ! _cairo_pattern_is_opaque (&composite->mask_pattern.base,
- &composite->mask_sample_area)) {
-
- if (! _cairo_pattern_is_opaque (&composite->source_pattern.base,
- &composite->source_sample_area)) {
- return _cairo_gl_msaa_compositor_mask_source_operator (compositor, composite);
- }
-
- /* If the source is opaque the operation reduces to OVER. */
- op = CAIRO_OPERATOR_OVER;
- }
-
- if (_should_use_unbounded_surface (composite)) {
- cairo_surface_t* surface = _prepare_unbounded_surface (dst);
-
- if (unlikely (surface == NULL))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* This may be a paint operation. */
- if (composite->original_mask_pattern == NULL) {
- status = _cairo_compositor_paint (compositor, surface,
- CAIRO_OPERATOR_SOURCE,
- &composite->source_pattern.base,
- NULL);
- } else {
- status = _cairo_compositor_mask (compositor, surface,
- CAIRO_OPERATOR_SOURCE,
- &composite->source_pattern.base,
- &composite->mask_pattern.base,
- NULL);
- }
-
- if (unlikely (status)) {
- cairo_surface_destroy (surface);
- return status;
- }
-
- return _paint_back_unbounded_surface (compositor, composite, surface);
- }
-
- status = _cairo_gl_composite_init (&setup,
- op,
- dst,
- FALSE /* assume_component_alpha */);
- if (unlikely (status))
- return status;
-
- status = _cairo_gl_composite_set_source (&setup,
- &composite->source_pattern.base,
- &composite->source_sample_area,
- &composite->bounded,
- FALSE);
- if (unlikely (status))
- goto finish;
-
- if (composite->original_mask_pattern != NULL) {
- status = _cairo_gl_composite_set_mask (&setup,
- &composite->mask_pattern.base,
- &composite->mask_sample_area,
- &composite->bounded,
- FALSE);
- }
- if (unlikely (status))
- goto finish;
-
- /* We always use multisampling here, because we do not yet have the smarts
- to calculate when the clip or the source requires it. */
- _cairo_gl_composite_set_multisample (&setup);
-
- status = _cairo_gl_composite_begin (&setup, &ctx);
- if (unlikely (status))
- goto finish;
-
- if (! clip)
- status = _draw_int_rect (ctx, &setup, &composite->bounded);
- else
- status = _cairo_gl_msaa_compositor_draw_clip (ctx, &setup, clip);
-
-finish:
- _cairo_gl_composite_fini (&setup);
-
- if (ctx)
- status = _cairo_gl_context_release (ctx, status);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_gl_msaa_compositor_paint (const cairo_compositor_t *compositor,
- cairo_composite_rectangles_t *composite)
-{
- return _cairo_gl_msaa_compositor_mask (compositor, composite);
-}
-
-static cairo_status_t
-_stroke_shaper_add_triangle (void *closure,
- const cairo_point_t triangle[3])
-{
- struct _tristrip_composite_info *info = closure;
- return _cairo_gl_composite_emit_triangle_as_tristrip (info->ctx,
- &info->setup,
- triangle);
-}
-
-static cairo_status_t
-_stroke_shaper_add_triangle_fan (void *closure,
- const cairo_point_t *midpoint,
- const cairo_point_t *points,
- int npoints)
-{
- struct _tristrip_composite_info *info = closure;
- return _draw_triangle_fan (info->ctx, &info->setup,
- midpoint, points, npoints);
-}
-
-static cairo_status_t
-_stroke_shaper_add_quad (void *closure,
- const cairo_point_t quad[4])
-{
- struct _tristrip_composite_info *info = closure;
- return _cairo_gl_composite_emit_quad_as_tristrip (info->ctx, &info->setup,
- quad);
-}
-
-static cairo_int_status_t
-_prevent_overlapping_strokes (cairo_gl_context_t *ctx,
- cairo_gl_composite_t *setup,
- cairo_composite_rectangles_t *composite,
- const cairo_path_fixed_t *path,
- const cairo_stroke_style_t *style,
- const cairo_matrix_t *ctm)
-{
- cairo_rectangle_int_t stroke_extents;
-
- if (! _cairo_gl_ensure_stencil (ctx, setup->dst))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (_cairo_pattern_is_opaque (&composite->source_pattern.base,
- &composite->source_sample_area))
- return CAIRO_INT_STATUS_SUCCESS;
-
- if (glIsEnabled (GL_STENCIL_TEST) == FALSE) {
- cairo_bool_t scissor_was_enabled;
-
- /* In case we have pending operations we have to flush before
- adding the stencil buffer. */
- _cairo_gl_composite_flush (ctx);
-
- /* Enable the stencil buffer, even if we are not using it for clipping,
- so we can use it below to prevent overlapping shapes. We initialize
- it all to one here which represents infinite clip. */
- glDepthMask (GL_TRUE);
- glEnable (GL_STENCIL_TEST);
-
- /* We scissor here so that we don't have to clear the entire stencil
- * buffer. If the scissor test is already enabled, it was enabled
- * for clipping. In that case, instead of calculating an intersection,
- * we just reuse it, and risk clearing too much. */
- scissor_was_enabled = glIsEnabled (GL_SCISSOR_TEST);
- if (! scissor_was_enabled) {
- _cairo_path_fixed_approximate_stroke_extents (path, style, ctm,
- FALSE, /* is_vector */
- &stroke_extents);
- _cairo_gl_scissor_to_rectangle (setup->dst, &stroke_extents);
- }
- glClearStencil (1);
- glClear (GL_STENCIL_BUFFER_BIT);
- if (! scissor_was_enabled)
- glDisable (GL_SCISSOR_TEST);
-
- glStencilFunc (GL_EQUAL, 1, 1);
- }
-
- /* This means that once we draw to a particular pixel nothing else can
- be drawn there until the stencil buffer is reset or the stencil test
- is disabled. */
- glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO);
-
- _cairo_clip_destroy (setup->dst->clip_on_stencil_buffer);
- setup->dst->clip_on_stencil_buffer = NULL;
-
- return CAIRO_INT_STATUS_SUCCESS;
-}
-
-static void
-query_surface_capabilities (cairo_gl_surface_t *surface)
-{
- GLint samples, stencil_bits;
- cairo_gl_context_t *ctx;
- cairo_int_status_t status;
-
- /* Texture surfaces are create in such a way that they always
- have stencil and multisample bits if possible, so we don't
- need to query their capabilities lazily. */
- if (_cairo_gl_surface_is_texture (surface))
- return;
- if (surface->stencil_and_msaa_caps_initialized)
- return;
-
- surface->stencil_and_msaa_caps_initialized = TRUE;
- surface->supports_stencil = FALSE;
- surface->supports_msaa = FALSE;
-
- status = _cairo_gl_context_acquire (surface->base.device, &ctx);
- if (unlikely (status))
- return;
-
- _cairo_gl_context_set_destination (ctx, surface, FALSE);
-
- glGetIntegerv(GL_SAMPLES, &samples);
- glGetIntegerv(GL_STENCIL_BITS, &stencil_bits);
- surface->supports_stencil = stencil_bits > 0;
- surface->supports_msaa = samples > 1;
- surface->num_samples = samples;
-
- status = _cairo_gl_context_release (ctx, status);
-}
-
-static cairo_int_status_t
-_cairo_gl_msaa_compositor_stroke (const cairo_compositor_t *compositor,
- cairo_composite_rectangles_t *composite,
- const cairo_path_fixed_t *path,
- const cairo_stroke_style_t *style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_antialias_t antialias)
-{
- cairo_int_status_t status;
- cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
- struct _tristrip_composite_info info;
-
- if (! can_use_msaa_compositor (dst, antialias))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (composite->is_bounded == FALSE) {
- cairo_surface_t* surface = _prepare_unbounded_surface (dst);
-
- if (unlikely (surface == NULL))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_compositor_stroke (compositor, surface,
- CAIRO_OPERATOR_SOURCE,
- &composite->source_pattern.base,
- path, style, ctm, ctm_inverse,
- tolerance, antialias, NULL);
- if (unlikely (status)) {
- cairo_surface_destroy (surface);
- return status;
- }
-
- return _paint_back_unbounded_surface (compositor, composite, surface);
- }
-
- status = _cairo_gl_composite_init (&info.setup,
- composite->op,
- dst,
- FALSE /* assume_component_alpha */);
- if (unlikely (status))
- return status;
-
- info.ctx = NULL;
-
- status = _cairo_gl_composite_set_source (&info.setup,
- &composite->source_pattern.base,
- &composite->source_sample_area,
- &composite->bounded,
- FALSE);
- if (unlikely (status))
- goto finish;
-
- _cairo_gl_msaa_compositor_set_clip (composite, &info.setup);
- if (antialias != CAIRO_ANTIALIAS_NONE)
- _cairo_gl_composite_set_multisample (&info.setup);
-
- status = _cairo_gl_composite_begin (&info.setup, &info.ctx);
- if (unlikely (status))
- goto finish;
-
- status = _prevent_overlapping_strokes (info.ctx, &info.setup,
- composite, path, style, ctm);
- if (unlikely (status))
- goto finish;
-
- status = _cairo_path_fixed_stroke_to_shaper ((cairo_path_fixed_t *) path,
- style,
- ctm,
- ctm_inverse,
- tolerance,
- _stroke_shaper_add_triangle,
- _stroke_shaper_add_triangle_fan,
- _stroke_shaper_add_quad,
- &info);
- if (unlikely (status))
- goto finish;
-
-finish:
- _cairo_gl_composite_fini (&info.setup);
-
- if (info.ctx)
- status = _cairo_gl_context_release (info.ctx, status);
-
- return status;
-}
-
-static cairo_int_status_t
-_draw_simple_quad_path (cairo_gl_context_t *ctx,
- cairo_gl_composite_t *setup,
- const cairo_path_fixed_t *path)
-{
- cairo_point_t triangle[3];
- cairo_int_status_t status;
- const cairo_point_t *points;
-
- points = cairo_path_head (path)->points;
- triangle[0] = points[0];
- triangle[1] = points[1];
- triangle[2] = points[2];
- status = _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle);
- if (status)
- return status;
-
- triangle[0] = points[2];
- triangle[1] = points[3];
- triangle[2] = points[0];
- return _cairo_gl_composite_emit_triangle_as_tristrip (ctx, setup, triangle);
-}
-
-static cairo_int_status_t
-_cairo_gl_msaa_compositor_fill (const cairo_compositor_t *compositor,
- cairo_composite_rectangles_t *composite,
- const cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias)
-{
- cairo_gl_composite_t setup;
- cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
- cairo_gl_context_t *ctx = NULL;
- cairo_int_status_t status;
- cairo_traps_t traps;
- cairo_bool_t draw_path_with_traps;
-
- if (! can_use_msaa_compositor (dst, antialias))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (composite->is_bounded == FALSE) {
- cairo_surface_t* surface = _prepare_unbounded_surface (dst);
-
- if (unlikely (surface == NULL))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
-
- status = _cairo_compositor_fill (compositor, surface,
- CAIRO_OPERATOR_SOURCE,
- &composite->source_pattern.base,
- path, fill_rule, tolerance,
- antialias, NULL);
-
- if (unlikely (status)) {
- cairo_surface_destroy (surface);
- return status;
- }
-
- return _paint_back_unbounded_surface (compositor, composite, surface);
- }
-
- draw_path_with_traps = ! _cairo_path_fixed_is_simple_quad (path);
-
- if (draw_path_with_traps) {
- _cairo_traps_init (&traps);
- status = _cairo_path_fixed_fill_to_traps (path, fill_rule, tolerance, &traps);
- if (unlikely (status))
- goto cleanup_traps;
- }
-
- status = _cairo_gl_composite_init (&setup,
- composite->op,
- dst,
- FALSE /* assume_component_alpha */);
- if (unlikely (status))
- goto cleanup_traps;
-
- status = _cairo_gl_composite_set_source (&setup,
- &composite->source_pattern.base,
- &composite->source_sample_area,
- &composite->bounded,
- FALSE);
- if (unlikely (status))
- goto cleanup_setup;
-
- _cairo_gl_msaa_compositor_set_clip (composite, &setup);
- if (antialias != CAIRO_ANTIALIAS_NONE)
- _cairo_gl_composite_set_multisample (&setup);
-
- status = _cairo_gl_composite_begin (&setup, &ctx);
- if (unlikely (status))
- goto cleanup_setup;
-
- if (! draw_path_with_traps)
- status = _draw_simple_quad_path (ctx, &setup, path);
- else
- status = _draw_traps (ctx, &setup, &traps);
- if (unlikely (status))
- goto cleanup_setup;
-
-cleanup_setup:
- _cairo_gl_composite_fini (&setup);
-
- if (ctx)
- status = _cairo_gl_context_release (ctx, status);
-
-cleanup_traps:
- if (draw_path_with_traps)
- _cairo_traps_fini (&traps);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_gl_msaa_compositor_glyphs (const cairo_compositor_t *compositor,
- cairo_composite_rectangles_t *composite,
- cairo_scaled_font_t *scaled_font,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_bool_t overlap)
-{
- cairo_int_status_t status;
- cairo_surface_t *src = NULL;
- int src_x, src_y;
- cairo_composite_glyphs_info_t info;
-
- cairo_gl_surface_t *dst = (cairo_gl_surface_t *) composite->surface;
-
- query_surface_capabilities (dst);
- if (! dst->supports_stencil)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (composite->op == CAIRO_OPERATOR_CLEAR)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (composite->is_bounded == FALSE) {
- cairo_surface_t* surface = _prepare_unbounded_surface (dst);
-
- if (unlikely (surface == NULL))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_compositor_glyphs (compositor, surface,
- CAIRO_OPERATOR_SOURCE,
- &composite->source_pattern.base,
- glyphs, num_glyphs,
- scaled_font, composite->clip);
-
- if (unlikely (status)) {
- cairo_surface_destroy (surface);
- return status;
- }
-
- return _paint_back_unbounded_surface (compositor, composite, surface);
- }
-
- src = _cairo_gl_pattern_to_source (&dst->base,
- &composite->source_pattern.base,
- FALSE,
- &composite->bounded,
- &composite->source_sample_area,
- &src_x, &src_y);
- if (unlikely (src->status)) {
- status = src->status;
- goto finish;
- }
-
- status = _cairo_gl_check_composite_glyphs (composite,
- scaled_font, glyphs,
- &num_glyphs);
- if (unlikely (status != CAIRO_INT_STATUS_SUCCESS))
- goto finish;
-
- info.font = scaled_font;
- info.glyphs = glyphs;
- info.num_glyphs = num_glyphs;
- info.use_mask = overlap || ! composite->is_bounded ||
- composite->op == CAIRO_OPERATOR_SOURCE;
- info.extents = composite->bounded;
-
- _cairo_scaled_font_freeze_cache (scaled_font);
- status = _cairo_gl_composite_glyphs_with_clip (dst, composite->op,
- src, src_x, src_y,
- 0, 0, &info,
- composite->clip);
-
- _cairo_scaled_font_thaw_cache (scaled_font);
-
-finish:
- if (src)
- cairo_surface_destroy (src);
-
- return status;
-}
-
-static void
-_cairo_gl_msaa_compositor_init (cairo_compositor_t *compositor,
- const cairo_compositor_t *delegate)
-{
- compositor->delegate = delegate;
-
- compositor->paint = _cairo_gl_msaa_compositor_paint;
- compositor->mask = _cairo_gl_msaa_compositor_mask;
- compositor->fill = _cairo_gl_msaa_compositor_fill;
- compositor->stroke = _cairo_gl_msaa_compositor_stroke;
- compositor->glyphs = _cairo_gl_msaa_compositor_glyphs;
-}
-
-const cairo_compositor_t *
-_cairo_gl_msaa_compositor_get (void)
-{
- static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
- static cairo_compositor_t compositor;
- if (_cairo_atomic_init_once_enter(&once)) {
- _cairo_gl_msaa_compositor_init (&compositor,
- _cairo_gl_span_compositor_get ());
- _cairo_atomic_init_once_leave(&once);
- }
-
- return &compositor;
-}
diff --git a/src/cairo-gl-operand.c b/src/cairo-gl-operand.c
deleted file mode 100644
index a754bde2f..000000000
--- a/src/cairo-gl-operand.c
+++ /dev/null
@@ -1,793 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 Eric Anholt
- * Copyright © 2009 Chris Wilson
- * Copyright © 2005,2010 Red Hat, Inc
- * Copyright © 2011 Intel Corporation
- *
- * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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):
- * Benjamin Otte <otte@gnome.org>
- * Carl Worth <cworth@cworth.org>
- * Chris Wilson <chris@chris-wilson.co.uk>
- * Eric Anholt <eric@anholt.net>
- */
-
-#include "cairoint.h"
-
-#include "cairo-gl-private.h"
-
-#include "cairo-composite-rectangles-private.h"
-#include "cairo-compositor-private.h"
-#include "cairo-default-context-private.h"
-#include "cairo-error-private.h"
-#include "cairo-image-surface-private.h"
-#include "cairo-surface-backend-private.h"
-#include "cairo-surface-offset-private.h"
-#include "cairo-surface-subsurface-inline.h"
-
-static cairo_int_status_t
-_cairo_gl_create_gradient_texture (cairo_gl_surface_t *dst,
- const cairo_gradient_pattern_t *pattern,
- cairo_gl_gradient_t **gradient)
-{
- cairo_gl_context_t *ctx;
- cairo_status_t status;
-
- status = _cairo_gl_context_acquire (dst->base.device, &ctx);
- if (unlikely (status))
- return status;
-
- status = _cairo_gl_gradient_create (ctx, pattern->n_stops, pattern->stops, gradient);
-
- return _cairo_gl_context_release (ctx, status);
-}
-
-static cairo_status_t
-_cairo_gl_subsurface_clone_operand_init (cairo_gl_operand_t *operand,
- const cairo_pattern_t *_src,
- cairo_gl_surface_t *dst,
- const cairo_rectangle_int_t *sample,
- const cairo_rectangle_int_t *extents,
- cairo_bool_t use_texgen)
-{
- const cairo_surface_pattern_t *src = (cairo_surface_pattern_t *)_src;
- cairo_surface_pattern_t local_pattern;
- cairo_surface_subsurface_t *sub;
- cairo_gl_surface_t *surface;
- cairo_gl_context_t *ctx;
- cairo_surface_attributes_t *attributes;
- cairo_status_t status;
-
- sub = (cairo_surface_subsurface_t *) src->surface;
-
- if (sub->snapshot &&
- sub->snapshot->type == CAIRO_SURFACE_TYPE_GL &&
- sub->snapshot->device == dst->base.device)
- {
- surface = (cairo_gl_surface_t *)
- cairo_surface_reference (sub->snapshot);
- }
- else
- {
- status = _cairo_gl_context_acquire (dst->base.device, &ctx);
- if (unlikely (status))
- return status;
-
- /* XXX Trim surface to the sample area within the subsurface? */
- surface = (cairo_gl_surface_t *)
- _cairo_gl_surface_create_scratch (ctx,
- sub->target->content,
- sub->extents.width,
- sub->extents.height);
- if (surface->base.status)
- return _cairo_gl_context_release (ctx, surface->base.status);
-
- _cairo_pattern_init_for_surface (&local_pattern, sub->target);
- cairo_matrix_init_translate (&local_pattern.base.matrix,
- sub->extents.x, sub->extents.y);
- local_pattern.base.filter = CAIRO_FILTER_NEAREST;
- status = _cairo_surface_paint (&surface->base,
- CAIRO_OPERATOR_SOURCE,
- &local_pattern.base,
- NULL);
- _cairo_pattern_fini (&local_pattern.base);
-
- status = _cairo_gl_context_release (ctx, status);
- if (unlikely (status)) {
- cairo_surface_destroy (&surface->base);
- return status;
- }
-
- _cairo_surface_subsurface_set_snapshot (&sub->base, &surface->base);
- }
-
- status = _cairo_gl_surface_resolve_multisampling (surface);
- if (unlikely (status))
- return status;
-
- attributes = &operand->texture.attributes;
-
- operand->type = CAIRO_GL_OPERAND_TEXTURE;
- operand->texture.surface = surface;
- operand->texture.owns_surface = surface;
- operand->texture.tex = surface->tex;
-
- if (_cairo_gl_device_requires_power_of_two_textures (dst->base.device)) {
- attributes->matrix = src->base.matrix;
- } else {
- cairo_matrix_t m;
-
- cairo_matrix_init_scale (&m,
- 1.0 / surface->width,
- 1.0 / surface->height);
- cairo_matrix_multiply (&attributes->matrix, &src->base.matrix, &m);
- }
-
- attributes->extend = src->base.extend;
- attributes->filter = src->base.filter;
- attributes->has_component_alpha = src->base.has_component_alpha;
-
- operand->texture.texgen = use_texgen;
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_subsurface_operand_init (cairo_gl_operand_t *operand,
- const cairo_pattern_t *_src,
- cairo_gl_surface_t *dst,
- const cairo_rectangle_int_t *sample,
- const cairo_rectangle_int_t *extents,
- cairo_bool_t use_texgen)
-{
- const cairo_surface_pattern_t *src = (cairo_surface_pattern_t *)_src;
- cairo_surface_subsurface_t *sub;
- cairo_gl_surface_t *surface;
- cairo_surface_attributes_t *attributes;
- cairo_int_status_t status;
-
- sub = (cairo_surface_subsurface_t *) src->surface;
-
- if (sample->x < 0 || sample->y < 0 ||
- sample->x + sample->width > sub->extents.width ||
- sample->y + sample->height > sub->extents.height)
- {
- return _cairo_gl_subsurface_clone_operand_init (operand, _src,
- dst, sample, extents,
- use_texgen);
- }
-
- surface = (cairo_gl_surface_t *) sub->target;
- if (surface->base.device && surface->base.device != dst->base.device)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (! _cairo_gl_surface_is_texture (surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_gl_surface_resolve_multisampling (surface);
- if (unlikely (status))
- return status;
-
- /* Translate the matrix from
- * (unnormalized src -> unnormalized src) to
- * (unnormalized dst -> unnormalized src)
- */
- _cairo_gl_operand_copy(operand, &surface->operand);
-
- attributes = &operand->texture.attributes;
- attributes->matrix = src->base.matrix;
- attributes->matrix.x0 += sub->extents.x;
- attributes->matrix.y0 += sub->extents.y;
- cairo_matrix_multiply (&attributes->matrix,
- &attributes->matrix,
- &surface->operand.texture.attributes.matrix);
-
- attributes->extend = src->base.extend;
- attributes->filter = src->base.filter;
- attributes->has_component_alpha = src->base.has_component_alpha;
-
- operand->texture.texgen = use_texgen;
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_surface_operand_init (cairo_gl_operand_t *operand,
- const cairo_pattern_t *_src,
- cairo_gl_surface_t *dst,
- const cairo_rectangle_int_t *sample,
- const cairo_rectangle_int_t *extents,
- cairo_bool_t use_texgen)
-{
- const cairo_surface_pattern_t *src = (cairo_surface_pattern_t *)_src;
- cairo_gl_surface_t *surface;
- cairo_surface_attributes_t *attributes;
- cairo_int_status_t status;
-
- surface = (cairo_gl_surface_t *) src->surface;
- if (surface->base.type != CAIRO_SURFACE_TYPE_GL)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (surface->base.backend->type != CAIRO_SURFACE_TYPE_GL) {
- if (_cairo_surface_is_subsurface (&surface->base))
- return _cairo_gl_subsurface_operand_init (operand, _src, dst,
- sample, extents,
- use_texgen);
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
- }
-
- if (surface->base.device && surface->base.device != dst->base.device)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (surface->base.device && ! _cairo_gl_surface_is_texture (surface))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_gl_surface_resolve_multisampling (surface);
- if (unlikely (status))
- return status;
-
- _cairo_gl_operand_copy(operand, &surface->operand);
-
- attributes = &operand->texture.attributes;
- cairo_matrix_multiply (&attributes->matrix,
- &src->base.matrix,
- &attributes->matrix);
-
- attributes->extend = src->base.extend;
- attributes->filter = src->base.filter;
- attributes->has_component_alpha = src->base.has_component_alpha;
-
- operand->texture.texgen = use_texgen;
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_pattern_texture_setup (cairo_gl_operand_t *operand,
- const cairo_pattern_t *_src,
- cairo_gl_surface_t *dst,
- const cairo_rectangle_int_t *extents)
-{
- cairo_status_t status;
- cairo_gl_surface_t *surface;
- cairo_gl_context_t *ctx;
- cairo_image_surface_t *image;
- cairo_bool_t src_is_gl_surface = FALSE;
- cairo_rectangle_int_t map_extents;
-
- if (_src->type == CAIRO_PATTERN_TYPE_SURFACE) {
- cairo_surface_t* src_surface = ((cairo_surface_pattern_t *) _src)->surface;
- src_is_gl_surface = src_surface->type == CAIRO_SURFACE_TYPE_GL;
- }
-
- status = _cairo_gl_context_acquire (dst->base.device, &ctx);
- if (unlikely (status))
- return status;
-
- surface = (cairo_gl_surface_t *)
- _cairo_gl_surface_create_scratch (ctx,
- CAIRO_CONTENT_COLOR_ALPHA,
- extents->width, extents->height);
- map_extents = *extents;
- map_extents.x = map_extents.y = 0;
- image = _cairo_surface_map_to_image (&surface->base, &map_extents);
-
- /* If the pattern is a GL surface, it belongs to some other GL context,
- so we need to release this device while we paint it to the image. */
- if (src_is_gl_surface) {
- status = _cairo_gl_context_release (ctx, status);
- if (unlikely (status)) {
- _cairo_surface_unmap_image (&surface->base, image);
- goto fail;
- }
- }
-
- status = _cairo_surface_offset_paint (&image->base, extents->x, extents->y,
- CAIRO_OPERATOR_SOURCE, _src, NULL);
-
- if (src_is_gl_surface) {
- status = _cairo_gl_context_acquire (dst->base.device, &ctx);
- if (unlikely (status)) {
- _cairo_surface_unmap_image (&surface->base, image);
- goto fail;
- }
- }
-
- status = _cairo_surface_unmap_image (&surface->base, image);
- status = _cairo_gl_context_release (ctx, status);
- if (unlikely (status))
- goto fail;
-
- *operand = surface->operand;
- operand->texture.owns_surface = surface;
- operand->texture.attributes.matrix.x0 -= extents->x * operand->texture.attributes.matrix.xx;
- operand->texture.attributes.matrix.y0 -= extents->y * operand->texture.attributes.matrix.yy;
- return CAIRO_STATUS_SUCCESS;
-
-fail:
- cairo_surface_destroy (&surface->base);
- return status;
-}
-
-void
-_cairo_gl_solid_operand_init (cairo_gl_operand_t *operand,
- const cairo_color_t *color)
-{
- operand->type = CAIRO_GL_OPERAND_CONSTANT;
- operand->constant.color[0] = color->red * color->alpha;
- operand->constant.color[1] = color->green * color->alpha;
- operand->constant.color[2] = color->blue * color->alpha;
- operand->constant.color[3] = color->alpha;
-}
-
-void
-_cairo_gl_operand_translate (cairo_gl_operand_t *operand,
- double tx, double ty)
-{
- switch (operand->type) {
- case CAIRO_GL_OPERAND_TEXTURE:
- operand->texture.attributes.matrix.x0 -= tx * operand->texture.attributes.matrix.xx;
- operand->texture.attributes.matrix.y0 -= ty * operand->texture.attributes.matrix.yy;
- break;
-
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- operand->gradient.m.x0 -= tx * operand->gradient.m.xx;
- operand->gradient.m.y0 -= ty * operand->gradient.m.yy;
- break;
-
- case CAIRO_GL_OPERAND_NONE:
- case CAIRO_GL_OPERAND_CONSTANT:
- case CAIRO_GL_OPERAND_COUNT:
- default:
- break;
- }
-}
-
-static cairo_status_t
-_cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
- const cairo_pattern_t *pattern,
- cairo_gl_surface_t *dst,
- cairo_bool_t use_texgen)
-{
- const cairo_gradient_pattern_t *gradient = (const cairo_gradient_pattern_t *)pattern;
- cairo_status_t status;
-
- assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
- gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
-
- if (! _cairo_gl_device_has_glsl (dst->base.device))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_gl_create_gradient_texture (dst,
- gradient,
- &operand->gradient.gradient);
- if (unlikely (status))
- return status;
-
- if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
- cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
- double x0, y0, dx, dy, sf, offset;
-
- dx = linear->pd2.x - linear->pd1.x;
- dy = linear->pd2.y - linear->pd1.y;
- sf = 1.0 / (dx * dx + dy * dy);
- dx *= sf;
- dy *= sf;
-
- x0 = linear->pd1.x;
- y0 = linear->pd1.y;
- offset = dx * x0 + dy * y0;
-
- operand->type = CAIRO_GL_OPERAND_LINEAR_GRADIENT;
-
- cairo_matrix_init (&operand->gradient.m, dx, 0, dy, 1, -offset, 0);
- if (! _cairo_matrix_is_identity (&pattern->matrix)) {
- cairo_matrix_multiply (&operand->gradient.m,
- &pattern->matrix,
- &operand->gradient.m);
- }
- } else {
- cairo_matrix_t m;
- cairo_circle_double_t circles[2];
- double x0, y0, r0, dx, dy, dr;
-
- /*
- * Some fragment shader implementations use half-floats to
- * represent numbers, so the maximum number they can represent
- * is about 2^14. Some intermediate computations used in the
- * radial gradient shaders can produce results of up to 2*k^4.
- * Setting k=8 makes the maximum result about 8192 (assuming
- * that the extreme circles are not much smaller than the
- * destination image).
- */
- _cairo_gradient_pattern_fit_to_range (gradient, 8.,
- &operand->gradient.m, circles);
-
- x0 = circles[0].center.x;
- y0 = circles[0].center.y;
- r0 = circles[0].radius;
- dx = circles[1].center.x - x0;
- dy = circles[1].center.y - y0;
- dr = circles[1].radius - r0;
-
- operand->gradient.a = dx * dx + dy * dy - dr * dr;
- operand->gradient.radius_0 = r0;
- operand->gradient.circle_d.center.x = dx;
- operand->gradient.circle_d.center.y = dy;
- operand->gradient.circle_d.radius = dr;
-
- if (operand->gradient.a == 0)
- operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0;
- else if (pattern->extend == CAIRO_EXTEND_NONE)
- operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE;
- else
- operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT;
-
- cairo_matrix_init_translate (&m, -x0, -y0);
- cairo_matrix_multiply (&operand->gradient.m,
- &operand->gradient.m,
- &m);
- }
-
- operand->gradient.extend = pattern->extend;
- operand->gradient.texgen = use_texgen;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-void
-_cairo_gl_operand_copy (cairo_gl_operand_t *dst,
- const cairo_gl_operand_t *src)
-{
- *dst = *src;
- switch (dst->type) {
- case CAIRO_GL_OPERAND_CONSTANT:
- break;
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- _cairo_gl_gradient_reference (dst->gradient.gradient);
- break;
- case CAIRO_GL_OPERAND_TEXTURE:
- cairo_surface_reference (&dst->texture.owns_surface->base);
- break;
- default:
- case CAIRO_GL_OPERAND_COUNT:
- ASSERT_NOT_REACHED;
- case CAIRO_GL_OPERAND_NONE:
- break;
- }
-}
-
-void
-_cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
-{
- switch (operand->type) {
- case CAIRO_GL_OPERAND_CONSTANT:
- break;
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- _cairo_gl_gradient_destroy (operand->gradient.gradient);
- break;
- case CAIRO_GL_OPERAND_TEXTURE:
- cairo_surface_destroy (&operand->texture.owns_surface->base);
- break;
- default:
- case CAIRO_GL_OPERAND_COUNT:
- ASSERT_NOT_REACHED;
- case CAIRO_GL_OPERAND_NONE:
- break;
- }
-
- operand->type = CAIRO_GL_OPERAND_NONE;
-}
-
-cairo_int_status_t
-_cairo_gl_operand_init (cairo_gl_operand_t *operand,
- const cairo_pattern_t *pattern,
- cairo_gl_surface_t *dst,
- const cairo_rectangle_int_t *sample,
- const cairo_rectangle_int_t *extents,
- cairo_bool_t use_texgen)
-{
- cairo_int_status_t status;
-
- TRACE ((stderr, "%s: type=%d\n", __FUNCTION__, pattern->type));
- switch (pattern->type) {
- case CAIRO_PATTERN_TYPE_SOLID:
- _cairo_gl_solid_operand_init (operand,
- &((cairo_solid_pattern_t *) pattern)->color);
- return CAIRO_STATUS_SUCCESS;
- case CAIRO_PATTERN_TYPE_SURFACE:
- status = _cairo_gl_surface_operand_init (operand, pattern, dst,
- sample, extents, use_texgen);
- if (status == CAIRO_INT_STATUS_UNSUPPORTED)
- break;
-
- return status;
-
- case CAIRO_PATTERN_TYPE_LINEAR:
- case CAIRO_PATTERN_TYPE_RADIAL:
- status = _cairo_gl_gradient_operand_init (operand, pattern, dst,
- use_texgen);
- if (status == CAIRO_INT_STATUS_UNSUPPORTED)
- break;
-
- return status;
-
- default:
- case CAIRO_PATTERN_TYPE_MESH:
- case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
- break;
- }
-
- return _cairo_gl_pattern_texture_setup (operand, pattern, dst, extents);
-}
-
-cairo_filter_t
-_cairo_gl_operand_get_filter (cairo_gl_operand_t *operand)
-{
- cairo_filter_t filter;
-
- switch ((int) operand->type) {
- case CAIRO_GL_OPERAND_TEXTURE:
- filter = operand->texture.attributes.filter;
- break;
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- filter = CAIRO_FILTER_BILINEAR;
- break;
- default:
- filter = CAIRO_FILTER_DEFAULT;
- break;
- }
-
- return filter;
-}
-
-GLint
-_cairo_gl_operand_get_gl_filter (cairo_gl_operand_t *operand)
-{
- cairo_filter_t filter = _cairo_gl_operand_get_filter (operand);
-
- return filter != CAIRO_FILTER_FAST && filter != CAIRO_FILTER_NEAREST ?
- GL_LINEAR :
- GL_NEAREST;
-}
-
-cairo_extend_t
-_cairo_gl_operand_get_extend (cairo_gl_operand_t *operand)
-{
- cairo_extend_t extend;
-
- switch ((int) operand->type) {
- case CAIRO_GL_OPERAND_TEXTURE:
- extend = operand->texture.attributes.extend;
- break;
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- extend = operand->gradient.extend;
- break;
- default:
- extend = CAIRO_EXTEND_NONE;
- break;
- }
-
- return extend;
-}
-
-
-void
-_cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
- cairo_gl_operand_t *operand,
- cairo_gl_tex_t tex_unit)
-{
- const cairo_matrix_t *texgen = NULL;
-
- switch (operand->type) {
- default:
- case CAIRO_GL_OPERAND_COUNT:
- ASSERT_NOT_REACHED;
- case CAIRO_GL_OPERAND_NONE:
- return;
-
- case CAIRO_GL_OPERAND_CONSTANT:
- _cairo_gl_shader_bind_vec4 (ctx,
- ctx->current_shader->constant_location[tex_unit],
- operand->constant.color[0],
- operand->constant.color[1],
- operand->constant.color[2],
- operand->constant.color[3]);
- return;
-
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- _cairo_gl_shader_bind_float (ctx,
- ctx->current_shader->a_location[tex_unit],
- operand->gradient.a);
- /* fall through */
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- _cairo_gl_shader_bind_vec3 (ctx,
- ctx->current_shader->circle_d_location[tex_unit],
- operand->gradient.circle_d.center.x,
- operand->gradient.circle_d.center.y,
- operand->gradient.circle_d.radius);
- _cairo_gl_shader_bind_float (ctx,
- ctx->current_shader->radius_0_location[tex_unit],
- operand->gradient.radius_0);
- /* fall through */
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_TEXTURE:
- /*
- * For GLES2 we use shaders to implement GL_CLAMP_TO_BORDER (used
- * with CAIRO_EXTEND_NONE). When bilinear filtering is enabled,
- * these shaders need the texture dimensions for their calculations.
- */
- if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3 ||
- ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2) &&
- _cairo_gl_operand_get_extend (operand) == CAIRO_EXTEND_NONE &&
- _cairo_gl_operand_get_gl_filter (operand) == GL_LINEAR)
- {
- float width, height;
- if (operand->type == CAIRO_GL_OPERAND_TEXTURE) {
- width = operand->texture.surface->width;
- height = operand->texture.surface->height;
- }
- else {
- width = operand->gradient.gradient->cache_entry.size,
- height = 1;
- }
- _cairo_gl_shader_bind_vec2 (ctx,
- ctx->current_shader->texdims_location[tex_unit],
- width, height);
- }
- break;
- }
-
- if (operand->type == CAIRO_GL_OPERAND_TEXTURE) {
- if (operand->texture.texgen)
- texgen = &operand->texture.attributes.matrix;
- } else {
- if (operand->gradient.texgen)
- texgen = &operand->gradient.m;
- }
- if (texgen) {
- _cairo_gl_shader_bind_matrix(ctx,
- ctx->current_shader->texgen_location[tex_unit],
- texgen);
- }
-}
-
-
-cairo_bool_t
-_cairo_gl_operand_needs_setup (cairo_gl_operand_t *dest,
- cairo_gl_operand_t *source,
- unsigned int vertex_offset)
-{
- if (dest->type != source->type)
- return TRUE;
- if (dest->vertex_offset != vertex_offset)
- return TRUE;
-
- switch (source->type) {
- case CAIRO_GL_OPERAND_NONE:
- return FALSE;
- case CAIRO_GL_OPERAND_CONSTANT:
- return dest->constant.color[0] != source->constant.color[0] ||
- dest->constant.color[1] != source->constant.color[1] ||
- dest->constant.color[2] != source->constant.color[2] ||
- dest->constant.color[3] != source->constant.color[3];
- case CAIRO_GL_OPERAND_TEXTURE:
- return dest->texture.surface != source->texture.surface ||
- dest->texture.attributes.extend != source->texture.attributes.extend ||
- dest->texture.attributes.filter != source->texture.attributes.filter ||
- dest->texture.attributes.has_component_alpha != source->texture.attributes.has_component_alpha;
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- /* XXX: improve this */
- return TRUE;
- default:
- case CAIRO_GL_OPERAND_COUNT:
- ASSERT_NOT_REACHED;
- break;
- }
- return TRUE;
-}
-
-unsigned int
-_cairo_gl_operand_get_vertex_size (const cairo_gl_operand_t *operand)
-{
- switch (operand->type) {
- default:
- case CAIRO_GL_OPERAND_COUNT:
- ASSERT_NOT_REACHED;
- case CAIRO_GL_OPERAND_NONE:
- case CAIRO_GL_OPERAND_CONSTANT:
- return 0;
- case CAIRO_GL_OPERAND_TEXTURE:
- return operand->texture.texgen ? 0 : 2 * sizeof (GLfloat);
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- return operand->gradient.texgen ? 0 : 2 * sizeof (GLfloat);
- }
-}
-
-void
-_cairo_gl_operand_emit (cairo_gl_operand_t *operand,
- GLfloat ** vb,
- GLfloat x,
- GLfloat y)
-{
- switch (operand->type) {
- default:
- case CAIRO_GL_OPERAND_COUNT:
- ASSERT_NOT_REACHED;
- case CAIRO_GL_OPERAND_NONE:
- case CAIRO_GL_OPERAND_CONSTANT:
- break;
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- if (! operand->gradient.texgen) {
- double s = x;
- double t = y;
-
- cairo_matrix_transform_point (&operand->gradient.m, &s, &t);
-
- *(*vb)++ = s;
- *(*vb)++ = t;
- }
- break;
- case CAIRO_GL_OPERAND_TEXTURE:
- if (! operand->texture.texgen) {
- cairo_surface_attributes_t *src_attributes = &operand->texture.attributes;
- double s = x;
- double t = y;
-
- cairo_matrix_transform_point (&src_attributes->matrix, &s, &t);
- *(*vb)++ = s;
- *(*vb)++ = t;
- }
- break;
- }
-}
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
deleted file mode 100644
index f02a58763..000000000
--- a/src/cairo-gl-private.h
+++ /dev/null
@@ -1,865 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 Eric Anholt
- * Copyright © 2009 Chris Wilson
- * Copyright © 2005,2010 Red Hat, Inc
- * Copyright © 2011 Linaro Limited
- *
- * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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):
- * Benjamin Otte <otte@gnome.org>
- * Carl Worth <cworth@cworth.org>
- * Chris Wilson <chris@chris-wilson.co.uk>
- * Eric Anholt <eric@anholt.net>
- * T. Zachary Laine <whatwasthataddress@gmail.com>
- * Alexandros Frantzis <alexandros.frantzis@linaro.org>
- */
-
-#ifndef CAIRO_GL_PRIVATE_H
-#define CAIRO_GL_PRIVATE_H
-
-#define GL_GLEXT_PROTOTYPES
-
-#include "cairoint.h"
-
-#include "cairo-gl.h"
-#include "cairo-gl-gradient-private.h"
-
-#include "cairo-device-private.h"
-#include "cairo-error-private.h"
-#include "cairo-rtree-private.h"
-#include "cairo-scaled-font-private.h"
-#include "cairo-spans-compositor-private.h"
-#include "cairo-array-private.h"
-
-#include <assert.h>
-
-#if CAIRO_HAS_GLESV3_SURFACE
-#include <GLES3/gl3.h>
-#include <GLES3/gl3ext.h>
-#elif CAIRO_HAS_GLESV2_SURFACE
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#elif CAIRO_HAS_GL_SURFACE
-#include <GL/gl.h>
-#include <GL/glext.h>
-#endif
-
-#include "cairo-gl-ext-def-private.h"
-
-#define DEBUG_GL 0
-
-#if DEBUG_GL && __GNUC__
-#define UNSUPPORTED(reason) ({ \
- fprintf (stderr, \
- "cairo-gl: hit unsupported operation in %s(), line %d: %s\n", \
- __FUNCTION__, __LINE__, reason); \
- CAIRO_INT_STATUS_UNSUPPORTED; \
-})
-#else
-#define UNSUPPORTED(reason) CAIRO_INT_STATUS_UNSUPPORTED
-#endif
-
-#define CAIRO_GL_VERSION_ENCODE(major, minor) ( \
- ((major) * 256) \
- + ((minor) * 1))
-
-/* maximal number of shaders we keep in the cache.
- * Random number that is hopefully big enough to not cause many cache evictions. */
-#define CAIRO_GL_MAX_SHADERS_PER_CONTEXT 64
-
-/* VBO size that we allocate, smaller size means we gotta flush more often,
- * but larger means hogging more memory and can cause trouble for drivers
- * (especially on embedded devices). Use the CAIRO_GL_VBO_SIZE environment
- * variable to set this to a different size. */
-#define CAIRO_GL_VBO_SIZE_DEFAULT (1024*1024)
-
-typedef struct _cairo_gl_surface cairo_gl_surface_t;
-
-/* GL flavor is the type of GL supported by the underlying platform. */
-typedef enum cairo_gl_flavor {
- CAIRO_GL_FLAVOR_NONE = 0,
- CAIRO_GL_FLAVOR_DESKTOP = 1,
- CAIRO_GL_FLAVOR_ES2 = 2,
- CAIRO_GL_FLAVOR_ES3 = 3
-} cairo_gl_flavor_t;
-
-/* Indices for vertex attributes used by BindAttribLocation, etc. */
-enum {
- CAIRO_GL_VERTEX_ATTRIB_INDEX = 0,
- CAIRO_GL_COLOR_ATTRIB_INDEX = 1,
- CAIRO_GL_TEXCOORD0_ATTRIB_INDEX = 2,
- CAIRO_GL_TEXCOORD1_ATTRIB_INDEX = CAIRO_GL_TEXCOORD0_ATTRIB_INDEX + 1
-};
-
-typedef enum cairo_gl_operand_type {
- CAIRO_GL_OPERAND_NONE,
- CAIRO_GL_OPERAND_CONSTANT,
- CAIRO_GL_OPERAND_TEXTURE,
- CAIRO_GL_OPERAND_LINEAR_GRADIENT,
- CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0,
- CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE,
- CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT,
-
- CAIRO_GL_OPERAND_COUNT
-} cairo_gl_operand_type_t;
-
-/* This union structure describes a potential source or mask operand to the
- * compositing equation.
- */
-typedef struct cairo_gl_operand {
- cairo_gl_operand_type_t type;
- union {
- struct {
- GLuint tex;
- cairo_gl_surface_t *surface;
- cairo_gl_surface_t *owns_surface;
- cairo_surface_attributes_t attributes;
- int texgen;
- } texture;
- struct {
- GLfloat color[4];
- } constant;
- struct {
- cairo_gl_gradient_t *gradient;
- cairo_matrix_t m;
- cairo_circle_double_t circle_d;
- double radius_0, a;
- cairo_extend_t extend;
- int texgen;
- } gradient;
- };
- unsigned int vertex_offset;
-} cairo_gl_operand_t;
-
-typedef struct cairo_gl_source {
- cairo_surface_t base;
- cairo_gl_operand_t operand;
-} cairo_gl_source_t;
-
-struct _cairo_gl_surface {
- cairo_surface_t base;
- cairo_gl_operand_t operand;
-
- int width, height;
-
- GLuint tex; /* GL texture object containing our data. */
- GLuint fb; /* GL framebuffer object wrapping our data. */
- GLuint depth_stencil; /* GL renderbuffer object for holding stencil buffer clip. */
-
-#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV3_SURFACE
- GLuint msaa_rb; /* The ARB MSAA path uses a renderbuffer. */
- GLuint msaa_fb;
-#endif
- GLuint msaa_depth_stencil;
-
- cairo_bool_t stencil_and_msaa_caps_initialized;
- cairo_bool_t supports_stencil; /* Stencil support for for non-texture surfaces. */
- cairo_bool_t supports_msaa;
- GLint num_samples;
- cairo_bool_t msaa_active; /* Whether the multisampling
- framebuffer is active or not. */
- cairo_bool_t content_in_texture; /* whether we just uploaded image
- to texture, used for certain
- gles2 extensions and glesv3 */
- cairo_clip_t *clip_on_stencil_buffer;
-
- int owns_tex;
- cairo_bool_t needs_update;
-
- cairo_region_t *clip_region;
-};
-
-typedef struct cairo_gl_glyph_cache {
- cairo_rtree_t rtree;
- cairo_gl_surface_t *surface;
-} cairo_gl_glyph_cache_t;
-
-typedef enum cairo_gl_tex {
- CAIRO_GL_TEX_SOURCE = 0,
- CAIRO_GL_TEX_MASK = 1,
- CAIRO_GL_TEX_TEMP = 2
-} cairo_gl_tex_t;
-
-typedef struct cairo_gl_shader {
- GLuint fragment_shader;
- GLuint program;
- GLint mvp_location;
- GLint constant_location[2];
- GLint a_location[2];
- GLint circle_d_location[2];
- GLint radius_0_location[2];
- GLint texdims_location[2];
- GLint texgen_location[2];
-} cairo_gl_shader_t;
-
-typedef enum cairo_gl_shader_in {
- CAIRO_GL_SHADER_IN_NORMAL,
- CAIRO_GL_SHADER_IN_CA_SOURCE,
- CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA,
-
- CAIRO_GL_SHADER_IN_COUNT
-} cairo_gl_shader_in_t;
-
-typedef enum cairo_gl_var_type {
- CAIRO_GL_VAR_NONE,
- CAIRO_GL_VAR_TEXCOORDS,
- CAIRO_GL_VAR_TEXGEN,
-} cairo_gl_var_type_t;
-
-typedef enum cairo_gl_primitive_type {
- CAIRO_GL_PRIMITIVE_TYPE_TRIANGLES,
- CAIRO_GL_PRIMITIVE_TYPE_TRISTRIPS
-} cairo_gl_primitive_type_t;
-
-typedef void (*cairo_gl_emit_rect_t) (cairo_gl_context_t *ctx,
- GLfloat x1, GLfloat y1,
- GLfloat x2, GLfloat y2);
-
-typedef void (*cairo_gl_emit_span_t) (cairo_gl_context_t *ctx,
- GLfloat x1, GLfloat y1,
- GLfloat x2, GLfloat y2,
- uint8_t alpha);
-
-typedef void (*cairo_gl_emit_glyph_t) (cairo_gl_context_t *ctx,
- GLfloat x1, GLfloat y1,
- GLfloat x2, GLfloat y2,
- GLfloat glyph_x1, GLfloat glyph_y1,
- GLfloat glyph_x2, GLfloat glyph_y2);
-
-#define cairo_gl_var_type_hash(src,mask,spans,dest) ((spans) << 5) | ((mask) << 3 | (src << 1) | (dest))
-#define CAIRO_GL_VAR_TYPE_MAX (1 << 6)
-
-typedef void (*cairo_gl_generic_func_t)(void);
-typedef cairo_gl_generic_func_t (*cairo_gl_get_proc_addr_func_t)(const char *procname);
-
-typedef struct _cairo_gl_dispatch {
- /* Buffers */
- void (*GenBuffers) (GLsizei n, GLuint *buffers);
- void (*BindBuffer) (GLenum target, GLuint buffer);
- void (*BufferData) (GLenum target, GLsizeiptr size,
- const GLvoid* data, GLenum usage);
- GLvoid *(*MapBuffer) (GLenum target, GLenum access);
- GLboolean (*UnmapBuffer) (GLenum target);
-
- /* Shaders */
- GLuint (*CreateShader) (GLenum type);
- void (*ShaderSource) (GLuint shader, GLsizei count,
- const GLchar** string, const GLint* length);
- void (*CompileShader) (GLuint shader);
- void (*GetShaderiv) (GLuint shader, GLenum pname, GLint *params);
- void (*GetShaderInfoLog) (GLuint shader, GLsizei bufSize,
- GLsizei *length, GLchar *infoLog);
- void (*DeleteShader) (GLuint shader);
-
- /* Programs */
- GLuint (*CreateProgram) (void);
- void (*AttachShader) (GLuint program, GLuint shader);
- void (*DeleteProgram) (GLuint program);
- void (*LinkProgram) (GLuint program);
- void (*UseProgram) (GLuint program);
- void (*GetProgramiv) (GLuint program, GLenum pname, GLint *params);
- void (*GetProgramInfoLog) (GLuint program, GLsizei bufSize,
- GLsizei *length, GLchar *infoLog);
-
- /* Uniforms */
- GLint (*GetUniformLocation) (GLuint program, const GLchar* name);
- void (*Uniform1f) (GLint location, GLfloat x);
- void (*Uniform2f) (GLint location, GLfloat x, GLfloat y);
- void (*Uniform3f) (GLint location, GLfloat x, GLfloat y, GLfloat z);
- void (*Uniform4f) (GLint location, GLfloat x, GLfloat y, GLfloat z,
- GLfloat w);
- void (*UniformMatrix3fv) (GLint location, GLsizei count,
- GLboolean transpose, const GLfloat *value);
- void (*UniformMatrix4fv) (GLint location, GLsizei count,
- GLboolean transpose, const GLfloat *value);
- void (*Uniform1i) (GLint location, GLint x);
-
- /* Attributes */
- void (*BindAttribLocation) (GLuint program, GLuint index,
- const GLchar *name);
- void (*VertexAttribPointer) (GLuint index, GLint size, GLenum type,
- GLboolean normalized, GLsizei stride,
- const GLvoid *pointer);
- void (*EnableVertexAttribArray) (GLuint index);
- void (*DisableVertexAttribArray) (GLuint index);
-
- /* Framebuffer objects */
- void (*GenFramebuffers) (GLsizei n, GLuint* framebuffers);
- void (*BindFramebuffer) (GLenum target, GLuint framebuffer);
- void (*FramebufferTexture2D) (GLenum target, GLenum attachment,
- GLenum textarget, GLuint texture,
- GLint level);
- GLenum (*CheckFramebufferStatus) (GLenum target);
- void (*DeleteFramebuffers) (GLsizei n, const GLuint* framebuffers);
- void (*GenRenderbuffers) (GLsizei n, GLuint *renderbuffers);
- void (*BindRenderbuffer) (GLenum target, GLuint renderbuffer);
- void (*RenderbufferStorage) (GLenum target, GLenum internal_format,
- GLsizei width, GLsizei height);
- void (*FramebufferRenderbuffer) (GLenum target, GLenum attachment,
- GLenum renderbuffer_ttarget, GLuint renderbuffer);
- void (*DeleteRenderbuffers) (GLsizei n, GLuint *renderbuffers);
- void (*BlitFramebuffer) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
- GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
- GLbitfield mask, GLenum filter);
- void (*RenderbufferStorageMultisample) (GLenum target, GLsizei samples,
- GLenum internalformat,
- GLsizei width, GLsizei height);
- void (*FramebufferTexture2DMultisample) (GLenum target, GLenum attachment,
- GLenum textarget, GLuint texture,
- GLint level, GLsizei samples);
-} cairo_gl_dispatch_t;
-
-struct _cairo_gl_context {
- cairo_device_t base;
-
- const cairo_compositor_t *compositor;
-
- GLuint texture_load_pbo;
- GLint max_framebuffer_size;
- GLint max_texture_size;
- GLint max_textures;
- GLenum tex_target;
-
- GLint num_samples;
- cairo_bool_t supports_msaa;
- char *vb;
-
- cairo_bool_t has_shader_support;
-
- GLuint vertex_shaders[CAIRO_GL_VAR_TYPE_MAX];
- cairo_gl_shader_t fill_rectangles_shader;
- cairo_cache_t shaders;
-
- cairo_cache_t gradients;
-
- cairo_gl_glyph_cache_t glyph_cache[2];
- cairo_list_t fonts;
-
- cairo_gl_surface_t *current_target;
- cairo_operator_t current_operator;
- cairo_gl_shader_t *pre_shader; /* for component alpha */
- cairo_gl_shader_t *current_shader;
-
- cairo_gl_operand_t operands[2];
- cairo_bool_t spans;
-
- unsigned int vbo_size;
- unsigned int vb_offset;
- unsigned int vertex_size;
- cairo_region_t *clip_region;
- cairo_clip_t *clip;
-
- cairo_gl_primitive_type_t primitive_type;
- cairo_array_t tristrip_indices;
-
- cairo_bool_t has_mesa_pack_invert;
- cairo_gl_dispatch_t dispatch;
- GLfloat modelviewprojection_matrix[16];
- cairo_gl_flavor_t gl_flavor;
- cairo_bool_t has_map_buffer;
- cairo_bool_t has_packed_depth_stencil;
- cairo_bool_t has_npot_repeat;
- cairo_bool_t can_read_bgra;
-
- cairo_bool_t thread_aware;
-
- void (*acquire) (void *ctx);
- void (*release) (void *ctx);
-
- void (*make_current) (void *ctx, cairo_gl_surface_t *surface);
- void (*swap_buffers)(void *ctx, cairo_gl_surface_t *surface);
- void (*destroy) (void *ctx);
-};
-
-typedef struct _cairo_gl_composite {
- cairo_gl_surface_t *dst;
- cairo_operator_t op;
- cairo_region_t *clip_region;
-
- cairo_gl_operand_t src;
- cairo_gl_operand_t mask;
- cairo_bool_t spans;
-
- cairo_clip_t *clip;
- cairo_bool_t multisample;
-} cairo_gl_composite_t;
-
-typedef struct _cairo_gl_font {
- cairo_scaled_font_private_t base;
- cairo_device_t *device;
- cairo_list_t link;
-} cairo_gl_font_t;
-
-static cairo_always_inline GLenum
-_cairo_gl_get_error (void)
-{
- GLenum err = glGetError();
-
- if (unlikely (err))
- while (glGetError ());
-
- return err;
-}
-
-static inline cairo_device_t *
-_cairo_gl_context_create_in_error (cairo_status_t status)
-{
- return (cairo_device_t *) _cairo_device_create_in_error (status);
-}
-
-cairo_private cairo_status_t
-_cairo_gl_context_init (cairo_gl_context_t *ctx);
-
-cairo_private void
-_cairo_gl_surface_init (cairo_device_t *device,
- cairo_gl_surface_t *surface,
- cairo_content_t content,
- int width, int height);
-
-static cairo_always_inline cairo_bool_t cairo_warn
-_cairo_gl_surface_is_texture (cairo_gl_surface_t *surface)
-{
- return surface->tex != 0;
-}
-
-cairo_private cairo_status_t
-_cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
- cairo_image_surface_t *src,
- int src_x, int src_y,
- int width, int height,
- int dst_x, int dst_y,
- cairo_bool_t force_flush);
-
-cairo_private cairo_int_status_t
-_cairo_gl_surface_resolve_multisampling (cairo_gl_surface_t *surface);
-
-static cairo_always_inline cairo_bool_t
-_cairo_gl_device_has_glsl (cairo_device_t *device)
-{
- return ((cairo_gl_context_t *) device)->has_shader_support;
-}
-
-static cairo_always_inline cairo_bool_t
-_cairo_gl_device_requires_power_of_two_textures (cairo_device_t *device)
-{
- return ((cairo_gl_context_t *) device)->tex_target == GL_TEXTURE_RECTANGLE;
-}
-
-static cairo_always_inline cairo_status_t cairo_warn
-_cairo_gl_context_acquire (cairo_device_t *device,
- cairo_gl_context_t **ctx)
-{
- cairo_status_t status;
-
- status = cairo_device_acquire (device);
- if (unlikely (status))
- return status;
-
- /* clear potential previous GL errors */
- _cairo_gl_get_error ();
-
- *ctx = (cairo_gl_context_t *) device;
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_always_inline cairo_warn cairo_status_t
-_cairo_gl_context_release (cairo_gl_context_t *ctx, cairo_status_t status)
-{
- GLenum err;
-
- err = _cairo_gl_get_error ();
-
- if (unlikely (err)) {
- cairo_status_t new_status;
- new_status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
- if (status == CAIRO_STATUS_SUCCESS)
- status = new_status;
- }
-
- cairo_device_release (&(ctx)->base);
-
- return status;
-}
-
-cairo_private void
-_cairo_gl_context_set_destination (cairo_gl_context_t *ctx,
- cairo_gl_surface_t *surface,
- cairo_bool_t multisampling);
-
-cairo_private void
-_cairo_gl_context_bind_framebuffer (cairo_gl_context_t *ctx,
- cairo_gl_surface_t *surface,
- cairo_bool_t multisampling);
-
-cairo_private cairo_gl_emit_rect_t
-_cairo_gl_context_choose_emit_rect (cairo_gl_context_t *ctx);
-
-cairo_private void
-_cairo_gl_context_emit_rect (cairo_gl_context_t *ctx,
- GLfloat x1, GLfloat y1,
- GLfloat x2, GLfloat y2);
-
-cairo_private cairo_gl_emit_span_t
-_cairo_gl_context_choose_emit_span (cairo_gl_context_t *ctx);
-
-cairo_private cairo_gl_emit_glyph_t
-_cairo_gl_context_choose_emit_glyph (cairo_gl_context_t *ctx);
-
-cairo_private void
-_cairo_gl_context_activate (cairo_gl_context_t *ctx,
- cairo_gl_tex_t tex_unit);
-
-cairo_private cairo_bool_t
-_cairo_gl_operator_is_supported (cairo_operator_t op);
-
-cairo_private cairo_bool_t
-_cairo_gl_ensure_stencil (cairo_gl_context_t *ctx,
- cairo_gl_surface_t *surface);
-
-cairo_private cairo_status_t
-_cairo_gl_composite_init (cairo_gl_composite_t *setup,
- cairo_operator_t op,
- cairo_gl_surface_t *dst,
- cairo_bool_t has_component_alpha);
-
-cairo_private void
-_cairo_gl_composite_fini (cairo_gl_composite_t *setup);
-
-cairo_private cairo_status_t
-_cairo_gl_composite_set_operator (cairo_gl_composite_t *setup,
- cairo_operator_t op,
- cairo_bool_t assume_component_alpha);
-
-cairo_private void
-_cairo_gl_composite_set_clip_region (cairo_gl_composite_t *setup,
- cairo_region_t *clip_region);
-
-cairo_private void
-_cairo_gl_composite_set_clip(cairo_gl_composite_t *setup,
- cairo_clip_t *clip);
-
-cairo_private cairo_int_status_t
-_cairo_gl_composite_set_source (cairo_gl_composite_t *setup,
- const cairo_pattern_t *pattern,
- const cairo_rectangle_int_t *sample,
- const cairo_rectangle_int_t *extents,
- cairo_bool_t use_texgen);
-
-cairo_private void
-_cairo_gl_composite_set_solid_source (cairo_gl_composite_t *setup,
- const cairo_color_t *color);
-
-cairo_private void
-_cairo_gl_composite_set_source_operand (cairo_gl_composite_t *setup,
- const cairo_gl_operand_t *source);
-
-cairo_private cairo_int_status_t
-_cairo_gl_composite_set_mask (cairo_gl_composite_t *setup,
- const cairo_pattern_t *pattern,
- const cairo_rectangle_int_t *sample,
- const cairo_rectangle_int_t *extents,
- cairo_bool_t use_texgen);
-
-cairo_private void
-_cairo_gl_composite_set_mask_operand (cairo_gl_composite_t *setup,
- const cairo_gl_operand_t *mask);
-
-cairo_private void
-_cairo_gl_composite_set_spans (cairo_gl_composite_t *setup);
-
-cairo_private void
-_cairo_gl_composite_set_multisample (cairo_gl_composite_t *setup);
-
-cairo_private cairo_status_t
-_cairo_gl_composite_begin (cairo_gl_composite_t *setup,
- cairo_gl_context_t **ctx);
-
-cairo_private cairo_status_t
-_cairo_gl_set_operands_and_operator (cairo_gl_composite_t *setup,
- cairo_gl_context_t *ctx);
-
-cairo_private void
-_cairo_gl_composite_flush (cairo_gl_context_t *ctx);
-
-cairo_private cairo_int_status_t
-_cairo_gl_composite_emit_quad_as_tristrip (cairo_gl_context_t *ctx,
- cairo_gl_composite_t *setup,
- const cairo_point_t quad[4]);
-
-cairo_private cairo_int_status_t
-_cairo_gl_composite_emit_triangle_as_tristrip (cairo_gl_context_t *ctx,
- cairo_gl_composite_t *setup,
- const cairo_point_t triangle[3]);
-
-cairo_private void
-_cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
- cairo_gl_tex_t tex_unit);
-
-cairo_private cairo_bool_t
-_cairo_gl_get_image_format_and_type (cairo_gl_flavor_t flavor,
- pixman_format_code_t pixman_format,
- GLenum *internal_format, GLenum *format,
- GLenum *type, cairo_bool_t *has_alpha,
- cairo_bool_t *needs_swap);
-
-cairo_private void
-_cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache);
-
-cairo_private void
-_cairo_gl_glyph_cache_fini (cairo_gl_context_t *ctx,
- cairo_gl_glyph_cache_t *cache);
-
-cairo_private cairo_int_status_t
-_cairo_gl_surface_show_glyphs (void *abstract_dst,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- const cairo_clip_t *clip,
- int *remaining_glyphs);
-
-cairo_private cairo_status_t
-_cairo_gl_context_init_shaders (cairo_gl_context_t *ctx);
-
-cairo_private void
-_cairo_gl_context_fini_shaders (cairo_gl_context_t *ctx);
-
-static cairo_always_inline cairo_bool_t
-_cairo_gl_context_is_flushed (cairo_gl_context_t *ctx)
-{
- return ctx->vb_offset == 0;
-}
-
-cairo_private cairo_status_t
-_cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
- cairo_gl_operand_t *source,
- cairo_gl_operand_t *mask,
- cairo_bool_t use_coverage,
- cairo_gl_shader_in_t in,
- cairo_gl_shader_t **shader);
-
-cairo_private void
-_cairo_gl_shader_bind_float (cairo_gl_context_t *ctx,
- GLint location,
- float value);
-
-cairo_private void
-_cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx,
- GLint location,
- float value0, float value1);
-
-cairo_private void
-_cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx,
- GLint location,
- float value0,
- float value1,
- float value2);
-
-cairo_private void
-_cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx,
- GLint location,
- float value0, float value1,
- float value2, float value3);
-
-cairo_private void
-_cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
- GLint location,
- const cairo_matrix_t* m);
-
-cairo_private void
-_cairo_gl_shader_bind_matrix4f (cairo_gl_context_t *ctx,
- GLint location,
- GLfloat* gl_m);
-
-cairo_private void
-_cairo_gl_set_shader (cairo_gl_context_t *ctx,
- cairo_gl_shader_t *shader);
-
-cairo_private void
-_cairo_gl_shader_fini (cairo_gl_context_t *ctx, cairo_gl_shader_t *shader);
-
-cairo_private int
-_cairo_gl_get_version (void);
-
-cairo_private cairo_gl_flavor_t
-_cairo_gl_get_flavor (void);
-
-cairo_private unsigned long
-_cairo_gl_get_vbo_size (void);
-
-cairo_private cairo_bool_t
-_cairo_gl_has_extension (const char *ext);
-
-cairo_private cairo_status_t
-_cairo_gl_dispatch_init(cairo_gl_dispatch_t *dispatch,
- cairo_gl_get_proc_addr_func_t get_proc_addr);
-
-cairo_private cairo_int_status_t
-_cairo_gl_operand_init (cairo_gl_operand_t *operand,
- const cairo_pattern_t *pattern,
- cairo_gl_surface_t *dst,
- const cairo_rectangle_int_t *sample,
- const cairo_rectangle_int_t *extents,
- cairo_bool_t use_texgen);
-
-cairo_private void
-_cairo_gl_solid_operand_init (cairo_gl_operand_t *operand,
- const cairo_color_t *color);
-
-cairo_private cairo_filter_t
-_cairo_gl_operand_get_filter (cairo_gl_operand_t *operand);
-
-cairo_private GLint
-_cairo_gl_operand_get_gl_filter (cairo_gl_operand_t *operand);
-
-cairo_private cairo_extend_t
-_cairo_gl_operand_get_extend (cairo_gl_operand_t *operand);
-
-cairo_private unsigned int
-_cairo_gl_operand_get_vertex_size (const cairo_gl_operand_t *operand);
-
-cairo_private cairo_bool_t
-_cairo_gl_operand_needs_setup (cairo_gl_operand_t *dest,
- cairo_gl_operand_t *source,
- unsigned int vertex_offset);
-
-cairo_private void
-_cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
- cairo_gl_operand_t *operand,
- cairo_gl_tex_t tex_unit);
-
-cairo_private void
-_cairo_gl_operand_emit (cairo_gl_operand_t *operand,
- GLfloat ** vb,
- GLfloat x,
- GLfloat y);
-
-cairo_private void
-_cairo_gl_operand_copy (cairo_gl_operand_t *dst,
- const cairo_gl_operand_t *src);
-
-cairo_private void
-_cairo_gl_operand_translate (cairo_gl_operand_t *operand,
- double tx, double ty);
-
-cairo_private void
-_cairo_gl_operand_destroy (cairo_gl_operand_t *operand);
-
-cairo_private const cairo_compositor_t *
-_cairo_gl_msaa_compositor_get (void);
-
-cairo_private const cairo_compositor_t *
-_cairo_gl_span_compositor_get (void);
-
-cairo_private const cairo_compositor_t *
-_cairo_gl_traps_compositor_get (void);
-
-cairo_private cairo_int_status_t
-_cairo_gl_check_composite_glyphs (const cairo_composite_rectangles_t *extents,
- cairo_scaled_font_t *scaled_font,
- cairo_glyph_t *glyphs,
- int *num_glyphs);
-
-cairo_private cairo_int_status_t
-_cairo_gl_composite_glyphs (void *_dst,
- cairo_operator_t op,
- cairo_surface_t *_src,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- cairo_composite_glyphs_info_t *info);
-
-cairo_private cairo_int_status_t
-_cairo_gl_composite_glyphs_with_clip (void *_dst,
- cairo_operator_t op,
- cairo_surface_t *_src,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- cairo_composite_glyphs_info_t *info,
- cairo_clip_t *clip);
-
-cairo_private void
-_cairo_gl_ensure_framebuffer (cairo_gl_context_t *ctx,
- cairo_gl_surface_t *surface);
-
-cairo_private cairo_surface_t *
-_cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
- cairo_content_t content,
- int width,
- int height);
-
-cairo_private cairo_surface_t *
-_cairo_gl_surface_create_scratch_for_caching (cairo_gl_context_t *ctx,
- cairo_content_t content,
- int width,
- int height);
-
-cairo_private cairo_surface_t *
-_cairo_gl_pattern_to_source (cairo_surface_t *dst,
- const cairo_pattern_t *pattern,
- cairo_bool_t is_mask,
- const cairo_rectangle_int_t *extents,
- const cairo_rectangle_int_t *sample,
- int *src_x, int *src_y);
-
-cairo_private cairo_int_status_t
-_cairo_gl_msaa_compositor_draw_clip (cairo_gl_context_t *ctx,
- cairo_gl_composite_t *setup,
- cairo_clip_t *clip);
-
-cairo_private cairo_surface_t *
-_cairo_gl_white_source (void);
-
-cairo_private void
-_cairo_gl_scissor_to_rectangle (cairo_gl_surface_t *surface,
- const cairo_rectangle_int_t *r);
-
-static inline cairo_gl_operand_t *
-source_to_operand (cairo_surface_t *surface)
-{
- cairo_gl_source_t *source = (cairo_gl_source_t *)surface;
- return source ? &source->operand : NULL;
-}
-
-static inline void
-_cairo_gl_glyph_cache_unlock (cairo_gl_glyph_cache_t *cache)
-{
- _cairo_rtree_unpin (&cache->rtree);
-}
-
-
-slim_hidden_proto (cairo_gl_surface_create);
-slim_hidden_proto (cairo_gl_surface_create_for_texture);
-
-#endif /* CAIRO_GL_PRIVATE_H */
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
deleted file mode 100644
index b70c177f2..000000000
--- a/src/cairo-gl-shaders.c
+++ /dev/null
@@ -1,1111 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 T. Zachary Laine
- * Copyright © 2010 Eric Anholt
- * Copyright © 2010 Red Hat, Inc
- * Copyright © 2010 Linaro Limited
- *
- * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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 T. Zachary Laine.
- *
- * Contributor(s):
- * Benjamin Otte <otte@gnome.org>
- * Eric Anholt <eric@anholt.net>
- * T. Zachary Laine <whatwasthataddress@gmail.com>
- * Alexandros Frantzis <alexandros.frantzis@linaro.org>
- * H. Lewin <heiko.lewin@gmx.de>
- */
-
-#include "cairoint.h"
-#include "cairo-gl-private.h"
-#include "cairo-error-private.h"
-#include "cairo-output-stream-private.h"
-
-static cairo_status_t
-_cairo_gl_shader_compile_and_link (cairo_gl_context_t *ctx,
- cairo_gl_shader_t *shader,
- cairo_gl_var_type_t src,
- cairo_gl_var_type_t mask,
- cairo_bool_t use_coverage,
- const char *fragment_text);
-
-typedef struct _cairo_shader_cache_entry {
- cairo_cache_entry_t base;
-
- unsigned vertex;
-
- cairo_gl_operand_type_t src;
- cairo_gl_operand_type_t mask;
- cairo_gl_operand_type_t dest;
- cairo_bool_t use_coverage;
-
- cairo_gl_shader_in_t in;
- GLint src_gl_filter;
- cairo_bool_t src_border_fade;
- cairo_extend_t src_extend;
- GLint mask_gl_filter;
- cairo_bool_t mask_border_fade;
- cairo_extend_t mask_extend;
-
- cairo_gl_context_t *ctx; /* XXX: needed to destroy the program */
- cairo_gl_shader_t shader;
-} cairo_shader_cache_entry_t;
-
-static cairo_bool_t
-_cairo_gl_shader_cache_equal_desktop (const void *key_a, const void *key_b)
-{
- const cairo_shader_cache_entry_t *a = key_a;
- const cairo_shader_cache_entry_t *b = key_b;
- cairo_bool_t both_have_npot_repeat =
- a->ctx->has_npot_repeat && b->ctx->has_npot_repeat;
-
- return (a->vertex == b->vertex &&
- a->src == b->src &&
- a->mask == b->mask &&
- a->dest == b->dest &&
- a->use_coverage == b->use_coverage &&
- a->in == b->in &&
- (both_have_npot_repeat || a->src_extend == b->src_extend) &&
- (both_have_npot_repeat || a->mask_extend == b->mask_extend));
-}
-
-/*
- * For GLES2 we use more complicated shaders to implement missing GL
- * features. In this case we need more parameters to uniquely identify
- * a shader (vs _cairo_gl_shader_cache_equal_desktop()).
- */
-static cairo_bool_t
-_cairo_gl_shader_cache_equal_gles2 (const void *key_a, const void *key_b)
-{
- const cairo_shader_cache_entry_t *a = key_a;
- const cairo_shader_cache_entry_t *b = key_b;
- cairo_bool_t both_have_npot_repeat =
- a->ctx->has_npot_repeat && b->ctx->has_npot_repeat;
-
- return (a->vertex == b->vertex &&
- a->src == b->src &&
- a->mask == b->mask &&
- a->dest == b->dest &&
- a->use_coverage == b->use_coverage &&
- a->in == b->in &&
- a->src_gl_filter == b->src_gl_filter &&
- a->src_border_fade == b->src_border_fade &&
- (both_have_npot_repeat || a->src_extend == b->src_extend) &&
- a->mask_gl_filter == b->mask_gl_filter &&
- a->mask_border_fade == b->mask_border_fade &&
- (both_have_npot_repeat || a->mask_extend == b->mask_extend));
-}
-
-static unsigned long
-_cairo_gl_shader_cache_hash (const cairo_shader_cache_entry_t *entry)
-{
- return (((uint32_t)entry->src << 24) | (entry->mask << 16) | (entry->dest << 8) | (entry->in << 1) | entry->use_coverage) ^ entry->vertex;
-}
-
-static void
-_cairo_gl_shader_cache_destroy (void *data)
-{
- cairo_shader_cache_entry_t *entry = data;
-
- _cairo_gl_shader_fini (entry->ctx, &entry->shader);
- if (entry->ctx->current_shader == &entry->shader)
- entry->ctx->current_shader = NULL;
- free (entry);
-}
-
-static void
-_cairo_gl_shader_init (cairo_gl_shader_t *shader)
-{
- shader->fragment_shader = 0;
- shader->program = 0;
-}
-
-cairo_status_t
-_cairo_gl_context_init_shaders (cairo_gl_context_t *ctx)
-{
- static const char *fill_fs_source =
- "#ifdef GL_ES\n"
- "precision mediump float;\n"
- "#endif\n"
- "uniform vec4 color;\n"
- "void main()\n"
- "{\n"
- " gl_FragColor = color;\n"
- "}\n";
- cairo_status_t status;
-
- if (_cairo_gl_get_version () >= CAIRO_GL_VERSION_ENCODE (2, 0) ||
- (_cairo_gl_has_extension ("GL_ARB_shader_objects") &&
- _cairo_gl_has_extension ("GL_ARB_fragment_shader") &&
- _cairo_gl_has_extension ("GL_ARB_vertex_shader"))) {
- ctx->has_shader_support = TRUE;
- } else {
- ctx->has_shader_support = FALSE;
- fprintf (stderr, "Error: The cairo gl backend requires shader support!\n");
- return CAIRO_STATUS_DEVICE_ERROR;
- }
-
- memset (ctx->vertex_shaders, 0, sizeof (ctx->vertex_shaders));
-
- status = _cairo_cache_init (&ctx->shaders,
- ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ?
- _cairo_gl_shader_cache_equal_desktop :
- _cairo_gl_shader_cache_equal_gles2,
- NULL,
- _cairo_gl_shader_cache_destroy,
- CAIRO_GL_MAX_SHADERS_PER_CONTEXT);
- if (unlikely (status))
- return status;
-
- _cairo_gl_shader_init (&ctx->fill_rectangles_shader);
- status = _cairo_gl_shader_compile_and_link (ctx,
- &ctx->fill_rectangles_shader,
- CAIRO_GL_VAR_NONE,
- CAIRO_GL_VAR_NONE,
- FALSE,
- fill_fs_source);
- if (unlikely (status))
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-void
-_cairo_gl_context_fini_shaders (cairo_gl_context_t *ctx)
-{
- int i;
-
- for (i = 0; i < CAIRO_GL_VAR_TYPE_MAX; i++) {
- if (ctx->vertex_shaders[i])
- ctx->dispatch.DeleteShader (ctx->vertex_shaders[i]);
- }
-
- _cairo_gl_shader_fini(ctx, &ctx->fill_rectangles_shader);
- _cairo_cache_fini (&ctx->shaders);
-}
-
-void
-_cairo_gl_shader_fini (cairo_gl_context_t *ctx,
- cairo_gl_shader_t *shader)
-{
- if (shader->fragment_shader)
- ctx->dispatch.DeleteShader (shader->fragment_shader);
-
- if (shader->program)
- ctx->dispatch.DeleteProgram (shader->program);
-}
-
-static const char *operand_names[] = { "source", "mask", "dest" };
-
-static cairo_gl_var_type_t
-cairo_gl_operand_get_var_type (cairo_gl_operand_t *operand)
-{
- switch (operand->type) {
- default:
- case CAIRO_GL_OPERAND_COUNT:
- ASSERT_NOT_REACHED;
- case CAIRO_GL_OPERAND_NONE:
- case CAIRO_GL_OPERAND_CONSTANT:
- return CAIRO_GL_VAR_NONE;
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- return operand->gradient.texgen ? CAIRO_GL_VAR_TEXGEN : CAIRO_GL_VAR_TEXCOORDS;
- case CAIRO_GL_OPERAND_TEXTURE:
- return operand->texture.texgen ? CAIRO_GL_VAR_TEXGEN : CAIRO_GL_VAR_TEXCOORDS;
- }
-}
-
-static void
-cairo_gl_shader_emit_variable (cairo_output_stream_t *stream,
- cairo_gl_var_type_t type,
- cairo_gl_tex_t name)
-{
- switch (type) {
- default:
- ASSERT_NOT_REACHED;
- case CAIRO_GL_VAR_NONE:
- break;
- case CAIRO_GL_VAR_TEXCOORDS:
- _cairo_output_stream_printf (stream,
- "attribute vec4 MultiTexCoord%d;\n"
- "varying vec2 %s_texcoords;\n",
- name,
- operand_names[name]);
- break;
- case CAIRO_GL_VAR_TEXGEN:
- _cairo_output_stream_printf (stream,
- "uniform mat3 %s_texgen;\n"
- "varying vec2 %s_texcoords;\n",
- operand_names[name],
- operand_names[name]);
- break;
- }
-}
-
-static void
-cairo_gl_shader_emit_vertex (cairo_output_stream_t *stream,
- cairo_gl_var_type_t type,
- cairo_gl_tex_t name)
-{
- switch (type) {
- default:
- ASSERT_NOT_REACHED;
- case CAIRO_GL_VAR_NONE:
- break;
- case CAIRO_GL_VAR_TEXCOORDS:
- _cairo_output_stream_printf (stream,
- " %s_texcoords = MultiTexCoord%d.xy;\n",
- operand_names[name], name);
- break;
-
- case CAIRO_GL_VAR_TEXGEN:
- _cairo_output_stream_printf (stream,
- " %s_texcoords = (%s_texgen * Vertex.xyw).xy;\n",
- operand_names[name], operand_names[name]);
- break;
- }
-}
-
-static void
-cairo_gl_shader_dcl_coverage (cairo_output_stream_t *stream)
-{
- _cairo_output_stream_printf (stream, "varying float coverage;\n");
-}
-
-static void
-cairo_gl_shader_def_coverage (cairo_output_stream_t *stream)
-{
- _cairo_output_stream_printf (stream, " coverage = Color.a;\n");
-}
-
-static cairo_status_t
-cairo_gl_shader_get_vertex_source (cairo_gl_var_type_t src,
- cairo_gl_var_type_t mask,
- cairo_bool_t use_coverage,
- cairo_gl_var_type_t dest,
- char **out)
-{
- cairo_output_stream_t *stream = _cairo_memory_stream_create ();
- unsigned char *source;
- unsigned long length;
- cairo_status_t status;
-
- cairo_gl_shader_emit_variable (stream, src, CAIRO_GL_TEX_SOURCE);
- cairo_gl_shader_emit_variable (stream, mask, CAIRO_GL_TEX_MASK);
- if (use_coverage)
- cairo_gl_shader_dcl_coverage (stream);
-
- _cairo_output_stream_printf (stream,
- "attribute vec4 Vertex;\n"
- "attribute vec4 Color;\n"
- "uniform mat4 ModelViewProjectionMatrix;\n"
- "void main()\n"
- "{\n"
- " gl_Position = ModelViewProjectionMatrix * Vertex;\n");
-
- cairo_gl_shader_emit_vertex (stream, src, CAIRO_GL_TEX_SOURCE);
- cairo_gl_shader_emit_vertex (stream, mask, CAIRO_GL_TEX_MASK);
- if (use_coverage)
- cairo_gl_shader_def_coverage (stream);
-
- _cairo_output_stream_write (stream,
- "}\n\0", 3);
-
- status = _cairo_memory_stream_destroy (stream, &source, &length);
- if (unlikely (status))
- return status;
-
- *out = (char *) source;
- return CAIRO_STATUS_SUCCESS;
-}
-
-/*
- * Returns whether an operand needs a special border fade fragment shader
- * to simulate the GL_CLAMP_TO_BORDER wrapping method that is missing in GLES2.
- */
-static cairo_bool_t
-_cairo_gl_shader_needs_border_fade (cairo_gl_operand_t *operand)
-{
- cairo_extend_t extend =_cairo_gl_operand_get_extend (operand);
-
- return extend == CAIRO_EXTEND_NONE &&
- (operand->type == CAIRO_GL_OPERAND_TEXTURE ||
- operand->type == CAIRO_GL_OPERAND_LINEAR_GRADIENT ||
- operand->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE ||
- operand->type == CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0);
-}
-
-static void
-cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
- cairo_gl_context_t *ctx,
- cairo_gl_operand_t *op,
- cairo_gl_tex_t name)
-{
- const char *namestr = operand_names[name];
- const char *rectstr = (ctx->tex_target == GL_TEXTURE_RECTANGLE ? "Rect" : "");
-
- switch (op->type) {
- case CAIRO_GL_OPERAND_COUNT:
- default:
- ASSERT_NOT_REACHED;
- break;
- case CAIRO_GL_OPERAND_NONE:
- _cairo_output_stream_printf (stream,
- "vec4 get_%s()\n"
- "{\n"
- " return vec4 (0, 0, 0, 1);\n"
- "}\n",
- namestr);
- break;
- case CAIRO_GL_OPERAND_CONSTANT:
- _cairo_output_stream_printf (stream,
- "uniform vec4 %s_constant;\n"
- "vec4 get_%s()\n"
- "{\n"
- " return %s_constant;\n"
- "}\n",
- namestr, namestr, namestr);
- break;
- case CAIRO_GL_OPERAND_TEXTURE:
- _cairo_output_stream_printf (stream,
- "uniform sampler2D%s %s_sampler;\n"
- "uniform vec2 %s_texdims;\n"
- "varying vec2 %s_texcoords;\n"
- "vec4 get_%s()\n"
- "{\n",
- rectstr, namestr, namestr, namestr, namestr);
- if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3 ||
- ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2) &&
- _cairo_gl_shader_needs_border_fade (op))
- {
- _cairo_output_stream_printf (stream,
- " vec2 border_fade = %s_border_fade (%s_texcoords, %s_texdims);\n"
- " vec4 texel = texture2D%s (%s_sampler, %s_texcoords);\n"
- " return texel * border_fade.x * border_fade.y;\n"
- "}\n",
- namestr, namestr, namestr, rectstr, namestr, namestr);
- }
- else
- {
- _cairo_output_stream_printf (stream,
- " return texture2D%s (%s_sampler, %s_wrap (%s_texcoords));\n"
- "}\n",
- rectstr, namestr, namestr, namestr);
- }
- break;
- case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- _cairo_output_stream_printf (stream,
- "varying vec2 %s_texcoords;\n"
- "uniform vec2 %s_texdims;\n"
- "uniform sampler2D%s %s_sampler;\n"
- "\n"
- "vec4 get_%s()\n"
- "{\n",
- namestr, namestr, rectstr, namestr, namestr);
- if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3 ||
- ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2) &&
- _cairo_gl_shader_needs_border_fade (op))
- {
- _cairo_output_stream_printf (stream,
- " float border_fade = %s_border_fade (%s_texcoords.x, %s_texdims.x);\n"
- " vec4 texel = texture2D%s (%s_sampler, vec2 (%s_texcoords.x, 0.5));\n"
- " return texel * border_fade;\n"
- "}\n",
- namestr, namestr, namestr, rectstr, namestr, namestr);
- }
- else
- {
- _cairo_output_stream_printf (stream,
- " return texture2D%s (%s_sampler, %s_wrap (vec2 (%s_texcoords.x, 0.5)));\n"
- "}\n",
- rectstr, namestr, namestr, namestr);
- }
- break;
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
- _cairo_output_stream_printf (stream,
- "varying vec2 %s_texcoords;\n"
- "uniform vec2 %s_texdims;\n"
- "uniform sampler2D%s %s_sampler;\n"
- "uniform vec3 %s_circle_d;\n"
- "uniform float %s_radius_0;\n"
- "\n"
- "vec4 get_%s()\n"
- "{\n"
- " vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n"
- " \n"
- " float B = dot (pos, %s_circle_d);\n"
- " float C = dot (pos, vec3 (pos.xy, -pos.z));\n"
- " \n"
- " float t = 0.5 * C / B;\n"
- " float is_valid = step (-%s_radius_0, t * %s_circle_d.z);\n",
- namestr, namestr, rectstr, namestr, namestr, namestr, namestr,
- namestr, namestr, namestr, namestr, namestr);
- if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3 ||
- ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2) &&
- _cairo_gl_shader_needs_border_fade (op))
- {
- _cairo_output_stream_printf (stream,
- " float border_fade = %s_border_fade (t, %s_texdims.x);\n"
- " vec4 texel = texture2D%s (%s_sampler, vec2 (t, 0.5));\n"
- " return mix (vec4 (0.0), texel * border_fade, is_valid);\n"
- "}\n",
- namestr, namestr, rectstr, namestr);
- }
- else
- {
- _cairo_output_stream_printf (stream,
- " vec4 texel = texture2D%s (%s_sampler, %s_wrap (vec2 (t, 0.5)));\n"
- " return mix (vec4 (0.0), texel, is_valid);\n"
- "}\n",
- rectstr, namestr, namestr);
- }
- break;
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
- _cairo_output_stream_printf (stream,
- "varying vec2 %s_texcoords;\n"
- "uniform vec2 %s_texdims;\n"
- "uniform sampler2D%s %s_sampler;\n"
- "uniform vec3 %s_circle_d;\n"
- "uniform float %s_a;\n"
- "uniform float %s_radius_0;\n"
- "\n"
- "vec4 get_%s()\n"
- "{\n"
- " vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n"
- " \n"
- " float B = dot (pos, %s_circle_d);\n"
- " float C = dot (pos, vec3 (pos.xy, -pos.z));\n"
- " \n"
- " float det = dot (vec2 (B, %s_a), vec2 (B, -C));\n"
- " float sqrtdet = sqrt (abs (det));\n"
- " vec2 t = (B + vec2 (sqrtdet, -sqrtdet)) / %s_a;\n"
- " \n"
- " vec2 is_valid = step (vec2 (0.0), t) * step (t, vec2(1.0));\n"
- " float has_color = step (0., det) * max (is_valid.x, is_valid.y);\n"
- " \n"
- " float upper_t = mix (t.y, t.x, is_valid.x);\n",
- namestr, namestr, rectstr, namestr, namestr, namestr, namestr,
- namestr, namestr, namestr, namestr, namestr, namestr);
- if ((ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3 ||
- ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2) &&
- _cairo_gl_shader_needs_border_fade (op))
- {
- _cairo_output_stream_printf (stream,
- " float border_fade = %s_border_fade (upper_t, %s_texdims.x);\n"
- " vec4 texel = texture2D%s (%s_sampler, vec2 (upper_t, 0.5));\n"
- " return mix (vec4 (0.0), texel * border_fade, has_color);\n"
- "}\n",
- namestr, namestr, rectstr, namestr);
- }
- else
- {
- _cairo_output_stream_printf (stream,
- " vec4 texel = texture2D%s (%s_sampler, %s_wrap (vec2(upper_t, 0.5)));\n"
- " return mix (vec4 (0.0), texel, has_color);\n"
- "}\n",
- rectstr, namestr, namestr);
- }
- break;
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
- _cairo_output_stream_printf (stream,
- "varying vec2 %s_texcoords;\n"
- "uniform sampler2D%s %s_sampler;\n"
- "uniform vec3 %s_circle_d;\n"
- "uniform float %s_a;\n"
- "uniform float %s_radius_0;\n"
- "\n"
- "vec4 get_%s()\n"
- "{\n"
- " vec3 pos = vec3 (%s_texcoords, %s_radius_0);\n"
- " \n"
- " float B = dot (pos, %s_circle_d);\n"
- " float C = dot (pos, vec3 (pos.xy, -pos.z));\n"
- " \n"
- " float det = dot (vec2 (B, %s_a), vec2 (B, -C));\n"
- " float sqrtdet = sqrt (abs (det));\n"
- " vec2 t = (B + vec2 (sqrtdet, -sqrtdet)) / %s_a;\n"
- " \n"
- " vec2 is_valid = step (vec2 (-%s_radius_0), t * %s_circle_d.z);\n"
- " float has_color = step (0., det) * max (is_valid.x, is_valid.y);\n"
- " \n"
- " float upper_t = mix (t.y, t.x, is_valid.x);\n"
- " vec4 texel = texture2D%s (%s_sampler, %s_wrap (vec2(upper_t, 0.5)));\n"
- " return mix (vec4 (0.0), texel, has_color);\n"
- "}\n",
- namestr, rectstr, namestr, namestr, namestr, namestr,
- namestr, namestr, namestr, namestr, namestr,
- namestr, namestr, namestr, rectstr, namestr, namestr);
- break;
- }
-}
-
-/*
- * Emits the border fade functions used by an operand.
- *
- * If bilinear filtering is used, the emitted function performs a linear
- * fade to transparency effect in the intervals [-1/2n, 1/2n] and
- * [1 - 1/2n, 1 + 1/2n] (n: texture size).
- *
- * If nearest filtering is used, the emitted function just returns
- * 0.0 for all values outside [0, 1).
- */
-static void
-_cairo_gl_shader_emit_border_fade (cairo_output_stream_t *stream,
- cairo_gl_operand_t *operand,
- cairo_gl_tex_t name)
-{
- const char *namestr = operand_names[name];
- GLint gl_filter = _cairo_gl_operand_get_gl_filter (operand);
-
- /* 2D version */
- _cairo_output_stream_printf (stream,
- "vec2 %s_border_fade (vec2 coords, vec2 dims)\n"
- "{\n",
- namestr);
-
- if (gl_filter == GL_LINEAR)
- _cairo_output_stream_printf (stream,
- " return clamp(-abs(dims * (coords - 0.5)) + (dims + vec2(1.0)) * 0.5, 0.0, 1.0);\n");
- else
- _cairo_output_stream_printf (stream,
- " bvec2 in_tex1 = greaterThanEqual (coords, vec2 (0.0));\n"
- " bvec2 in_tex2 = lessThan (coords, vec2 (1.0));\n"
- " return vec2 (float (all (in_tex1) && all (in_tex2)));\n");
-
- _cairo_output_stream_printf (stream, "}\n");
-
- /* 1D version */
- _cairo_output_stream_printf (stream,
- "float %s_border_fade (float x, float dim)\n"
- "{\n",
- namestr);
- if (gl_filter == GL_LINEAR)
- _cairo_output_stream_printf (stream,
- " return clamp(-abs(dim * (x - 0.5)) + (dim + 1.0) * 0.5, 0.0, 1.0);\n");
- else
- _cairo_output_stream_printf (stream,
- " bool in_tex = x >= 0.0 && x < 1.0;\n"
- " return float (in_tex);\n");
-
- _cairo_output_stream_printf (stream, "}\n");
-}
-
-/*
- * Emits the wrap function used by an operand.
- *
- * In OpenGL ES 2.0, repeat wrap modes (GL_REPEAT and GL_MIRRORED REPEAT) are
- * only available for NPOT textures if the GL_OES_texture_npot is supported.
- * If GL_OES_texture_npot is not supported, we need to implement the wrapping
- * functionality in the shader.
- */
-static void
-_cairo_gl_shader_emit_wrap (cairo_gl_context_t *ctx,
- cairo_output_stream_t *stream,
- cairo_gl_operand_t *operand,
- cairo_gl_tex_t name)
-{
- const char *namestr = operand_names[name];
- cairo_extend_t extend = _cairo_gl_operand_get_extend (operand);
-
- _cairo_output_stream_printf (stream,
- "vec2 %s_wrap(vec2 coords)\n"
- "{\n",
- namestr);
-
- if (! ctx->has_npot_repeat &&
- (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT))
- {
- if (extend == CAIRO_EXTEND_REPEAT) {
- _cairo_output_stream_printf (stream,
- " return fract(coords);\n");
- } else { /* CAIRO_EXTEND_REFLECT */
- _cairo_output_stream_printf (stream,
- " return mix(fract(coords), 1.0 - fract(coords), floor(mod(coords, 2.0)));\n");
- }
- }
- else
- {
- _cairo_output_stream_printf (stream, " return coords;\n");
- }
-
- _cairo_output_stream_printf (stream, "}\n");
-}
-
-static cairo_status_t
-cairo_gl_shader_get_fragment_source (cairo_gl_context_t *ctx,
- cairo_gl_shader_in_t in,
- cairo_gl_operand_t *src,
- cairo_gl_operand_t *mask,
- cairo_bool_t use_coverage,
- cairo_gl_operand_type_t dest_type,
- char **out)
-{
- cairo_output_stream_t *stream = _cairo_memory_stream_create ();
- unsigned char *source;
- unsigned long length;
- cairo_status_t status;
- const char *coverage_str;
-
- _cairo_output_stream_printf (stream,
- "#ifdef GL_ES\n"
- "precision mediump float;\n"
- "#endif\n");
-
- _cairo_gl_shader_emit_wrap (ctx, stream, src, CAIRO_GL_TEX_SOURCE);
- _cairo_gl_shader_emit_wrap (ctx, stream, mask, CAIRO_GL_TEX_MASK);
-
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3 ||
- ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2) {
- if (_cairo_gl_shader_needs_border_fade (src))
- _cairo_gl_shader_emit_border_fade (stream, src, CAIRO_GL_TEX_SOURCE);
- if (_cairo_gl_shader_needs_border_fade (mask))
- _cairo_gl_shader_emit_border_fade (stream, mask, CAIRO_GL_TEX_MASK);
- }
-
- cairo_gl_shader_emit_color (stream, ctx, src, CAIRO_GL_TEX_SOURCE);
- cairo_gl_shader_emit_color (stream, ctx, mask, CAIRO_GL_TEX_MASK);
-
- coverage_str = "";
- if (use_coverage) {
- _cairo_output_stream_printf (stream, "varying float coverage;\n");
- coverage_str = " * coverage";
- }
-
- _cairo_output_stream_printf (stream,
- "void main()\n"
- "{\n");
- switch (in) {
- case CAIRO_GL_SHADER_IN_COUNT:
- default:
- ASSERT_NOT_REACHED;
- case CAIRO_GL_SHADER_IN_NORMAL:
- _cairo_output_stream_printf (stream,
- " gl_FragColor = get_source() * get_mask().a%s;\n",
- coverage_str);
- break;
- case CAIRO_GL_SHADER_IN_CA_SOURCE:
- _cairo_output_stream_printf (stream,
- " gl_FragColor = get_source() * get_mask()%s;\n",
- coverage_str);
- break;
- case CAIRO_GL_SHADER_IN_CA_SOURCE_ALPHA:
- _cairo_output_stream_printf (stream,
- " gl_FragColor = get_source().a * get_mask()%s;\n",
- coverage_str);
- break;
- }
-
- _cairo_output_stream_write (stream,
- "}\n\0", 3);
-
- status = _cairo_memory_stream_destroy (stream, &source, &length);
- if (unlikely (status))
- return status;
-
- *out = (char *) source;
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-compile_shader (cairo_gl_context_t *ctx,
- GLuint *shader,
- GLenum type,
- const char *source)
-{
- cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
- GLint success, log_size, num_chars;
- char *log;
-
- *shader = dispatch->CreateShader (type);
- dispatch->ShaderSource (*shader, 1, &source, 0);
- dispatch->CompileShader (*shader);
- dispatch->GetShaderiv (*shader, GL_COMPILE_STATUS, &success);
-
- if (success)
- return;
-
- dispatch->GetShaderiv (*shader, GL_INFO_LOG_LENGTH, &log_size);
- if (log_size < 0) {
- printf ("OpenGL shader compilation failed.\n");
- ASSERT_NOT_REACHED;
- return;
- }
-
- log = _cairo_malloc (log_size + 1);
- dispatch->GetShaderInfoLog (*shader, log_size, &num_chars, log);
- log[num_chars] = '\0';
-
- printf ("OpenGL shader compilation failed. Shader:\n%s\n", source);
- printf ("OpenGL compilation log:\n%s\n", log);
-
- free (log);
- ASSERT_NOT_REACHED;
-}
-
-static void
-link_shader_program (cairo_gl_context_t *ctx,
- GLuint *program,
- GLuint vert,
- GLuint frag)
-{
- cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
- GLint success, log_size, num_chars;
- char *log;
-
- *program = dispatch->CreateProgram ();
- dispatch->AttachShader (*program, vert);
- dispatch->AttachShader (*program, frag);
-
- dispatch->BindAttribLocation (*program, CAIRO_GL_VERTEX_ATTRIB_INDEX,
- "Vertex");
- dispatch->BindAttribLocation (*program, CAIRO_GL_COLOR_ATTRIB_INDEX,
- "Color");
- dispatch->BindAttribLocation (*program, CAIRO_GL_TEXCOORD0_ATTRIB_INDEX,
- "MultiTexCoord0");
- dispatch->BindAttribLocation (*program, CAIRO_GL_TEXCOORD1_ATTRIB_INDEX,
- "MultiTexCoord1");
-
- dispatch->LinkProgram (*program);
- dispatch->GetProgramiv (*program, GL_LINK_STATUS, &success);
- if (success)
- return;
-
- dispatch->GetProgramiv (*program, GL_INFO_LOG_LENGTH, &log_size);
- if (log_size < 0) {
- printf ("OpenGL shader link failed.\n");
- ASSERT_NOT_REACHED;
- return;
- }
-
- log = _cairo_malloc (log_size + 1);
- dispatch->GetProgramInfoLog (*program, log_size, &num_chars, log);
- log[num_chars] = '\0';
-
- printf ("OpenGL shader link failed:\n%s\n", log);
- free (log);
- ASSERT_NOT_REACHED;
-}
-
-static GLint
-_cairo_gl_get_op_uniform_location(cairo_gl_context_t *ctx,
- cairo_gl_shader_t *shader,
- cairo_gl_tex_t tex_unit,
- const char *suffix)
-{
- cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
- char uniform_name[100];
- const char *unit_name[2] = { "source", "mask" };
-
- snprintf (uniform_name, sizeof (uniform_name), "%s_%s",
- unit_name[tex_unit], suffix);
-
- return dispatch->GetUniformLocation (shader->program, uniform_name);
-}
-
-static cairo_status_t
-_cairo_gl_shader_compile_and_link (cairo_gl_context_t *ctx,
- cairo_gl_shader_t *shader,
- cairo_gl_var_type_t src,
- cairo_gl_var_type_t mask,
- cairo_bool_t use_coverage,
- const char *fragment_text)
-{
- cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
- unsigned int vertex_shader;
- cairo_status_t status;
- int i;
-
- assert (shader->program == 0);
-
- vertex_shader = cairo_gl_var_type_hash (src, mask, use_coverage,
- CAIRO_GL_VAR_NONE);
- if (ctx->vertex_shaders[vertex_shader] == 0) {
- char *source;
-
- status = cairo_gl_shader_get_vertex_source (src,
- mask,
- use_coverage,
- CAIRO_GL_VAR_NONE,
- &source);
- if (unlikely (status))
- goto FAILURE;
-
- compile_shader (ctx, &ctx->vertex_shaders[vertex_shader],
- GL_VERTEX_SHADER, source);
- free (source);
- }
-
- compile_shader (ctx, &shader->fragment_shader,
- GL_FRAGMENT_SHADER, fragment_text);
-
- link_shader_program (ctx, &shader->program,
- ctx->vertex_shaders[vertex_shader],
- shader->fragment_shader);
-
- shader->mvp_location =
- dispatch->GetUniformLocation (shader->program,
- "ModelViewProjectionMatrix");
-
- for (i = 0; i < 2; i++) {
- shader->constant_location[i] =
- _cairo_gl_get_op_uniform_location (ctx, shader, i, "constant");
- shader->a_location[i] =
- _cairo_gl_get_op_uniform_location (ctx, shader, i, "a");
- shader->circle_d_location[i] =
- _cairo_gl_get_op_uniform_location (ctx, shader, i, "circle_d");
- shader->radius_0_location[i] =
- _cairo_gl_get_op_uniform_location (ctx, shader, i, "radius_0");
- shader->texdims_location[i] =
- _cairo_gl_get_op_uniform_location (ctx, shader, i, "texdims");
- shader->texgen_location[i] =
- _cairo_gl_get_op_uniform_location (ctx, shader, i, "texgen");
- }
-
- return CAIRO_STATUS_SUCCESS;
-
- FAILURE:
- _cairo_gl_shader_fini (ctx, shader);
- shader->fragment_shader = 0;
- shader->program = 0;
-
- return status;
-}
-
-/* We always bind the source to texture unit 0 if present, and mask to
- * texture unit 1 if present, so we can just initialize these once at
- * compile time.
- */
-static cairo_status_t
-_cairo_gl_shader_set_samplers (cairo_gl_context_t *ctx,
- cairo_gl_shader_t *shader)
-{
- cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
- GLint location;
- GLint saved_program;
-
- /* We have to save/restore the current program because we might be
- * asked for a different program while a shader is bound. This shouldn't
- * be a performance issue, since this is only called once per compile.
- */
- glGetIntegerv (GL_CURRENT_PROGRAM, &saved_program);
- dispatch->UseProgram (shader->program);
-
- location = dispatch->GetUniformLocation (shader->program, "source_sampler");
- if (location != -1) {
- dispatch->Uniform1i (location, CAIRO_GL_TEX_SOURCE);
- }
-
- location = dispatch->GetUniformLocation (shader->program, "mask_sampler");
- if (location != -1) {
- dispatch->Uniform1i (location, CAIRO_GL_TEX_MASK);
- }
- if(_cairo_gl_get_error()) return CAIRO_STATUS_DEVICE_ERROR;
- dispatch->UseProgram (saved_program);
- /* Pop and ignore a possible gl-error when restoring the previous program.
- * It may be that being selected in the gl-context was the last reference
- * to the shader.
- */
- _cairo_gl_get_error();
- return CAIRO_STATUS_SUCCESS;
-}
-
-void
-_cairo_gl_shader_bind_float (cairo_gl_context_t *ctx,
- GLint location,
- float value)
-{
- cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
- assert (location != -1);
- dispatch->Uniform1f (location, value);
-}
-
-void
-_cairo_gl_shader_bind_vec2 (cairo_gl_context_t *ctx,
- GLint location,
- float value0,
- float value1)
-{
- cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
- assert (location != -1);
- dispatch->Uniform2f (location, value0, value1);
-}
-
-void
-_cairo_gl_shader_bind_vec3 (cairo_gl_context_t *ctx,
- GLint location,
- float value0,
- float value1,
- float value2)
-{
- cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
- assert (location != -1);
- dispatch->Uniform3f (location, value0, value1, value2);
-}
-
-void
-_cairo_gl_shader_bind_vec4 (cairo_gl_context_t *ctx,
- GLint location,
- float value0, float value1,
- float value2, float value3)
-{
- cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
- assert (location != -1);
- dispatch->Uniform4f (location, value0, value1, value2, value3);
-}
-
-void
-_cairo_gl_shader_bind_matrix (cairo_gl_context_t *ctx,
- GLint location,
- const cairo_matrix_t* m)
-{
- cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
- float gl_m[9] = {
- m->xx, m->yx, 0,
- m->xy, m->yy, 0,
- m->x0, m->y0, 1
- };
- assert (location != -1);
- dispatch->UniformMatrix3fv (location, 1, GL_FALSE, gl_m);
-}
-
-void
-_cairo_gl_shader_bind_matrix4f (cairo_gl_context_t *ctx,
- GLint location, GLfloat* gl_m)
-{
- cairo_gl_dispatch_t *dispatch = &ctx->dispatch;
- assert (location != -1);
- dispatch->UniformMatrix4fv (location, 1, GL_FALSE, gl_m);
-}
-
-void
-_cairo_gl_set_shader (cairo_gl_context_t *ctx,
- cairo_gl_shader_t *shader)
-{
- if (ctx->current_shader == shader)
- return;
-
- if (shader)
- ctx->dispatch.UseProgram (shader->program);
- else
- ctx->dispatch.UseProgram (0);
-
- ctx->current_shader = shader;
-}
-
-cairo_status_t
-_cairo_gl_get_shader_by_type (cairo_gl_context_t *ctx,
- cairo_gl_operand_t *source,
- cairo_gl_operand_t *mask,
- cairo_bool_t use_coverage,
- cairo_gl_shader_in_t in,
- cairo_gl_shader_t **shader)
-{
- cairo_shader_cache_entry_t lookup, *entry;
- char *fs_source;
- cairo_status_t status;
-
- lookup.ctx = ctx;
-
- lookup.vertex = cairo_gl_var_type_hash (cairo_gl_operand_get_var_type (source),
- cairo_gl_operand_get_var_type (mask),
- use_coverage,
- CAIRO_GL_VAR_NONE);
-
- lookup.src = source->type;
- lookup.mask = mask->type;
- lookup.dest = CAIRO_GL_OPERAND_NONE;
- lookup.use_coverage = use_coverage;
- lookup.in = in;
- lookup.src_gl_filter = _cairo_gl_operand_get_gl_filter (source);
- lookup.src_border_fade = _cairo_gl_shader_needs_border_fade (source);
- lookup.src_extend = _cairo_gl_operand_get_extend (source);
- lookup.mask_gl_filter = _cairo_gl_operand_get_gl_filter (mask);
- lookup.mask_border_fade = _cairo_gl_shader_needs_border_fade (mask);
- lookup.mask_extend = _cairo_gl_operand_get_extend (mask);
- lookup.base.hash = _cairo_gl_shader_cache_hash (&lookup);
- lookup.base.size = 1;
-
- entry = _cairo_cache_lookup (&ctx->shaders, &lookup.base);
- if (entry) {
- assert (entry->shader.program);
- *shader = &entry->shader;
- return CAIRO_STATUS_SUCCESS;
- }
-
- status = cairo_gl_shader_get_fragment_source (ctx,
- in,
- source,
- mask,
- use_coverage,
- CAIRO_GL_OPERAND_NONE,
- &fs_source);
- if (unlikely (status))
- return status;
-
- entry = _cairo_malloc (sizeof (cairo_shader_cache_entry_t));
- if (unlikely (entry == NULL)) {
- free (fs_source);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- memcpy (entry, &lookup, sizeof (cairo_shader_cache_entry_t));
-
- entry->ctx = ctx;
- _cairo_gl_shader_init (&entry->shader);
- status = _cairo_gl_shader_compile_and_link (ctx,
- &entry->shader,
- cairo_gl_operand_get_var_type (source),
- cairo_gl_operand_get_var_type (mask),
- use_coverage,
- fs_source);
- free (fs_source);
-
- if (unlikely (status)) {
- free (entry);
- return status;
- }
-
- status = _cairo_gl_shader_set_samplers (ctx, &entry->shader);
- if (unlikely (status)) {
- _cairo_gl_shader_fini (ctx, &entry->shader);
- free (entry);
- return status;
- }
-
- status = _cairo_cache_insert (&ctx->shaders, &entry->base);
- if (unlikely (status)) {
- _cairo_gl_shader_fini (ctx, &entry->shader);
- free (entry);
- return status;
- }
-
- *shader = &entry->shader;
-
- return CAIRO_STATUS_SUCCESS;
-}
diff --git a/src/cairo-gl-source.c b/src/cairo-gl-source.c
deleted file mode 100644
index 7e0ee4a82..000000000
--- a/src/cairo-gl-source.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2011 Intel Corporation
- *
- * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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):
- * Chris Wilson <chris@chris-wilson.co.uk>
- */
-
-#include "cairoint.h"
-
-#include "cairo-gl-private.h"
-
-#include "cairo-surface-backend-private.h"
-
-static cairo_status_t
-_cairo_gl_source_finish (void *abstract_surface)
-{
- cairo_gl_source_t *source = abstract_surface;
-
- _cairo_gl_operand_destroy (&source->operand);
- return CAIRO_STATUS_SUCCESS;
-}
-
-static const cairo_surface_backend_t cairo_gl_source_backend = {
- CAIRO_SURFACE_TYPE_GL,
- _cairo_gl_source_finish,
- NULL, /* read-only wrapper */
-};
-
-cairo_surface_t *
-_cairo_gl_pattern_to_source (cairo_surface_t *dst,
- const cairo_pattern_t *pattern,
- cairo_bool_t is_mask,
- const cairo_rectangle_int_t *extents,
- const cairo_rectangle_int_t *sample,
- int *src_x, int *src_y)
-{
- cairo_gl_source_t *source;
- cairo_int_status_t status;
-
- TRACE ((stderr, "%s\n", __FUNCTION__));
- if (pattern == NULL)
- return _cairo_gl_white_source ();
-
- source = _cairo_malloc (sizeof (*source));
- if (unlikely (source == NULL))
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
-
- _cairo_surface_init (&source->base,
- &cairo_gl_source_backend,
- NULL, /* device */
- CAIRO_CONTENT_COLOR_ALPHA,
- FALSE); /* is_vector */
-
- *src_x = *src_y = 0;
- status = _cairo_gl_operand_init (&source->operand, pattern,
- (cairo_gl_surface_t *)dst,
- sample, extents,
- FALSE);
- if (unlikely (status)) {
- cairo_surface_destroy (&source->base);
- return _cairo_surface_create_in_error (status);
- }
-
- return &source->base;
-}
-
-cairo_surface_t *
-_cairo_gl_white_source (void)
-{
- cairo_gl_source_t *source;
-
- source = _cairo_malloc (sizeof (*source));
- if (unlikely (source == NULL))
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
-
- _cairo_surface_init (&source->base,
- &cairo_gl_source_backend,
- NULL, /* device */
- CAIRO_CONTENT_COLOR_ALPHA,
- FALSE); /* is_vector */
-
- _cairo_gl_solid_operand_init (&source->operand, CAIRO_COLOR_WHITE);
-
- return &source->base;
-}
diff --git a/src/cairo-gl-spans-compositor.c b/src/cairo-gl-spans-compositor.c
deleted file mode 100644
index 0a4538a04..000000000
--- a/src/cairo-gl-spans-compositor.c
+++ /dev/null
@@ -1,556 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 Eric Anholt
- * Copyright © 2009 Chris Wilson
- * Copyright © 2005,2010 Red Hat, Inc
- * Copyright © 2011 Intel Corporation
- *
- * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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):
- * Benjamin Otte <otte@gnome.org>
- * Carl Worth <cworth@cworth.org>
- * Chris Wilson <chris@chris-wilson.co.uk>
- * Eric Anholt <eric@anholt.net>
- */
-
-#include "cairoint.h"
-
-#include "cairo-gl-private.h"
-
-#include "cairo-composite-rectangles-private.h"
-#include "cairo-compositor-private.h"
-#include "cairo-default-context-private.h"
-#include "cairo-error-private.h"
-#include "cairo-image-surface-private.h"
-#include "cairo-spans-compositor-private.h"
-#include "cairo-surface-backend-private.h"
-
-typedef struct _cairo_gl_span_renderer {
- cairo_span_renderer_t base;
-
- cairo_gl_composite_t setup;
- double opacity;
-
- cairo_gl_emit_span_t emit;
-
- int xmin, xmax;
- int ymin, ymax;
-
- cairo_gl_context_t *ctx;
-} cairo_gl_span_renderer_t;
-
-static cairo_status_t
-_cairo_gl_bounded_opaque_spans (void *abstract_renderer,
- int y, int height,
- const cairo_half_open_span_t *spans,
- unsigned num_spans)
-{
- cairo_gl_span_renderer_t *r = abstract_renderer;
- cairo_gl_emit_span_t emit = r->emit;
-
- if (num_spans == 0)
- return CAIRO_STATUS_SUCCESS;
-
- do {
- if (spans[0].coverage) {
- emit (r->ctx,
- spans[0].x, y,
- spans[1].x, y + height,
- spans[0].coverage);
- }
-
- spans++;
- } while (--num_spans > 1);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_bounded_spans (void *abstract_renderer,
- int y, int height,
- const cairo_half_open_span_t *spans,
- unsigned num_spans)
-{
- cairo_gl_span_renderer_t *r = abstract_renderer;
- cairo_gl_emit_span_t emit = r->emit;
-
- if (num_spans == 0)
- return CAIRO_STATUS_SUCCESS;
-
- do {
- if (spans[0].coverage) {
- emit (r->ctx,
- spans[0].x, y,
- spans[1].x, y + height,
- r->opacity * spans[0].coverage);
- }
-
- spans++;
- } while (--num_spans > 1);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_unbounded_spans (void *abstract_renderer,
- int y, int height,
- const cairo_half_open_span_t *spans,
- unsigned num_spans)
-{
- cairo_gl_span_renderer_t *r = abstract_renderer;
- cairo_gl_emit_span_t emit = r->emit;
-
- if (y > r->ymin) {
- emit (r->ctx,
- r->xmin, r->ymin,
- r->xmax, y,
- 0);
- }
-
- if (num_spans == 0) {
- emit (r->ctx,
- r->xmin, y,
- r->xmax, y + height,
- 0);
- } else {
- if (spans[0].x != r->xmin) {
- emit (r->ctx,
- r->xmin, y,
- spans[0].x, y + height,
- 0);
- }
-
- do {
- emit (r->ctx,
- spans[0].x, y,
- spans[1].x, y + height,
- r->opacity * spans[0].coverage);
- spans++;
- } while (--num_spans > 1);
-
- if (spans[0].x != r->xmax) {
- emit (r->ctx,
- spans[0].x, y,
- r->xmax, y + height,
- 0);
- }
- }
-
- r->ymin = y + height;
- return CAIRO_STATUS_SUCCESS;
-}
-
-/* XXX */
-static cairo_status_t
-_cairo_gl_clipped_spans (void *abstract_renderer,
- int y, int height,
- const cairo_half_open_span_t *spans,
- unsigned num_spans)
-{
- cairo_gl_span_renderer_t *r = abstract_renderer;
- cairo_gl_emit_span_t emit = r->emit;
-
- if (y > r->ymin) {
- emit (r->ctx,
- r->xmin, r->ymin,
- r->xmax, y,
- 0);
- }
-
- if (num_spans == 0) {
- emit (r->ctx,
- r->xmin, y,
- r->xmax, y + height,
- 0);
- } else {
- if (spans[0].x != r->xmin) {
- emit (r->ctx,
- r->xmin, y,
- spans[0].x, y + height,
- 0);
- }
-
- do {
- emit (r->ctx,
- spans[0].x, y,
- spans[1].x, y + height,
- r->opacity * spans[0].coverage);
- spans++;
- } while (--num_spans > 1);
-
- if (spans[0].x != r->xmax) {
- emit (r->ctx,
- spans[0].x, y,
- r->xmax, y + height,
- 0);
- }
- }
-
- r->ymin = y + height;
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_finish_unbounded_spans (void *abstract_renderer)
-{
- cairo_gl_span_renderer_t *r = abstract_renderer;
- cairo_gl_emit_span_t emit = r->emit;
-
- if (r->ymax > r->ymin) {
- emit (r->ctx,
- r->xmin, r->ymin,
- r->xmax, r->ymax,
- 0);
- }
-
- return _cairo_gl_context_release (r->ctx, CAIRO_STATUS_SUCCESS);
-}
-
-static cairo_status_t
-_cairo_gl_finish_bounded_spans (void *abstract_renderer)
-{
- cairo_gl_span_renderer_t *r = abstract_renderer;
-
- return _cairo_gl_context_release (r->ctx, CAIRO_STATUS_SUCCESS);
-}
-
-static void
-emit_aligned_boxes (cairo_gl_context_t *ctx,
- const cairo_boxes_t *boxes)
-{
- const struct _cairo_boxes_chunk *chunk;
- cairo_gl_emit_rect_t emit = _cairo_gl_context_choose_emit_rect (ctx);
- int i;
-
- TRACE ((stderr, "%s: num_boxes=%d\n", __FUNCTION__, boxes->num_boxes));
- for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
- for (i = 0; i < chunk->count; i++) {
- int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
- int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
- int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
- int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
- emit (ctx, x1, y1, x2, y2);
- }
- }
-}
-
-static cairo_int_status_t
-fill_boxes (void *_dst,
- cairo_operator_t op,
- const cairo_color_t *color,
- cairo_boxes_t *boxes)
-{
- cairo_gl_composite_t setup;
- cairo_gl_context_t *ctx;
- cairo_int_status_t status;
-
- TRACE ((stderr, "%s\n", __FUNCTION__));
- status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
- if (unlikely (status))
- goto FAIL;
-
- _cairo_gl_composite_set_solid_source (&setup, color);
-
- status = _cairo_gl_composite_begin (&setup, &ctx);
- if (unlikely (status))
- goto FAIL;
-
- emit_aligned_boxes (ctx, boxes);
- status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
-
-FAIL:
- _cairo_gl_composite_fini (&setup);
- return status;
-}
-
-static cairo_int_status_t
-draw_image_boxes (void *_dst,
- cairo_image_surface_t *image,
- cairo_boxes_t *boxes,
- int dx, int dy)
-{
- cairo_gl_surface_t *dst = _dst;
- struct _cairo_boxes_chunk *chunk;
- int i;
-
- for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
- for (i = 0; i < chunk->count; i++) {
- cairo_box_t *b = &chunk->base[i];
- int x = _cairo_fixed_integer_part (b->p1.x);
- int y = _cairo_fixed_integer_part (b->p1.y);
- int w = _cairo_fixed_integer_part (b->p2.x) - x;
- int h = _cairo_fixed_integer_part (b->p2.y) - y;
- cairo_status_t status;
-
- status = _cairo_gl_surface_draw_image (dst, image,
- x + dx, y + dy,
- w, h,
- x, y, TRUE);
- if (unlikely (status))
- return status;
- }
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t copy_boxes (void *_dst,
- cairo_surface_t *_src,
- cairo_boxes_t *boxes,
- const cairo_rectangle_int_t *extents,
- int dx, int dy)
-{
- cairo_gl_surface_t *dst = _dst;
- cairo_gl_surface_t *src = (cairo_gl_surface_t *)_src;
- cairo_gl_composite_t setup;
- cairo_gl_context_t *ctx;
- cairo_int_status_t status;
-
- TRACE ((stderr, "%s\n", __FUNCTION__));
- if (! _cairo_gl_surface_is_texture (src))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- if (src->base.device != dst->base.device)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_gl_composite_init (&setup, CAIRO_OPERATOR_SOURCE, _dst, FALSE);
- if (unlikely (status))
- goto FAIL;
-
- _cairo_gl_composite_set_source_operand (&setup, &src->operand);
- _cairo_gl_operand_translate (&setup.src, -dx, -dy);
-
- status = _cairo_gl_composite_begin (&setup, &ctx);
- if (unlikely (status))
- goto FAIL;
-
- emit_aligned_boxes (ctx, boxes);
- status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
-
-FAIL:
- _cairo_gl_composite_fini (&setup);
- return status;
-}
-
-static cairo_int_status_t
-composite_boxes (void *_dst,
- cairo_operator_t op,
- cairo_surface_t *abstract_src,
- cairo_surface_t *abstract_mask,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- cairo_boxes_t *boxes,
- const cairo_rectangle_int_t *extents)
-{
- cairo_gl_composite_t setup;
- cairo_gl_context_t *ctx;
- cairo_int_status_t status;
- cairo_gl_operand_t tmp_operand;
- cairo_gl_operand_t *src_operand;
-
- TRACE ((stderr, "%s mask=(%d,%d), dst=(%d, %d)\n", __FUNCTION__,
- mask_x, mask_y, dst_x, dst_y));
-
- if (abstract_mask) {
- if (op == CAIRO_OPERATOR_CLEAR) {
- _cairo_gl_solid_operand_init (&tmp_operand, CAIRO_COLOR_WHITE);
- src_operand = &tmp_operand;
- op = CAIRO_OPERATOR_DEST_OUT;
- } else if (op == CAIRO_OPERATOR_SOURCE) {
- /* requires a LERP in the shader between dest and source */
- return CAIRO_INT_STATUS_UNSUPPORTED;
- } else
- src_operand = source_to_operand (abstract_src);
- } else
- src_operand = source_to_operand (abstract_src);
-
- status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
- if (unlikely (status))
- goto FAIL;
-
- _cairo_gl_composite_set_source_operand (&setup,
- src_operand);
- _cairo_gl_operand_translate (&setup.src, -src_x, -src_y);
-
- _cairo_gl_composite_set_mask_operand (&setup,
- source_to_operand (abstract_mask));
- _cairo_gl_operand_translate (&setup.mask, -mask_x, -mask_y);
-
- status = _cairo_gl_composite_begin (&setup, &ctx);
- if (unlikely (status))
- goto FAIL;
-
- emit_aligned_boxes (ctx, boxes);
- status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
-
-FAIL:
- _cairo_gl_composite_fini (&setup);
- if (src_operand == &tmp_operand)
- _cairo_gl_operand_destroy (&tmp_operand);
- return status;
-}
-
-static cairo_int_status_t
-_cairo_gl_span_renderer_init (cairo_abstract_span_renderer_t *_r,
- const cairo_composite_rectangles_t *composite,
- cairo_antialias_t antialias,
- cairo_bool_t needs_clip)
-{
- cairo_gl_span_renderer_t *r = (cairo_gl_span_renderer_t *)_r;
- const cairo_pattern_t *source = &composite->source_pattern.base;
- cairo_operator_t op = composite->op;
- cairo_int_status_t status;
-
- if (op == CAIRO_OPERATOR_SOURCE) {
- if (! _cairo_pattern_is_opaque (&composite->source_pattern.base,
- &composite->source_sample_area))
- return CAIRO_INT_STATUS_UNSUPPORTED;
- op = CAIRO_OPERATOR_OVER;
- }
-
- /* XXX earlier! */
- if (op == CAIRO_OPERATOR_CLEAR) {
- source = &_cairo_pattern_white.base;
- op = CAIRO_OPERATOR_DEST_OUT;
- } else if (composite->surface->is_clear &&
- (op == CAIRO_OPERATOR_SOURCE ||
- op == CAIRO_OPERATOR_OVER ||
- op == CAIRO_OPERATOR_ADD)) {
- op = CAIRO_OPERATOR_SOURCE;
- } else if (op == CAIRO_OPERATOR_SOURCE) {
- /* no lerp equivalent without some major PITA */
- return CAIRO_INT_STATUS_UNSUPPORTED;
- } else if (! _cairo_gl_operator_is_supported (op))
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- status = _cairo_gl_composite_init (&r->setup,
- op, (cairo_gl_surface_t *)composite->surface,
- FALSE);
- if (unlikely (status))
- goto FAIL;
-
- status = _cairo_gl_composite_set_source (&r->setup, source,
- &composite->source_sample_area,
- &composite->unbounded,
- TRUE);
- if (unlikely (status))
- goto FAIL;
-
- r->opacity = 1.0;
- if (composite->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) {
- r->opacity = composite->mask_pattern.solid.color.alpha;
- } else {
- status = _cairo_gl_composite_set_mask (&r->setup,
- &composite->mask_pattern.base,
- &composite->mask_sample_area,
- &composite->unbounded,
- TRUE);
- if (unlikely (status))
- goto FAIL;
- }
-
- _cairo_gl_composite_set_spans (&r->setup);
-
- status = _cairo_gl_composite_begin (&r->setup, &r->ctx);
- if (unlikely (status))
- goto FAIL;
-
- r->emit = _cairo_gl_context_choose_emit_span (r->ctx);
- if (composite->is_bounded) {
- if (r->opacity == 1.)
- r->base.render_rows = _cairo_gl_bounded_opaque_spans;
- else
- r->base.render_rows = _cairo_gl_bounded_spans;
- r->base.finish = _cairo_gl_finish_bounded_spans;
- } else {
- if (needs_clip)
- r->base.render_rows = _cairo_gl_clipped_spans;
- else
- r->base.render_rows = _cairo_gl_unbounded_spans;
- r->base.finish = _cairo_gl_finish_unbounded_spans;
- r->xmin = composite->unbounded.x;
- r->xmax = composite->unbounded.x + composite->unbounded.width;
- r->ymin = composite->unbounded.y;
- r->ymax = composite->unbounded.y + composite->unbounded.height;
- }
-
- return CAIRO_STATUS_SUCCESS;
-
-FAIL:
- return status;
-}
-
-static void
-_cairo_gl_span_renderer_fini (cairo_abstract_span_renderer_t *_r,
- cairo_int_status_t status)
-{
- cairo_gl_span_renderer_t *r = (cairo_gl_span_renderer_t *) _r;
-
- if (status == CAIRO_INT_STATUS_UNSUPPORTED)
- return;
-
- if (status == CAIRO_INT_STATUS_SUCCESS)
- r->base.finish (r);
-
- _cairo_gl_composite_fini (&r->setup);
-}
-
-const cairo_compositor_t *
-_cairo_gl_span_compositor_get (void)
-{
- static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
- static cairo_spans_compositor_t spans;
- static cairo_compositor_t shape;
-
- if (_cairo_atomic_init_once_enter(&once)) {
- /* The fallback to traps here is essentially just for glyphs... */
- _cairo_shape_mask_compositor_init (&shape,
- _cairo_gl_traps_compositor_get());
- shape.glyphs = NULL;
-
- _cairo_spans_compositor_init (&spans, &shape);
- spans.fill_boxes = fill_boxes;
- spans.draw_image_boxes = draw_image_boxes;
- spans.copy_boxes = copy_boxes;
- //spans.check_composite_boxes = check_composite_boxes;
- spans.pattern_to_surface = _cairo_gl_pattern_to_source;
- spans.composite_boxes = composite_boxes;
- //spans.check_span_renderer = check_span_renderer;
- spans.renderer_init = _cairo_gl_span_renderer_init;
- spans.renderer_fini = _cairo_gl_span_renderer_fini;
-
- _cairo_atomic_init_once_leave(&once);
- }
-
- return &spans.base;
-}
diff --git a/src/cairo-gl-surface-legacy.c b/src/cairo-gl-surface-legacy.c
deleted file mode 100644
index 87dca2f03..000000000
--- a/src/cairo-gl-surface-legacy.c
+++ /dev/null
@@ -1,602 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 Eric Anholt
- * Copyright © 2009 Chris Wilson
- * Copyright © 2005,2010 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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):
- * Benjamin Otte <otte@gnome.org>
- * Carl Worth <cworth@cworth.org>
- * Chris Wilson <chris@chris-wilson.co.uk>
- * Eric Anholt <eric@anholt.net>
- */
-
-#include "cairoint.h"
-
-#include "cairo-composite-rectangles-private.h"
-#include "cairo-default-context-private.h"
-#include "cairo-error-private.h"
-#include "cairo-gl-private.h"
-#include "cairo-image-surface-inline.h"
-
-cairo_status_t
-_cairo_gl_surface_acquire_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t **image_out,
- cairo_rectangle_int_t *image_rect_out,
- void **image_extra)
-{
- cairo_gl_surface_t *surface = abstract_surface;
- cairo_int_status_t status;
-
- status = _cairo_gl_surface_deferred_clear (surface);
- if (unlikely (status))
- return status;
-
- *image_extra = NULL;
- return _cairo_gl_surface_get_image (surface, interest_rect, image_out,
- image_rect_out);
-}
-
-void
-_cairo_gl_surface_release_dest_image (void *abstract_surface,
- cairo_rectangle_int_t *interest_rect,
- cairo_image_surface_t *image,
- cairo_rectangle_int_t *image_rect,
- void *image_extra)
-{
- cairo_status_t status;
-
- status = _cairo_gl_surface_draw_image (abstract_surface, image,
- 0, 0,
- image->width, image->height,
- image_rect->x, image_rect->y,
- TRUE);
- /* as we created the image, its format should be directly applicable */
- assert (status == CAIRO_STATUS_SUCCESS);
-
- cairo_surface_destroy (&image->base);
-}
-
-cairo_status_t
-_cairo_gl_surface_clone_similar (void *abstract_surface,
- cairo_surface_t *src,
- int src_x,
- int src_y,
- int width,
- int height,
- int *clone_offset_x,
- int *clone_offset_y,
- cairo_surface_t **clone_out)
-{
- cairo_gl_surface_t *surface = abstract_surface;
- cairo_int_status_t status;
-
- /* XXX: Use GLCopyTexImage2D to clone non-texture-surfaces */
- if (src->device == surface->base.device &&
- _cairo_gl_surface_is_texture ((cairo_gl_surface_t *) src)) {
- status = _cairo_gl_surface_deferred_clear ((cairo_gl_surface_t *)src);
- if (unlikely (status))
- return status;
-
- *clone_offset_x = 0;
- *clone_offset_y = 0;
- *clone_out = cairo_surface_reference (src);
-
- return CAIRO_STATUS_SUCCESS;
- } else if (_cairo_surface_is_image (src)) {
- cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
- cairo_gl_surface_t *clone;
-
- clone = (cairo_gl_surface_t *)
- _cairo_gl_surface_create_similar (&surface->base,
- src->content,
- width, height);
- if (clone == NULL)
- return UNSUPPORTED ("create_similar failed");
- if (clone->base.status)
- return clone->base.status;
-
- status = _cairo_gl_surface_draw_image (clone, image_src,
- src_x, src_y,
- width, height,
- 0, 0, TRUE);
- 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;
- }
-
- return UNSUPPORTED ("unknown src surface type in clone_similar");
-}
-
-/* Creates a cairo-gl pattern surface for the given trapezoids */
-static cairo_status_t
-_cairo_gl_get_traps_pattern (cairo_gl_surface_t *dst,
- int dst_x, int dst_y,
- int width, int height,
- cairo_trapezoid_t *traps,
- int num_traps,
- cairo_antialias_t antialias,
- cairo_surface_pattern_t *pattern)
-{
- pixman_format_code_t pixman_format;
- pixman_image_t *image;
- cairo_surface_t *surface;
- int i;
-
- pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1,
- image = pixman_image_create_bits (pixman_format, width, height, NULL, 0);
- if (unlikely (image == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- for (i = 0; i < num_traps; i++) {
- pixman_trapezoid_t trap;
-
- trap.top = _cairo_fixed_to_16_16 (traps[i].top);
- trap.bottom = _cairo_fixed_to_16_16 (traps[i].bottom);
-
- trap.left.p1.x = _cairo_fixed_to_16_16 (traps[i].left.p1.x);
- trap.left.p1.y = _cairo_fixed_to_16_16 (traps[i].left.p1.y);
- trap.left.p2.x = _cairo_fixed_to_16_16 (traps[i].left.p2.x);
- trap.left.p2.y = _cairo_fixed_to_16_16 (traps[i].left.p2.y);
-
- trap.right.p1.x = _cairo_fixed_to_16_16 (traps[i].right.p1.x);
- trap.right.p1.y = _cairo_fixed_to_16_16 (traps[i].right.p1.y);
- trap.right.p2.x = _cairo_fixed_to_16_16 (traps[i].right.p2.x);
- trap.right.p2.y = _cairo_fixed_to_16_16 (traps[i].right.p2.y);
-
- pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y);
- }
-
- surface = _cairo_image_surface_create_for_pixman_image (image,
- pixman_format);
- if (unlikely (surface->status)) {
- pixman_image_unref (image);
- return surface->status;
- }
-
- _cairo_pattern_init_for_surface (pattern, surface);
- cairo_surface_destroy (surface);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_int_status_t
-_cairo_gl_surface_composite (cairo_operator_t op,
- const cairo_pattern_t *src,
- const cairo_pattern_t *mask,
- void *abstract_dst,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_region_t *clip_region)
-{
- cairo_gl_surface_t *dst = abstract_dst;
- cairo_gl_context_t *ctx;
- cairo_status_t status;
- cairo_gl_composite_t setup;
- cairo_rectangle_int_t rect = { dst_x, dst_y, width, height };
- int dx, dy;
-
- status = _cairo_gl_surface_deferred_clear (dst);
- if (unlikely (status))
- return status;
-
- if (op == CAIRO_OPERATOR_SOURCE &&
- mask == NULL &&
- src->type == CAIRO_PATTERN_TYPE_SURFACE &&
- _cairo_surface_is_image (((cairo_surface_pattern_t *) src)->surface) &&
- _cairo_matrix_is_integer_translation (&src->matrix, &dx, &dy)) {
- cairo_image_surface_t *image = (cairo_image_surface_t *)
- ((cairo_surface_pattern_t *) src)->surface;
- dx += src_x;
- dy += src_y;
- if (dx >= 0 &&
- dy >= 0 &&
- dx + width <= (unsigned int) image->width &&
- dy + height <= (unsigned int) image->height) {
- status = _cairo_gl_surface_draw_image (dst, image,
- dx, dy,
- width, height,
- dst_x, dst_y, TRUE);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
- }
- }
-
- status = _cairo_gl_composite_init (&setup, op, dst,
- mask && mask->has_component_alpha,
- &rect);
- if (unlikely (status))
- goto CLEANUP;
-
- status = _cairo_gl_composite_set_source (&setup, src,
- src_x, src_y,
- dst_x, dst_y,
- width, height);
- if (unlikely (status))
- goto CLEANUP;
-
- status = _cairo_gl_composite_set_mask (&setup, mask,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height);
- if (unlikely (status))
- goto CLEANUP;
-
- status = _cairo_gl_composite_begin (&setup, &ctx);
- if (unlikely (status))
- goto CLEANUP;
-
- if (clip_region != NULL) {
- int i, num_rectangles;
-
- num_rectangles = cairo_region_num_rectangles (clip_region);
-
- for (i = 0; i < num_rectangles; i++) {
- cairo_rectangle_int_t rect;
-
- cairo_region_get_rectangle (clip_region, i, &rect);
- _cairo_gl_composite_emit_rect (ctx,
- rect.x, rect.y,
- rect.x + rect.width, rect.y + rect.height,
- 0);
- }
- } else {
- _cairo_gl_composite_emit_rect (ctx,
- dst_x, dst_y,
- dst_x + width, dst_y + height,
- 0);
- }
-
- status = _cairo_gl_context_release (ctx, status);
-
- CLEANUP:
- _cairo_gl_composite_fini (&setup);
-
- return status;
-}
-
-cairo_int_status_t
-_cairo_gl_surface_composite_trapezoids (cairo_operator_t op,
- const cairo_pattern_t *pattern,
- void *abstract_dst,
- cairo_antialias_t antialias,
- int src_x, int src_y,
- int dst_x, int dst_y,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps,
- cairo_region_t *clip_region)
-{
- cairo_gl_surface_t *dst = abstract_dst;
- cairo_surface_pattern_t traps_pattern;
- cairo_int_status_t status;
-
- if (! _cairo_gl_operator_is_supported (op))
- return UNSUPPORTED ("unsupported operator");
-
- status = _cairo_gl_surface_deferred_clear (dst);
- if (unlikely (status))
- return status;
-
- status = _cairo_gl_get_traps_pattern (dst,
- dst_x, dst_y, width, height,
- traps, num_traps, antialias,
- &traps_pattern);
- if (unlikely (status))
- return status;
-
- status = _cairo_gl_surface_composite (op,
- pattern, &traps_pattern.base, dst,
- src_x, src_y,
- 0, 0,
- dst_x, dst_y,
- width, height,
- clip_region);
-
- _cairo_pattern_fini (&traps_pattern.base);
-
- assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
- return status;
-}
-
-cairo_int_status_t
-_cairo_gl_surface_fill_rectangles (void *abstract_dst,
- cairo_operator_t op,
- const cairo_color_t *color,
- cairo_rectangle_int_t *rects,
- int num_rects)
-{
- cairo_gl_surface_t *dst = abstract_dst;
- cairo_solid_pattern_t solid;
- cairo_gl_context_t *ctx;
- cairo_status_t status;
- cairo_gl_composite_t setup;
- int i;
-
- status = _cairo_gl_surface_deferred_clear (dst);
- if (unlikely (status))
- return status;
-
- status = _cairo_gl_composite_init (&setup, op, dst,
- FALSE,
- /* XXX */ NULL);
- if (unlikely (status))
- goto CLEANUP;
-
- _cairo_pattern_init_solid (&solid, color);
- status = _cairo_gl_composite_set_source (&setup, &solid.base,
- 0, 0,
- 0, 0,
- 0, 0);
- if (unlikely (status))
- goto CLEANUP;
-
- status = _cairo_gl_composite_set_mask (&setup, NULL,
- 0, 0,
- 0, 0,
- 0, 0);
- if (unlikely (status))
- goto CLEANUP;
-
- status = _cairo_gl_composite_begin (&setup, &ctx);
- if (unlikely (status))
- goto CLEANUP;
-
- for (i = 0; i < num_rects; i++) {
- _cairo_gl_composite_emit_rect (ctx,
- rects[i].x,
- rects[i].y,
- rects[i].x + rects[i].width,
- rects[i].y + rects[i].height,
- 0);
- }
-
- status = _cairo_gl_context_release (ctx, status);
-
- CLEANUP:
- _cairo_gl_composite_fini (&setup);
-
- return status;
-}
-
-typedef struct _cairo_gl_surface_span_renderer {
- cairo_span_renderer_t base;
-
- cairo_gl_composite_t setup;
-
- int xmin, xmax;
- int ymin, ymax;
-
- cairo_gl_context_t *ctx;
-} cairo_gl_surface_span_renderer_t;
-
-static cairo_status_t
-_cairo_gl_render_bounded_spans (void *abstract_renderer,
- int y, int height,
- const cairo_half_open_span_t *spans,
- unsigned num_spans)
-{
- cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
- if (num_spans == 0)
- return CAIRO_STATUS_SUCCESS;
-
- do {
- if (spans[0].coverage) {
- _cairo_gl_composite_emit_rect (renderer->ctx,
- spans[0].x, y,
- spans[1].x, y + height,
- spans[0].coverage);
- }
-
- spans++;
- } while (--num_spans > 1);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_render_unbounded_spans (void *abstract_renderer,
- int y, int height,
- const cairo_half_open_span_t *spans,
- unsigned num_spans)
-{
- cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
- if (y > renderer->ymin) {
- _cairo_gl_composite_emit_rect (renderer->ctx,
- renderer->xmin, renderer->ymin,
- renderer->xmax, y,
- 0);
- }
-
- if (num_spans == 0) {
- _cairo_gl_composite_emit_rect (renderer->ctx,
- renderer->xmin, y,
- renderer->xmax, y + height,
- 0);
- } else {
- if (spans[0].x != renderer->xmin) {
- _cairo_gl_composite_emit_rect (renderer->ctx,
- renderer->xmin, y,
- spans[0].x, y + height,
- 0);
- }
-
- do {
- _cairo_gl_composite_emit_rect (renderer->ctx,
- spans[0].x, y,
- spans[1].x, y + height,
- spans[0].coverage);
- spans++;
- } while (--num_spans > 1);
-
- if (spans[0].x != renderer->xmax) {
- _cairo_gl_composite_emit_rect (renderer->ctx,
- spans[0].x, y,
- renderer->xmax, y + height,
- 0);
- }
- }
-
- renderer->ymin = y + height;
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_gl_finish_unbounded_spans (void *abstract_renderer)
-{
- cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
- if (renderer->ymax > renderer->ymin) {
- _cairo_gl_composite_emit_rect (renderer->ctx,
- renderer->xmin, renderer->ymin,
- renderer->xmax, renderer->ymax,
- 0);
- }
-
- return _cairo_gl_context_release (renderer->ctx, CAIRO_STATUS_SUCCESS);
-}
-
-static cairo_status_t
-_cairo_gl_finish_bounded_spans (void *abstract_renderer)
-{
- cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
- return _cairo_gl_context_release (renderer->ctx, CAIRO_STATUS_SUCCESS);
-}
-
-static void
-_cairo_gl_surface_span_renderer_destroy (void *abstract_renderer)
-{
- cairo_gl_surface_span_renderer_t *renderer = abstract_renderer;
-
- if (!renderer)
- return;
-
- _cairo_gl_composite_fini (&renderer->setup);
-
- free (renderer);
-}
-
-cairo_bool_t
-_cairo_gl_surface_check_span_renderer (cairo_operator_t op,
- const cairo_pattern_t *pattern,
- void *abstract_dst,
- cairo_antialias_t antialias)
-{
- if (! _cairo_gl_operator_is_supported (op))
- return FALSE;
-
- return TRUE;
-
- (void) pattern;
- (void) abstract_dst;
- (void) antialias;
-}
-
-cairo_span_renderer_t *
-_cairo_gl_surface_create_span_renderer (cairo_operator_t op,
- const cairo_pattern_t *src,
- void *abstract_dst,
- cairo_antialias_t antialias,
- const cairo_composite_rectangles_t *rects)
-{
- cairo_gl_surface_t *dst = abstract_dst;
- cairo_gl_surface_span_renderer_t *renderer;
- cairo_status_t status;
- const cairo_rectangle_int_t *extents;
-
- status = _cairo_gl_surface_deferred_clear (dst);
- if (unlikely (status))
- return _cairo_span_renderer_create_in_error (status);
-
- renderer = calloc (1, sizeof (*renderer));
- if (unlikely (renderer == NULL))
- return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
-
- renderer->base.destroy = _cairo_gl_surface_span_renderer_destroy;
- if (rects->is_bounded) {
- renderer->base.render_rows = _cairo_gl_render_bounded_spans;
- renderer->base.finish = _cairo_gl_finish_bounded_spans;
- extents = &rects->bounded;
- } else {
- renderer->base.render_rows = _cairo_gl_render_unbounded_spans;
- renderer->base.finish = _cairo_gl_finish_unbounded_spans;
- extents = &rects->unbounded;
- }
- renderer->xmin = extents->x;
- renderer->xmax = extents->x + extents->width;
- renderer->ymin = extents->y;
- renderer->ymax = extents->y + extents->height;
-
- status = _cairo_gl_composite_init (&renderer->setup,
- op, dst,
- FALSE, extents);
- if (unlikely (status))
- goto FAIL;
-
- status = _cairo_gl_composite_set_source (&renderer->setup, src,
- extents->x, extents->y,
- extents->x, extents->y,
- extents->width, extents->height);
- if (unlikely (status))
- goto FAIL;
-
- _cairo_gl_composite_set_spans (&renderer->setup);
- _cairo_gl_composite_set_clip_region (&renderer->setup,
- _cairo_clip_get_region (rects->clip));
-
- status = _cairo_gl_composite_begin (&renderer->setup, &renderer->ctx);
- if (unlikely (status))
- goto FAIL;
-
- return &renderer->base;
-
-FAIL:
- _cairo_gl_composite_fini (&renderer->setup);
- free (renderer);
- return _cairo_span_renderer_create_in_error (status);
-}
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
deleted file mode 100644
index e48244dd4..000000000
--- a/src/cairo-gl-surface.c
+++ /dev/null
@@ -1,1552 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 Eric Anholt
- * Copyright © 2009 Chris Wilson
- * Copyright © 2005,2010 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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):
- * Benjamin Otte <otte@gnome.org>
- * Carl Worth <cworth@cworth.org>
- * Chris Wilson <chris@chris-wilson.co.uk>
- * Eric Anholt <eric@anholt.net>
- */
-
-#include "cairoint.h"
-
-#include "cairo-gl-private.h"
-
-#include "cairo-composite-rectangles-private.h"
-#include "cairo-compositor-private.h"
-#include "cairo-default-context-private.h"
-#include "cairo-error-private.h"
-#include "cairo-image-surface-inline.h"
-#include "cairo-surface-backend-private.h"
-
-static const cairo_surface_backend_t _cairo_gl_surface_backend;
-
-static cairo_status_t
-_cairo_gl_surface_flush (void *abstract_surface, unsigned flags);
-
-static cairo_bool_t _cairo_surface_is_gl (cairo_surface_t *surface)
-{
- return surface->backend == &_cairo_gl_surface_backend;
-}
-
-static cairo_bool_t
-_cairo_gl_get_image_format_and_type_gles2 (pixman_format_code_t pixman_format,
- GLenum *internal_format, GLenum *format,
- GLenum *type, cairo_bool_t *has_alpha,
- cairo_bool_t *needs_swap)
-{
- cairo_bool_t is_little_endian = _cairo_is_little_endian ();
-
- *has_alpha = TRUE;
-
- switch ((int) pixman_format) {
- case PIXMAN_a8r8g8b8:
- *internal_format = GL_BGRA;
- *format = GL_BGRA;
- *type = GL_UNSIGNED_BYTE;
- *needs_swap = !is_little_endian;
- return TRUE;
-
- case PIXMAN_x8r8g8b8:
- *internal_format = GL_BGRA;
- *format = GL_BGRA;
- *type = GL_UNSIGNED_BYTE;
- *has_alpha = FALSE;
- *needs_swap = !is_little_endian;
- return TRUE;
-
- case PIXMAN_a8b8g8r8:
- *internal_format = GL_RGBA;
- *format = GL_RGBA;
- *type = GL_UNSIGNED_BYTE;
- *needs_swap = !is_little_endian;
- return TRUE;
-
- case PIXMAN_x8b8g8r8:
- *internal_format = GL_RGBA;
- *format = GL_RGBA;
- *type = GL_UNSIGNED_BYTE;
- *has_alpha = FALSE;
- *needs_swap = !is_little_endian;
- return TRUE;
-
- case PIXMAN_b8g8r8a8:
- *internal_format = GL_BGRA;
- *format = GL_BGRA;
- *type = GL_UNSIGNED_BYTE;
- *needs_swap = is_little_endian;
- return TRUE;
-
- case PIXMAN_b8g8r8x8:
- *internal_format = GL_BGRA;
- *format = GL_BGRA;
- *type = GL_UNSIGNED_BYTE;
- *has_alpha = FALSE;
- *needs_swap = is_little_endian;
- return TRUE;
-
- case PIXMAN_r8g8b8:
- *internal_format = GL_RGB;
- *format = GL_RGB;
- *type = GL_UNSIGNED_BYTE;
- *needs_swap = is_little_endian;
- return TRUE;
-
- case PIXMAN_b8g8r8:
- *internal_format = GL_RGB;
- *format = GL_RGB;
- *type = GL_UNSIGNED_BYTE;
- *needs_swap = !is_little_endian;
- return TRUE;
-
- case PIXMAN_r5g6b5:
- *internal_format = GL_RGB;
- *format = GL_RGB;
- *type = GL_UNSIGNED_SHORT_5_6_5;
- *needs_swap = FALSE;
- return TRUE;
-
- case PIXMAN_b5g6r5:
- *internal_format = GL_RGB;
- *format = GL_RGB;
- *type = GL_UNSIGNED_SHORT_5_6_5;
- *needs_swap = TRUE;
- return TRUE;
-
- case PIXMAN_a1b5g5r5:
- *internal_format = GL_RGBA;
- *format = GL_RGBA;
- *type = GL_UNSIGNED_SHORT_5_5_5_1;
- *needs_swap = TRUE;
- return TRUE;
-
- case PIXMAN_x1b5g5r5:
- *internal_format = GL_RGBA;
- *format = GL_RGBA;
- *type = GL_UNSIGNED_SHORT_5_5_5_1;
- *has_alpha = FALSE;
- *needs_swap = TRUE;
- return TRUE;
-
- case PIXMAN_a8:
- *internal_format = GL_ALPHA;
- *format = GL_ALPHA;
- *type = GL_UNSIGNED_BYTE;
- *needs_swap = FALSE;
- return TRUE;
-
- default:
- return FALSE;
- }
-}
-
-static cairo_bool_t
-_cairo_gl_get_image_format_and_type_gl (pixman_format_code_t pixman_format,
- GLenum *internal_format, GLenum *format,
- GLenum *type, cairo_bool_t *has_alpha,
- cairo_bool_t *needs_swap)
-{
- *has_alpha = TRUE;
- *needs_swap = FALSE;
-
- switch (pixman_format) {
- case PIXMAN_a8r8g8b8:
- *internal_format = GL_RGBA;
- *format = GL_BGRA;
- *type = GL_UNSIGNED_INT_8_8_8_8_REV;
- return TRUE;
- case PIXMAN_x8r8g8b8:
- *internal_format = GL_RGB;
- *format = GL_BGRA;
- *type = GL_UNSIGNED_INT_8_8_8_8_REV;
- *has_alpha = FALSE;
- return TRUE;
- case PIXMAN_a8b8g8r8:
- *internal_format = GL_RGBA;
- *format = GL_RGBA;
- *type = GL_UNSIGNED_INT_8_8_8_8_REV;
- return TRUE;
- case PIXMAN_x8b8g8r8:
- *internal_format = GL_RGB;
- *format = GL_RGBA;
- *type = GL_UNSIGNED_INT_8_8_8_8_REV;
- *has_alpha = FALSE;
- return TRUE;
- case PIXMAN_b8g8r8a8:
- *internal_format = GL_RGBA;
- *format = GL_BGRA;
- *type = GL_UNSIGNED_INT_8_8_8_8;
- return TRUE;
- case PIXMAN_b8g8r8x8:
- *internal_format = GL_RGB;
- *format = GL_BGRA;
- *type = GL_UNSIGNED_INT_8_8_8_8;
- *has_alpha = FALSE;
- return TRUE;
- case PIXMAN_r8g8b8:
- *internal_format = GL_RGB;
- *format = GL_RGB;
- *type = GL_UNSIGNED_BYTE;
- return TRUE;
- case PIXMAN_b8g8r8:
- *internal_format = GL_RGB;
- *format = GL_BGR;
- *type = GL_UNSIGNED_BYTE;
- return TRUE;
- case PIXMAN_r5g6b5:
- *internal_format = GL_RGB;
- *format = GL_RGB;
- *type = GL_UNSIGNED_SHORT_5_6_5;
- return TRUE;
- case PIXMAN_b5g6r5:
- *internal_format = GL_RGB;
- *format = GL_RGB;
- *type = GL_UNSIGNED_SHORT_5_6_5_REV;
- return TRUE;
- case PIXMAN_a1r5g5b5:
- *internal_format = GL_RGBA;
- *format = GL_BGRA;
- *type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
- return TRUE;
- case PIXMAN_x1r5g5b5:
- *internal_format = GL_RGB;
- *format = GL_BGRA;
- *type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
- *has_alpha = FALSE;
- return TRUE;
- case PIXMAN_a1b5g5r5:
- *internal_format = GL_RGBA;
- *format = GL_RGBA;
- *type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
- return TRUE;
- case PIXMAN_x1b5g5r5:
- *internal_format = GL_RGB;
- *format = GL_RGBA;
- *type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
- *has_alpha = FALSE;
- return TRUE;
- case PIXMAN_a8:
- *internal_format = GL_ALPHA;
- *format = GL_ALPHA;
- *type = GL_UNSIGNED_BYTE;
- return TRUE;
-
-#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,27,2)
- case PIXMAN_a8r8g8b8_sRGB:
-#endif
- case PIXMAN_a2b10g10r10:
- case PIXMAN_x2b10g10r10:
- case PIXMAN_a4r4g4b4:
- case PIXMAN_x4r4g4b4:
- case PIXMAN_a4b4g4r4:
- case PIXMAN_x4b4g4r4:
- case PIXMAN_r3g3b2:
- case PIXMAN_b2g3r3:
- case PIXMAN_a2r2g2b2:
- case PIXMAN_a2b2g2r2:
- case PIXMAN_c8:
- case PIXMAN_x4a4:
- /* case PIXMAN_x4c4: */
- case PIXMAN_x4g4:
- case PIXMAN_a4:
- case PIXMAN_r1g2b1:
- case PIXMAN_b1g2r1:
- case PIXMAN_a1r1g1b1:
- case PIXMAN_a1b1g1r1:
- case PIXMAN_c4:
- case PIXMAN_g4:
- case PIXMAN_a1:
- case PIXMAN_g1:
- case PIXMAN_yuy2:
- case PIXMAN_yv12:
- case PIXMAN_x2r10g10b10:
- case PIXMAN_a2r10g10b10:
- case PIXMAN_r8g8b8x8:
- case PIXMAN_r8g8b8a8:
- case PIXMAN_x14r6g6b6:
- case PIXMAN_rgb_float:
- case PIXMAN_rgba_float:
- default:
- return FALSE;
- }
-}
-
-/*
- * Extracts pixel data from an image surface.
- */
-static cairo_status_t
-_cairo_gl_surface_extract_image_data (cairo_image_surface_t *image,
- int x, int y,
- int width, int height,
- void **output)
-{
- int cpp = PIXMAN_FORMAT_BPP (image->pixman_format) / 8;
- char *data = _cairo_malloc_ab (width * height, cpp);
- char *dst = data;
- unsigned char *src = image->data + y * image->stride + x * cpp;
- int i;
-
- if (unlikely (data == NULL))
- return CAIRO_STATUS_NO_MEMORY;
-
- for (i = 0; i < height; i++) {
- memcpy (dst, src, width * cpp);
- src += image->stride;
- dst += width * cpp;
- }
-
- *output = data;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_bool_t
-_cairo_gl_get_image_format_and_type (cairo_gl_flavor_t flavor,
- pixman_format_code_t pixman_format,
- GLenum *internal_format, GLenum *format,
- GLenum *type, cairo_bool_t *has_alpha,
- cairo_bool_t *needs_swap)
-{
- if (flavor == CAIRO_GL_FLAVOR_DESKTOP)
- return _cairo_gl_get_image_format_and_type_gl (pixman_format,
- internal_format, format,
- type, has_alpha,
- needs_swap);
- else
- return _cairo_gl_get_image_format_and_type_gles2 (pixman_format,
- internal_format, format,
- type, has_alpha,
- needs_swap);
-
-}
-
-cairo_bool_t
-_cairo_gl_operator_is_supported (cairo_operator_t op)
-{
- return op < CAIRO_OPERATOR_SATURATE;
-}
-
-static void
-_cairo_gl_surface_embedded_operand_init (cairo_gl_surface_t *surface)
-{
- cairo_gl_operand_t *operand = &surface->operand;
- cairo_surface_attributes_t *attributes = &operand->texture.attributes;
-
- memset (operand, 0, sizeof (cairo_gl_operand_t));
-
- operand->type = CAIRO_GL_OPERAND_TEXTURE;
- operand->texture.surface = surface;
- operand->texture.tex = surface->tex;
-
- if (_cairo_gl_device_requires_power_of_two_textures (surface->base.device)) {
- cairo_matrix_init_identity (&attributes->matrix);
- } else {
- cairo_matrix_init_scale (&attributes->matrix,
- 1.0 / surface->width,
- 1.0 / surface->height);
- }
-
- attributes->extend = CAIRO_EXTEND_NONE;
- attributes->filter = CAIRO_FILTER_NEAREST;
-}
-
-void
-_cairo_gl_surface_init (cairo_device_t *device,
- cairo_gl_surface_t *surface,
- cairo_content_t content,
- int width, int height)
-{
- assert (width > 0 && height > 0);
-
- _cairo_surface_init (&surface->base,
- &_cairo_gl_surface_backend,
- device,
- content,
- FALSE); /* is_vector */
-
- surface->width = width;
- surface->height = height;
- surface->needs_update = FALSE;
- surface->content_in_texture = FALSE;
-
- _cairo_gl_surface_embedded_operand_init (surface);
-}
-
-static cairo_bool_t
-_cairo_gl_surface_size_valid_for_context (cairo_gl_context_t *ctx,
- int width, int height)
-{
- return width > 0 && height > 0 &&
- width <= ctx->max_framebuffer_size &&
- height <= ctx->max_framebuffer_size;
-}
-
-static cairo_bool_t
-_cairo_gl_surface_size_valid (cairo_gl_surface_t *surface,
- int width, int height)
-{
- cairo_gl_context_t *ctx = (cairo_gl_context_t *)surface->base.device;
- return _cairo_gl_surface_size_valid_for_context (ctx, width, height);
-}
-
-static cairo_surface_t *
-_cairo_gl_surface_create_scratch_for_texture (cairo_gl_context_t *ctx,
- cairo_content_t content,
- GLuint tex,
- int width,
- int height)
-{
- cairo_gl_surface_t *surface;
-
- surface = calloc (1, sizeof (cairo_gl_surface_t));
- if (unlikely (surface == NULL))
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
-
- surface->tex = tex;
- _cairo_gl_surface_init (&ctx->base, surface, content, width, height);
-
- surface->supports_msaa = ctx->supports_msaa;
- surface->num_samples = ctx->num_samples;
- surface->supports_stencil = TRUE;
-
- /* Create the texture used to store the surface's data. */
- _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
- glBindTexture (ctx->tex_target, surface->tex);
- glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-
- return &surface->base;
-}
-
-static cairo_surface_t *
-_create_scratch_internal (cairo_gl_context_t *ctx,
- cairo_content_t content,
- int width,
- int height,
- cairo_bool_t for_caching)
-{
- cairo_gl_surface_t *surface;
- GLenum format;
- GLuint tex;
-
- glGenTextures (1, &tex);
- surface = (cairo_gl_surface_t *)
- _cairo_gl_surface_create_scratch_for_texture (ctx, content,
- tex, width, height);
- if (unlikely (surface->base.status))
- return &surface->base;
-
- surface->owns_tex = TRUE;
-
- /* adjust the texture size after setting our real extents */
- if (width < 1)
- width = 1;
- if (height < 1)
- height = 1;
-
- switch (content) {
- default:
- ASSERT_NOT_REACHED;
- case CAIRO_CONTENT_COLOR_ALPHA:
- format = GL_RGBA;
- break;
- case CAIRO_CONTENT_ALPHA:
- /* When using GL_ALPHA, compositing doesn't work properly, but for
- * caching surfaces, we are just uploading pixel data, so it isn't
- * an issue. */
- if (for_caching)
- format = GL_ALPHA;
- else
- format = GL_RGBA;
- break;
- case CAIRO_CONTENT_COLOR:
- /* GL_RGB is almost what we want here -- sampling 1 alpha when
- * texturing, using 1 as destination alpha factor in blending,
- * etc. However, when filtering with GL_CLAMP_TO_BORDER, the
- * alpha channel of the border color will also be clamped to
- * 1, when we actually want the border color we explicitly
- * specified. So, we have to store RGBA, and fill the alpha
- * channel with 1 when blending.
- */
- format = GL_RGBA;
- break;
- }
-
- glTexImage2D (ctx->tex_target, 0, format, width, height, 0,
- format, GL_UNSIGNED_BYTE, NULL);
-
- return &surface->base;
-}
-
-cairo_surface_t *
-_cairo_gl_surface_create_scratch (cairo_gl_context_t *ctx,
- cairo_content_t content,
- int width,
- int height)
-{
- return _create_scratch_internal (ctx, content, width, height, FALSE);
-}
-
-cairo_surface_t *
-_cairo_gl_surface_create_scratch_for_caching (cairo_gl_context_t *ctx,
- cairo_content_t content,
- int width,
- int height)
-{
- return _create_scratch_internal (ctx, content, width, height, TRUE);
-}
-
-static cairo_status_t
-_cairo_gl_surface_clear (cairo_gl_surface_t *surface,
- const cairo_color_t *color)
-{
- cairo_gl_context_t *ctx;
- cairo_status_t status;
- double r, g, b, a;
-
- status = _cairo_gl_context_acquire (surface->base.device, &ctx);
- if (unlikely (status))
- return status;
-
- _cairo_gl_context_set_destination (ctx, surface, surface->msaa_active);
- if (surface->base.content & CAIRO_CONTENT_COLOR) {
- r = color->red * color->alpha;
- g = color->green * color->alpha;
- b = color->blue * color->alpha;
- } else {
- r = g = b = 0;
- }
- if (surface->base.content & CAIRO_CONTENT_ALPHA) {
- a = color->alpha;
- } else {
- a = 1.0;
- }
-
- glDisable (GL_SCISSOR_TEST);
- glClearColor (r, g, b, a);
- glClear (GL_COLOR_BUFFER_BIT);
-
- if (a == 0)
- surface->base.is_clear = TRUE;
-
- return _cairo_gl_context_release (ctx, status);
-}
-
-static cairo_surface_t *
-_cairo_gl_surface_create_and_clear_scratch (cairo_gl_context_t *ctx,
- cairo_content_t content,
- int width,
- int height)
-{
- cairo_gl_surface_t *surface;
- cairo_int_status_t status;
-
- surface = (cairo_gl_surface_t *)
- _cairo_gl_surface_create_scratch (ctx, content, width, height);
- if (unlikely (surface->base.status))
- return &surface->base;
-
- /* Cairo surfaces start out initialized to transparent (black) */
- status = _cairo_gl_surface_clear (surface, CAIRO_COLOR_TRANSPARENT);
- if (unlikely (status)) {
- cairo_surface_destroy (&surface->base);
- return _cairo_surface_create_in_error (status);
- }
-
- return &surface->base;
-}
-
-cairo_surface_t *
-cairo_gl_surface_create (cairo_device_t *abstract_device,
- cairo_content_t content,
- int width,
- int height)
-{
- cairo_gl_context_t *ctx;
- cairo_gl_surface_t *surface;
- cairo_status_t status;
-
- if (! CAIRO_CONTENT_VALID (content))
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
-
- if (abstract_device == NULL)
- return _cairo_image_surface_create_with_content (content, width, height);
-
- if (abstract_device->status)
- return _cairo_surface_create_in_error (abstract_device->status);
-
- if (abstract_device->backend->type != CAIRO_DEVICE_TYPE_GL)
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
-
- status = _cairo_gl_context_acquire (abstract_device, &ctx);
- if (unlikely (status))
- return _cairo_surface_create_in_error (status);
-
- if (! _cairo_gl_surface_size_valid_for_context (ctx, width, height)) {
- status = _cairo_gl_context_release (ctx, status);
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
- }
-
- surface = (cairo_gl_surface_t *)
- _cairo_gl_surface_create_and_clear_scratch (ctx, content, width, height);
- if (unlikely (surface->base.status)) {
- status = _cairo_gl_context_release (ctx, surface->base.status);
- cairo_surface_destroy (&surface->base);
- return _cairo_surface_create_in_error (status);
- }
-
- status = _cairo_gl_context_release (ctx, status);
- if (unlikely (status)) {
- cairo_surface_destroy (&surface->base);
- return _cairo_surface_create_in_error (status);
- }
-
- return &surface->base;
-}
-slim_hidden_def (cairo_gl_surface_create);
-
-/**
- * cairo_gl_surface_create_for_texture:
- * @content: type of content in the surface
- * @tex: name of texture to use for storage of surface pixels
- * @width: width of the surface, in pixels
- * @height: height of the surface, in pixels
- *
- * Creates a GL surface for the specified texture with the specified
- * content and dimensions. The texture must be kept around until the
- * #cairo_surface_t is destroyed or cairo_surface_finish() is called
- * on the surface. The initial contents of @tex will be used as the
- * initial image contents; you must explicitly clear the buffer,
- * using, for example, cairo_rectangle() and cairo_fill() if you want
- * it cleared. The format of @tex should be compatible with @content,
- * in the sense that it must have the color components required by
- * @content.
- *
- * Return value: a pointer to the newly created surface. The caller
- * owns the surface and should call cairo_surface_destroy() when done
- * with it.
- *
- * This function always returns a valid pointer, but it will return a
- * pointer to a "nil" surface if an error such as out of memory
- * occurs. You can use cairo_surface_status() to check for this.
- *
- * Since: TBD
- **/
-cairo_surface_t *
-cairo_gl_surface_create_for_texture (cairo_device_t *abstract_device,
- cairo_content_t content,
- unsigned int tex,
- int width,
- int height)
-{
- cairo_gl_context_t *ctx;
- cairo_gl_surface_t *surface;
- cairo_status_t status;
-
- if (! CAIRO_CONTENT_VALID (content))
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
-
- if (abstract_device == NULL)
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER));
-
- if (abstract_device->status)
- return _cairo_surface_create_in_error (abstract_device->status);
-
- if (abstract_device->backend->type != CAIRO_DEVICE_TYPE_GL)
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH));
-
- status = _cairo_gl_context_acquire (abstract_device, &ctx);
- if (unlikely (status))
- return _cairo_surface_create_in_error (status);
-
- if (! _cairo_gl_surface_size_valid_for_context (ctx, width, height)) {
- status = _cairo_gl_context_release (ctx, status);
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
- }
-
- surface = (cairo_gl_surface_t *)
- _cairo_gl_surface_create_scratch_for_texture (ctx, content,
- tex, width, height);
- status = _cairo_gl_context_release (ctx, status);
-
- return &surface->base;
-}
-slim_hidden_def (cairo_gl_surface_create_for_texture);
-
-
-void
-cairo_gl_surface_set_size (cairo_surface_t *abstract_surface,
- int width,
- int height)
-{
- cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
-
- if (unlikely (abstract_surface->status))
- return;
- if (unlikely (abstract_surface->finished)) {
- _cairo_surface_set_error (abstract_surface,
- _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
- return;
- }
-
- if (! _cairo_surface_is_gl (abstract_surface) ||
- _cairo_gl_surface_is_texture (surface)) {
- _cairo_surface_set_error (abstract_surface,
- _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
- return;
- }
-
- if (surface->width != width || surface->height != height) {
- surface->needs_update = TRUE;
- surface->width = width;
- surface->height = height;
- }
-}
-
-int
-cairo_gl_surface_get_width (cairo_surface_t *abstract_surface)
-{
- cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
-
- if (! _cairo_surface_is_gl (abstract_surface))
- return 0;
-
- return surface->width;
-}
-
-int
-cairo_gl_surface_get_height (cairo_surface_t *abstract_surface)
-{
- cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
-
- if (! _cairo_surface_is_gl (abstract_surface))
- return 0;
-
- return surface->height;
-}
-
-void
-cairo_gl_surface_swapbuffers (cairo_surface_t *abstract_surface)
-{
- cairo_gl_surface_t *surface = (cairo_gl_surface_t *) abstract_surface;
-
- if (unlikely (abstract_surface->status))
- return;
- if (unlikely (abstract_surface->finished)) {
- _cairo_surface_set_error (abstract_surface,
- _cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
- return;
- }
-
- if (! _cairo_surface_is_gl (abstract_surface)) {
- _cairo_surface_set_error (abstract_surface,
- CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
- return;
- }
-
- if (! _cairo_gl_surface_is_texture (surface)) {
- cairo_gl_context_t *ctx;
- cairo_status_t status;
-
- status = _cairo_gl_context_acquire (surface->base.device, &ctx);
- if (unlikely (status))
- return;
-
- /* For swapping on EGL, at least, we need a valid context/target. */
- _cairo_gl_context_set_destination (ctx, surface, FALSE);
- /* And in any case we should flush any pending operations. */
- _cairo_gl_composite_flush (ctx);
-
- ctx->swap_buffers (ctx, surface);
-
- status = _cairo_gl_context_release (ctx, status);
- if (status)
- status = _cairo_surface_set_error (abstract_surface, status);
- }
-}
-
-static cairo_surface_t *
-_cairo_gl_surface_create_similar (void *abstract_surface,
- cairo_content_t content,
- int width,
- int height)
-{
- cairo_surface_t *surface = abstract_surface;
- cairo_gl_context_t *ctx;
- cairo_status_t status;
-
- if (! _cairo_gl_surface_size_valid (abstract_surface, width, height))
- return _cairo_image_surface_create_with_content (content, width, height);
-
- status = _cairo_gl_context_acquire (surface->device, &ctx);
- if (unlikely (status))
- return _cairo_surface_create_in_error (status);
-
- surface = _cairo_gl_surface_create_and_clear_scratch (ctx, content, width, height);
-
- status = _cairo_gl_context_release (ctx, status);
- if (unlikely (status)) {
- cairo_surface_destroy (surface);
- return _cairo_surface_create_in_error (status);
- }
-
- return surface;
-}
-
-static cairo_int_status_t
-_cairo_gl_surface_fill_alpha_channel (cairo_gl_surface_t *dst,
- cairo_gl_context_t *ctx,
- int x, int y,
- int width, int height)
-{
- cairo_gl_composite_t setup;
- cairo_status_t status;
-
- _cairo_gl_composite_flush (ctx);
- glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
-
- status = _cairo_gl_composite_init (&setup, CAIRO_OPERATOR_SOURCE,
- dst, FALSE);
- if (unlikely (status))
- goto CLEANUP;
-
- _cairo_gl_composite_set_solid_source (&setup, CAIRO_COLOR_BLACK);
-
- status = _cairo_gl_composite_begin (&setup, &ctx);
- if (unlikely (status))
- goto CLEANUP;
-
- _cairo_gl_context_emit_rect (ctx, x, y, x + width, y + height);
-
- status = _cairo_gl_context_release (ctx, status);
-
- CLEANUP:
- _cairo_gl_composite_fini (&setup);
-
- _cairo_gl_composite_flush (ctx);
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-
- return status;
-}
-
-cairo_status_t
-_cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
- cairo_image_surface_t *src,
- int src_x, int src_y,
- int width, int height,
- int dst_x, int dst_y,
- cairo_bool_t force_flush)
-{
- GLenum internal_format, format, type;
- cairo_bool_t has_alpha, needs_swap;
- cairo_image_surface_t *clone = NULL;
- cairo_gl_context_t *ctx;
- int cpp;
- cairo_image_surface_t *rgba_clone = NULL;
- cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
-
- status = _cairo_gl_context_acquire (dst->base.device, &ctx);
- if (unlikely (status))
- return status;
-
- if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES3 ||
- _cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES2) {
- pixman_format_code_t pixman_format;
- cairo_surface_pattern_t pattern;
- cairo_bool_t require_conversion = FALSE;
- pixman_format = _cairo_is_little_endian () ? PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8;
-
- if (src->base.content != CAIRO_CONTENT_ALPHA) {
- if (src->pixman_format != pixman_format)
- require_conversion = TRUE;
- }
- else if (dst->base.content != CAIRO_CONTENT_ALPHA) {
- require_conversion = TRUE;
- }
- else if (src->pixman_format != PIXMAN_a8) {
- pixman_format = PIXMAN_a8;
- require_conversion = TRUE;
- }
-
- if (require_conversion) {
- rgba_clone = (cairo_image_surface_t *)
- _cairo_image_surface_create_with_pixman_format (NULL,
- pixman_format,
- src->width,
- src->height,
- 0);
- if (unlikely (rgba_clone->base.status))
- goto FAIL;
-
- _cairo_pattern_init_for_surface (&pattern, &src->base);
- status = _cairo_surface_paint (&rgba_clone->base,
- CAIRO_OPERATOR_SOURCE,
- &pattern.base, NULL);
- _cairo_pattern_fini (&pattern.base);
- if (unlikely (status))
- goto FAIL;
-
- src = rgba_clone;
- }
- }
-
- if (! _cairo_gl_get_image_format_and_type (ctx->gl_flavor,
- src->pixman_format,
- &internal_format,
- &format,
- &type,
- &has_alpha,
- &needs_swap))
- {
- cairo_bool_t is_supported;
-
- clone = _cairo_image_surface_coerce (src);
- if (unlikely (status = clone->base.status))
- goto FAIL;
-
- is_supported =
- _cairo_gl_get_image_format_and_type (ctx->gl_flavor,
- clone->pixman_format,
- &internal_format,
- &format,
- &type,
- &has_alpha,
- &needs_swap);
- assert (is_supported);
- assert (!needs_swap);
- src = clone;
- }
-
- cpp = PIXMAN_FORMAT_BPP (src->pixman_format) / 8;
-
- if (force_flush) {
- status = _cairo_gl_surface_flush (&dst->base, 0);
- if (unlikely (status))
- goto FAIL;
- }
-
- if (_cairo_gl_surface_is_texture (dst)) {
- void *data_start = src->data + src_y * src->stride + src_x * cpp;
- void *data_start_gles2 = NULL;
-
- /*
- * Due to GL_UNPACK_ROW_LENGTH missing in GLES2 we have to extract the
- * image data ourselves in some cases. In particular, we must extract
- * the pixels if:
- * a. we don't want full-length lines or
- * b. the row stride cannot be handled by GL itself using a 4 byte
- * alignment constraint
- */
- if (src->stride < 0 ||
- (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES2 &&
- (src->width * cpp < src->stride - 3 ||
- width != src->width)))
- {
- glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
- status = _cairo_gl_surface_extract_image_data (src, src_x, src_y,
- width, height,
- &data_start_gles2);
- if (unlikely (status))
- goto FAIL;
-
- data_start = data_start_gles2;
- }
- else
- {
- glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
- ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
- glPixelStorei (GL_UNPACK_ROW_LENGTH, src->stride / cpp);
- }
-
- /* we must resolve the renderbuffer to texture before we
- upload image */
- status = _cairo_gl_surface_resolve_multisampling (dst);
- if (unlikely (status)) {
- free (data_start_gles2);
- goto FAIL;
- }
-
- _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
- glBindTexture (ctx->tex_target, dst->tex);
- glTexParameteri (ctx->tex_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri (ctx->tex_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexSubImage2D (ctx->tex_target, 0,
- dst_x, dst_y, width, height,
- format, type, data_start);
-
- free (data_start_gles2);
-
- /* If we just treated some rgb-only data as rgba, then we have to
- * go back and fix up the alpha channel where we filled in this
- * texture data.
- */
- if (!has_alpha) {
- _cairo_gl_surface_fill_alpha_channel (dst, ctx,
- dst_x, dst_y,
- width, height);
- }
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
- dst->content_in_texture = TRUE;
- } else {
- cairo_surface_t *tmp;
-
- tmp = _cairo_gl_surface_create_scratch (ctx,
- dst->base.content,
- width, height);
- if (unlikely (tmp->status))
- goto FAIL;
-
- status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *) tmp,
- src,
- src_x, src_y,
- width, height,
- 0, 0, force_flush);
- if (status == CAIRO_INT_STATUS_SUCCESS) {
- cairo_surface_pattern_t tmp_pattern;
- cairo_rectangle_int_t r;
- cairo_clip_t *clip;
-
- _cairo_pattern_init_for_surface (&tmp_pattern, tmp);
- cairo_matrix_init_translate (&tmp_pattern.base.matrix,
- -dst_x, -dst_y);
- tmp_pattern.base.filter = CAIRO_FILTER_NEAREST;
- tmp_pattern.base.extend = CAIRO_EXTEND_NONE;
-
- r.x = dst_x;
- r.y = dst_y;
- r.width = width;
- r.height = height;
- clip = _cairo_clip_intersect_rectangle (NULL, &r);
- status = _cairo_surface_paint (&dst->base,
- CAIRO_OPERATOR_SOURCE,
- &tmp_pattern.base,
- clip);
- _cairo_clip_destroy (clip);
- _cairo_pattern_fini (&tmp_pattern.base);
- }
-
- cairo_surface_destroy (tmp);
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
- dst->content_in_texture = TRUE;
- }
-
-FAIL:
- status = _cairo_gl_context_release (ctx, status);
-
- if (clone)
- cairo_surface_destroy (&clone->base);
-
- if (rgba_clone)
- cairo_surface_destroy (&rgba_clone->base);
-
- return status;
-}
-
-static int _cairo_gl_surface_flavor (cairo_gl_surface_t *surface)
-{
- cairo_gl_context_t *ctx = (cairo_gl_context_t *)surface->base.device;
- return ctx->gl_flavor;
-}
-
-static cairo_status_t
-_cairo_gl_surface_finish (void *abstract_surface)
-{
- cairo_gl_surface_t *surface = abstract_surface;
- cairo_status_t status;
- cairo_gl_context_t *ctx;
-
- status = _cairo_gl_context_acquire (surface->base.device, &ctx);
- if (unlikely (status))
- return status;
-
- if (ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE &&
- ctx->operands[CAIRO_GL_TEX_SOURCE].texture.surface == surface)
- _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_SOURCE);
- if (ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE &&
- ctx->operands[CAIRO_GL_TEX_MASK].texture.surface == surface)
- _cairo_gl_context_destroy_operand (ctx, CAIRO_GL_TEX_MASK);
- if (ctx->current_target == surface)
- ctx->current_target = NULL;
-
- if (surface->fb)
- ctx->dispatch.DeleteFramebuffers (1, &surface->fb);
- if (surface->depth_stencil)
- ctx->dispatch.DeleteRenderbuffers (1, &surface->depth_stencil);
- if (surface->owns_tex)
- glDeleteTextures (1, &surface->tex);
-
- if (surface->msaa_depth_stencil)
- ctx->dispatch.DeleteRenderbuffers (1, &surface->msaa_depth_stencil);
-
-#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV3_SURFACE
- if (surface->msaa_fb)
- ctx->dispatch.DeleteFramebuffers (1, &surface->msaa_fb);
- if (surface->msaa_rb)
- ctx->dispatch.DeleteRenderbuffers (1, &surface->msaa_rb);
-#endif
-
- _cairo_clip_destroy (surface->clip_on_stencil_buffer);
-
- return _cairo_gl_context_release (ctx, status);
-}
-
-static cairo_image_surface_t *
-_cairo_gl_surface_map_to_image (void *abstract_surface,
- const cairo_rectangle_int_t *extents)
-{
- cairo_gl_surface_t *surface = abstract_surface;
- cairo_image_surface_t *image;
- cairo_gl_context_t *ctx;
- GLenum format, type;
- pixman_format_code_t pixman_format;
- unsigned int cpp;
- cairo_bool_t flipped, mesa_invert;
- cairo_status_t status;
- int y;
-
- status = _cairo_gl_context_acquire (surface->base.device, &ctx);
- if (unlikely (status)) {
- return _cairo_image_surface_create_in_error (status);
- }
-
- /* Want to use a switch statement here but the compiler gets whiny. */
- if (surface->base.content == CAIRO_CONTENT_COLOR_ALPHA) {
- format = GL_BGRA;
- pixman_format = PIXMAN_a8r8g8b8;
- type = GL_UNSIGNED_INT_8_8_8_8_REV;
- cpp = 4;
- } else if (surface->base.content == CAIRO_CONTENT_COLOR) {
- format = GL_BGRA;
- pixman_format = PIXMAN_x8r8g8b8;
- type = GL_UNSIGNED_INT_8_8_8_8_REV;
- cpp = 4;
- } else if (surface->base.content == CAIRO_CONTENT_ALPHA) {
- format = GL_ALPHA;
- pixman_format = PIXMAN_a8;
- type = GL_UNSIGNED_BYTE;
- cpp = 1;
- } else {
- ASSERT_NOT_REACHED;
- return NULL;
- }
-
- if (_cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES3 ||
- _cairo_gl_surface_flavor (surface) == CAIRO_GL_FLAVOR_ES2) {
- /* If only RGBA is supported, we must download data in a compatible
- * format. This means that pixman will convert the data on the CPU when
- * interacting with other image surfaces. For ALPHA, GLES2 does not
- * support GL_PACK_ROW_LENGTH anyway, and this makes sure that the
- * pixman image that is created has row_stride = row_width * bpp. */
- if (surface->base.content == CAIRO_CONTENT_ALPHA || !ctx->can_read_bgra) {
- cairo_bool_t little_endian = _cairo_is_little_endian ();
- format = GL_RGBA;
-
- if (surface->base.content == CAIRO_CONTENT_COLOR) {
- pixman_format = little_endian ?
- PIXMAN_x8b8g8r8 : PIXMAN_r8g8b8x8;
- } else {
- pixman_format = little_endian ?
- PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8;
- }
- }
-
- /* GLES2 only supports GL_UNSIGNED_BYTE. */
- type = GL_UNSIGNED_BYTE;
- cpp = 4;
- }
-
- image = (cairo_image_surface_t*)
- _cairo_image_surface_create_with_pixman_format (NULL,
- pixman_format,
- extents->width,
- extents->height,
- -1);
- if (unlikely (image->base.status)) {
- status = _cairo_gl_context_release (ctx, status);
- return image;
- }
-
- cairo_surface_set_device_offset (&image->base, -extents->x, -extents->y);
-
- /* If the original surface has not been modified or
- * is clear, we can avoid downloading data. */
- if (surface->base.is_clear || surface->base.serial == 0) {
- status = _cairo_gl_context_release (ctx, status);
- return image;
- }
-
- /* This is inefficient, as we'd rather just read the thing without making
- * it the destination. But then, this is the fallback path, so let's not
- * fall back instead.
- */
- _cairo_gl_composite_flush (ctx);
-
- if (ctx->gl_flavor != CAIRO_GL_FLAVOR_ES3) {
- _cairo_gl_context_set_destination (ctx, surface, FALSE);
- } else {
- if (surface->content_in_texture) {
- _cairo_gl_ensure_framebuffer (ctx, surface);
- ctx->dispatch.BindFramebuffer (GL_FRAMEBUFFER, surface->fb);
- } else {
- status = _cairo_gl_surface_resolve_multisampling (surface);
- if (unlikely (status)) {
- status = _cairo_gl_context_release (ctx, status);
- cairo_surface_destroy (&image->base);
- return _cairo_image_surface_create_in_error (status);
- }
- }
- }
-
- flipped = ! _cairo_gl_surface_is_texture (surface);
- mesa_invert = flipped && ctx->has_mesa_pack_invert;
-
- glPixelStorei (GL_PACK_ALIGNMENT, 4);
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_DESKTOP ||
- ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
- glPixelStorei (GL_PACK_ROW_LENGTH, image->stride / cpp);
- if (mesa_invert)
- glPixelStorei (GL_PACK_INVERT_MESA, 1);
-
- y = extents->y;
- if (flipped)
- y = surface->height - extents->y - extents->height;
-
- glReadPixels (extents->x, y,
- extents->width, extents->height,
- format, type, image->data);
- if (mesa_invert)
- glPixelStorei (GL_PACK_INVERT_MESA, 0);
-
- status = _cairo_gl_context_release (ctx, status);
- if (unlikely (status)) {
- cairo_surface_destroy (&image->base);
- return _cairo_image_surface_create_in_error (status);
- }
-
- /* We must invert the image manually if we lack GL_MESA_pack_invert */
- if (flipped && ! mesa_invert) {
- uint8_t stack[1024], *row = stack;
- uint8_t *top = image->data;
- uint8_t *bot = image->data + (image->height-1)*image->stride;
-
- if (image->stride > (int)sizeof(stack)) {
- row = _cairo_malloc (image->stride);
- if (unlikely (row == NULL)) {
- cairo_surface_destroy (&image->base);
- return _cairo_image_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
- }
- }
-
- while (top < bot) {
- memcpy (row, top, image->stride);
- memcpy (top, bot, image->stride);
- memcpy (bot, row, image->stride);
- top += image->stride;
- bot -= image->stride;
- }
-
- if (row != stack)
- free(row);
- }
-
- image->base.is_clear = FALSE;
- return image;
-}
-
-static cairo_surface_t *
-_cairo_gl_surface_source (void *abstract_surface,
- cairo_rectangle_int_t *extents)
-{
- cairo_gl_surface_t *surface = abstract_surface;
-
- if (extents) {
- extents->x = extents->y = 0;
- extents->width = surface->width;
- extents->height = surface->height;
- }
-
- return &surface->base;
-}
-
-static cairo_status_t
-_cairo_gl_surface_acquire_source_image (void *abstract_surface,
- cairo_image_surface_t **image_out,
- void **image_extra)
-{
- cairo_gl_surface_t *surface = abstract_surface;
- cairo_rectangle_int_t extents;
-
- *image_extra = NULL;
-
- extents.x = extents.y = 0;
- extents.width = surface->width;
- extents.height = surface->height;
-
- *image_out = (cairo_image_surface_t *)
- _cairo_gl_surface_map_to_image (surface, &extents);
- return (*image_out)->base.status;
-}
-
-static void
-_cairo_gl_surface_release_source_image (void *abstract_surface,
- cairo_image_surface_t *image,
- void *image_extra)
-{
- cairo_surface_destroy (&image->base);
-}
-
-static cairo_int_status_t
-_cairo_gl_surface_unmap_image (void *abstract_surface,
- cairo_image_surface_t *image)
-{
- cairo_int_status_t status;
-
- status = _cairo_gl_surface_draw_image (abstract_surface, image,
- 0, 0,
- image->width, image->height,
- image->base.device_transform_inverse.x0,
- image->base.device_transform_inverse.y0,
- TRUE);
-
- cairo_surface_finish (&image->base);
- cairo_surface_destroy (&image->base);
-
- return status;
-}
-
-static cairo_bool_t
-_cairo_gl_surface_get_extents (void *abstract_surface,
- cairo_rectangle_int_t *rectangle)
-{
- cairo_gl_surface_t *surface = abstract_surface;
-
- rectangle->x = 0;
- rectangle->y = 0;
- rectangle->width = surface->width;
- rectangle->height = surface->height;
-
- return TRUE;
-}
-
-static cairo_status_t
-_cairo_gl_surface_flush (void *abstract_surface, unsigned flags)
-{
- cairo_gl_surface_t *surface = abstract_surface;
- cairo_status_t status;
- cairo_gl_context_t *ctx;
-
- if (flags)
- return CAIRO_STATUS_SUCCESS;
-
- status = _cairo_gl_context_acquire (surface->base.device, &ctx);
- if (unlikely (status))
- return status;
-
- if ((ctx->operands[CAIRO_GL_TEX_SOURCE].type == CAIRO_GL_OPERAND_TEXTURE &&
- ctx->operands[CAIRO_GL_TEX_SOURCE].texture.surface == surface) ||
- (ctx->operands[CAIRO_GL_TEX_MASK].type == CAIRO_GL_OPERAND_TEXTURE &&
- ctx->operands[CAIRO_GL_TEX_MASK].texture.surface == surface) ||
- (ctx->current_target == surface))
- _cairo_gl_composite_flush (ctx);
-
- status = _cairo_gl_surface_resolve_multisampling (surface);
-
- return _cairo_gl_context_release (ctx, status);
-}
-
-cairo_int_status_t
-_cairo_gl_surface_resolve_multisampling (cairo_gl_surface_t *surface)
-{
- cairo_gl_context_t *ctx;
- cairo_int_status_t status;
-
- if (! surface->msaa_active)
- return CAIRO_INT_STATUS_SUCCESS;
-
- if (surface->base.device == NULL)
- return CAIRO_INT_STATUS_SUCCESS;
-
- /* GLES surfaces do not need explicit resolution. */
- if (((cairo_gl_context_t *) surface->base.device)->gl_flavor == CAIRO_GL_FLAVOR_ES2)
- return CAIRO_INT_STATUS_SUCCESS;
- else if (((cairo_gl_context_t *) surface->base.device)->gl_flavor == CAIRO_GL_FLAVOR_ES3 &&
- surface->content_in_texture)
- return CAIRO_INT_STATUS_SUCCESS;
-
- if (! _cairo_gl_surface_is_texture (surface))
- return CAIRO_INT_STATUS_SUCCESS;
-
- status = _cairo_gl_context_acquire (surface->base.device, &ctx);
- if (unlikely (status))
- return status;
-
-#if CAIRO_HAS_GLESV3_SURFACE
- _cairo_gl_composite_flush (ctx);
- ctx->current_target = NULL;
- _cairo_gl_context_bind_framebuffer (ctx, surface, FALSE);
- if (ctx->gl_flavor == CAIRO_GL_FLAVOR_ES3)
- surface->content_in_texture = TRUE;
-
-#elif CAIRO_HAS_GL_SURFACE
- ctx->current_target = surface;
- _cairo_gl_context_bind_framebuffer (ctx, surface, FALSE);
-
-#else
- ctx->current_target = surface;
-
-#endif
-
- status = _cairo_gl_context_release (ctx, status);
- return status;
-}
-
-static const cairo_compositor_t *
-get_compositor (cairo_gl_surface_t *surface)
-{
- cairo_gl_context_t *ctx = (cairo_gl_context_t *)surface->base.device;
- return ctx->compositor;
-}
-
-static cairo_int_status_t
-_cairo_gl_surface_paint (void *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_clip_t *clip)
-{
- /* simplify the common case of clearing the surface */
- if (clip == NULL) {
- if (op == CAIRO_OPERATOR_CLEAR)
- return _cairo_gl_surface_clear (surface, CAIRO_COLOR_TRANSPARENT);
- else if (source->type == CAIRO_PATTERN_TYPE_SOLID &&
- (op == CAIRO_OPERATOR_SOURCE ||
- (op == CAIRO_OPERATOR_OVER && _cairo_pattern_is_opaque_solid (source)))) {
- return _cairo_gl_surface_clear (surface,
- &((cairo_solid_pattern_t *) source)->color);
- }
- }
-
- return _cairo_compositor_paint (get_compositor (surface), surface,
- op, source, clip);
-}
-
-static cairo_int_status_t
-_cairo_gl_surface_mask (void *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_pattern_t *mask,
- const cairo_clip_t *clip)
-{
- return _cairo_compositor_mask (get_compositor (surface), surface,
- op, source, mask, clip);
-}
-
-static cairo_int_status_t
-_cairo_gl_surface_stroke (void *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- const cairo_stroke_style_t *style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip)
-{
- return _cairo_compositor_stroke (get_compositor (surface), surface,
- op, source, path, style,
- ctm, ctm_inverse, tolerance, antialias,
- clip);
-}
-
-static cairo_int_status_t
-_cairo_gl_surface_fill (void *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t*path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip)
-{
- return _cairo_compositor_fill (get_compositor (surface), surface,
- op, source, path,
- fill_rule, tolerance, antialias,
- clip);
-}
-
-static cairo_int_status_t
-_cairo_gl_surface_glyphs (void *surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *font,
- const cairo_clip_t *clip)
-{
- return _cairo_compositor_glyphs (get_compositor (surface), surface,
- op, source, glyphs, num_glyphs, font,
- clip);
-}
-
-static const cairo_surface_backend_t _cairo_gl_surface_backend = {
- CAIRO_SURFACE_TYPE_GL,
- _cairo_gl_surface_finish,
- _cairo_default_context_create,
-
- _cairo_gl_surface_create_similar,
- NULL, /* similar image */
- _cairo_gl_surface_map_to_image,
- _cairo_gl_surface_unmap_image,
-
- _cairo_gl_surface_source,
- _cairo_gl_surface_acquire_source_image,
- _cairo_gl_surface_release_source_image,
- NULL, /* snapshot */
-
- NULL, /* copy_page */
- NULL, /* show_page */
-
- _cairo_gl_surface_get_extents,
- _cairo_image_surface_get_font_options,
-
- _cairo_gl_surface_flush,
- NULL, /* mark_dirty_rectangle */
-
- _cairo_gl_surface_paint,
- _cairo_gl_surface_mask,
- _cairo_gl_surface_stroke,
- _cairo_gl_surface_fill,
- NULL, /* fill/stroke */
- _cairo_gl_surface_glyphs,
-};
diff --git a/src/cairo-gl-traps-compositor.c b/src/cairo-gl-traps-compositor.c
deleted file mode 100644
index 7938c5b20..000000000
--- a/src/cairo-gl-traps-compositor.c
+++ /dev/null
@@ -1,531 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 Eric Anholt
- * Copyright © 2009 Chris Wilson
- * Copyright © 2005,2010 Red Hat, Inc
- * Copyright © 2011 Intel Corporation
- *
- * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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):
- * Benjamin Otte <otte@gnome.org>
- * Carl Worth <cworth@cworth.org>
- * Chris Wilson <chris@chris-wilson.co.uk>
- * Eric Anholt <eric@anholt.net>
- */
-
-#include "cairoint.h"
-
-#include "cairo-gl-private.h"
-
-#include "cairo-composite-rectangles-private.h"
-#include "cairo-compositor-private.h"
-#include "cairo-default-context-private.h"
-#include "cairo-error-private.h"
-#include "cairo-image-surface-private.h"
-#include "cairo-spans-compositor-private.h"
-#include "cairo-surface-backend-private.h"
-#include "cairo-surface-offset-private.h"
-
-static cairo_int_status_t
-acquire (void *abstract_dst)
-{
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-release (void *abstract_dst)
-{
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-set_clip_region (void *_surface,
- cairo_region_t *region)
-{
- cairo_gl_surface_t *surface = _surface;
-
- surface->clip_region = region;
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-draw_image_boxes (void *_dst,
- cairo_image_surface_t *image,
- cairo_boxes_t *boxes,
- int dx, int dy)
-{
- cairo_gl_surface_t *dst = _dst;
- struct _cairo_boxes_chunk *chunk;
- int i;
-
- for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
- for (i = 0; i < chunk->count; i++) {
- cairo_box_t *b = &chunk->base[i];
- int x = _cairo_fixed_integer_part (b->p1.x);
- int y = _cairo_fixed_integer_part (b->p1.y);
- int w = _cairo_fixed_integer_part (b->p2.x) - x;
- int h = _cairo_fixed_integer_part (b->p2.y) - y;
- cairo_status_t status;
-
- status = _cairo_gl_surface_draw_image (dst, image,
- x + dx, y + dy,
- w, h,
- x, y,
- TRUE);
- if (unlikely (status))
- return status;
- }
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-emit_aligned_boxes (cairo_gl_context_t *ctx,
- const cairo_boxes_t *boxes)
-{
- const struct _cairo_boxes_chunk *chunk;
- cairo_gl_emit_rect_t emit = _cairo_gl_context_choose_emit_rect (ctx);
- int i;
-
- for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
- for (i = 0; i < chunk->count; i++) {
- int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
- int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
- int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
- int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
- emit (ctx, x1, y1, x2, y2);
- }
- }
-}
-
-static cairo_int_status_t
-fill_boxes (void *_dst,
- cairo_operator_t op,
- const cairo_color_t *color,
- cairo_boxes_t *boxes)
-{
- cairo_gl_composite_t setup;
- cairo_gl_context_t *ctx;
- cairo_int_status_t status;
-
- status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
- if (unlikely (status))
- goto FAIL;
-
- _cairo_gl_composite_set_solid_source (&setup, color);
-
- status = _cairo_gl_composite_begin (&setup, &ctx);
- if (unlikely (status))
- goto FAIL;
-
- emit_aligned_boxes (ctx, boxes);
- status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
-
-FAIL:
- _cairo_gl_composite_fini (&setup);
- return status;
-}
-
-static cairo_int_status_t
-composite_boxes (void *_dst,
- cairo_operator_t op,
- cairo_surface_t *abstract_src,
- cairo_surface_t *abstract_mask,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- cairo_boxes_t *boxes,
- const cairo_rectangle_int_t *extents)
-{
- cairo_gl_composite_t setup;
- cairo_gl_context_t *ctx;
- cairo_int_status_t status;
-
- status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
- if (unlikely (status))
- goto FAIL;
-
- _cairo_gl_composite_set_source_operand (&setup,
- source_to_operand (abstract_src));
- _cairo_gl_operand_translate (&setup.src, dst_x-src_x, dst_y-src_y);
-
- _cairo_gl_composite_set_mask_operand (&setup,
- source_to_operand (abstract_mask));
- _cairo_gl_operand_translate (&setup.mask, dst_x-mask_x, dst_y-mask_y);
-
- status = _cairo_gl_composite_begin (&setup, &ctx);
- if (unlikely (status))
- goto FAIL;
-
- emit_aligned_boxes (ctx, boxes);
- status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
-
-FAIL:
- _cairo_gl_composite_fini (&setup);
- return status;
-}
-
-static cairo_int_status_t
-composite (void *_dst,
- cairo_operator_t op,
- cairo_surface_t *abstract_src,
- cairo_surface_t *abstract_mask,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- cairo_gl_composite_t setup;
- cairo_gl_context_t *ctx;
- cairo_int_status_t status;
-
- status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
- if (unlikely (status))
- goto FAIL;
-
- _cairo_gl_composite_set_source_operand (&setup,
- source_to_operand (abstract_src));
- _cairo_gl_operand_translate (&setup.src, dst_x-src_x, dst_y-src_y);
-
- _cairo_gl_composite_set_mask_operand (&setup,
- source_to_operand (abstract_mask));
- _cairo_gl_operand_translate (&setup.mask, dst_x-mask_x, dst_y-mask_y);
-
- status = _cairo_gl_composite_begin (&setup, &ctx);
- if (unlikely (status))
- goto FAIL;
-
- /* XXX clip */
- _cairo_gl_context_emit_rect (ctx, dst_x, dst_y, dst_x+width, dst_y+height);
- status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
-
-FAIL:
- _cairo_gl_composite_fini (&setup);
- return status;
-}
-
-static cairo_int_status_t
-lerp (void *dst,
- cairo_surface_t *src,
- cairo_surface_t *mask,
- int src_x,
- int src_y,
- int mask_x,
- int mask_y,
- int dst_x,
- int dst_y,
- unsigned int width,
- unsigned int height)
-{
- cairo_int_status_t status;
-
- /* we could avoid some repetition... */
- status = composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL,
- mask_x, mask_y,
- 0, 0,
- dst_x, dst_y,
- width, height);
- if (unlikely (status))
- return status;
-
- status = composite (dst, CAIRO_OPERATOR_ADD, src, mask,
- src_x, src_y,
- mask_x, mask_y,
- dst_x, dst_y,
- width, height);
- if (unlikely (status))
- return status;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-traps_to_operand (void *_dst,
- const cairo_rectangle_int_t *extents,
- cairo_antialias_t antialias,
- cairo_traps_t *traps,
- cairo_gl_operand_t *operand,
- int dst_x, int dst_y)
-{
- pixman_format_code_t pixman_format;
- pixman_image_t *pixman_image;
- cairo_surface_t *image, *mask;
- cairo_surface_pattern_t pattern;
- cairo_status_t status;
-
- pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1;
- pixman_image = pixman_image_create_bits (pixman_format,
- extents->width,
- extents->height,
- NULL, 0);
- if (unlikely (pixman_image == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- _pixman_image_add_traps (pixman_image, extents->x, extents->y, traps);
- image = _cairo_image_surface_create_for_pixman_image (pixman_image,
- pixman_format);
- if (unlikely (image->status)) {
- pixman_image_unref (pixman_image);
- return image->status;
- }
-
- mask = _cairo_surface_create_scratch (_dst,
- CAIRO_CONTENT_COLOR_ALPHA,
- extents->width,
- extents->height,
- NULL);
- if (unlikely (mask->status)) {
- cairo_surface_destroy (image);
- return mask->status;
- }
-
- status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask,
- (cairo_image_surface_t *)image,
- 0, 0,
- extents->width, extents->height,
- 0, 0,
- TRUE);
- cairo_surface_destroy (image);
-
- if (unlikely (status))
- goto error;
-
- _cairo_pattern_init_for_surface (&pattern, mask);
- cairo_matrix_init_translate (&pattern.base.matrix,
- -extents->x+dst_x, -extents->y+dst_y);
- pattern.base.filter = CAIRO_FILTER_NEAREST;
- pattern.base.extend = CAIRO_EXTEND_NONE;
- status = _cairo_gl_operand_init (operand, &pattern.base, _dst,
- &_cairo_unbounded_rectangle,
- &_cairo_unbounded_rectangle,
- FALSE);
- _cairo_pattern_fini (&pattern.base);
-
- if (unlikely (status))
- goto error;
-
- operand->texture.owns_surface = (cairo_gl_surface_t *)mask;
- return CAIRO_STATUS_SUCCESS;
-
-error:
- cairo_surface_destroy (mask);
- return status;
-}
-
-static cairo_int_status_t
-composite_traps (void *_dst,
- cairo_operator_t op,
- cairo_surface_t *abstract_src,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- const cairo_rectangle_int_t *extents,
- cairo_antialias_t antialias,
- cairo_traps_t *traps)
-{
- cairo_gl_composite_t setup;
- cairo_gl_context_t *ctx;
- cairo_int_status_t status;
-
- status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
- if (unlikely (status))
- goto FAIL;
-
- _cairo_gl_composite_set_source_operand (&setup,
- source_to_operand (abstract_src));
- _cairo_gl_operand_translate (&setup.src, -src_x-dst_x, -src_y-dst_y);
- status = traps_to_operand (_dst, extents, antialias, traps, &setup.mask, dst_x, dst_y);
- if (unlikely (status))
- goto FAIL;
-
- status = _cairo_gl_composite_begin (&setup, &ctx);
- if (unlikely (status))
- goto FAIL;
-
- /* XXX clip */
- _cairo_gl_context_emit_rect (ctx,
- extents->x-dst_x, extents->y-dst_y,
- extents->x-dst_x+extents->width,
- extents->y-dst_y+extents->height);
- status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
-
-FAIL:
- _cairo_gl_composite_fini (&setup);
- return status;
-}
-
-static cairo_gl_surface_t *
-tristrip_to_surface (void *_dst,
- const cairo_rectangle_int_t *extents,
- cairo_antialias_t antialias,
- cairo_tristrip_t *strip)
-{
- pixman_format_code_t pixman_format;
- pixman_image_t *pixman_image;
- cairo_surface_t *image, *mask;
- cairo_status_t status;
-
- pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1,
- pixman_image = pixman_image_create_bits (pixman_format,
- extents->width,
- extents->height,
- NULL, 0);
- if (unlikely (pixman_image == NULL))
- return (cairo_gl_surface_t *)_cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
-
- _pixman_image_add_tristrip (pixman_image, extents->x, extents->y, strip);
- image = _cairo_image_surface_create_for_pixman_image (pixman_image,
- pixman_format);
- if (unlikely (image->status)) {
- pixman_image_unref (pixman_image);
- return (cairo_gl_surface_t *)image;
- }
-
- mask = _cairo_surface_create_scratch (_dst,
- CAIRO_CONTENT_COLOR_ALPHA,
- extents->width,
- extents->height,
- NULL);
- if (unlikely (mask->status)) {
- cairo_surface_destroy (image);
- return (cairo_gl_surface_t *)mask;
- }
-
- status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask,
- (cairo_image_surface_t *)image,
- 0, 0,
- extents->width, extents->height,
- 0, 0,
- TRUE);
- cairo_surface_destroy (image);
- if (unlikely (status)) {
- cairo_surface_destroy (mask);
- return (cairo_gl_surface_t*)_cairo_surface_create_in_error (status);
- }
-
- return (cairo_gl_surface_t*)mask;
-}
-
-static cairo_int_status_t
-composite_tristrip (void *_dst,
- cairo_operator_t op,
- cairo_surface_t *abstract_src,
- int src_x,
- int src_y,
- int dst_x,
- int dst_y,
- const cairo_rectangle_int_t *extents,
- cairo_antialias_t antialias,
- cairo_tristrip_t *strip)
-{
- cairo_gl_composite_t setup;
- cairo_gl_context_t *ctx;
- cairo_gl_surface_t *mask;
- cairo_int_status_t status;
-
- mask = tristrip_to_surface (_dst, extents, antialias, strip);
- if (unlikely (mask->base.status))
- return mask->base.status;
-
- status = _cairo_gl_composite_init (&setup, op, _dst, FALSE);
- if (unlikely (status))
- goto FAIL;
-
- _cairo_gl_composite_set_source_operand (&setup,
- source_to_operand (abstract_src));
-
- //_cairo_gl_composite_set_mask_surface (&setup, mask, 0, 0);
-
- status = _cairo_gl_composite_begin (&setup, &ctx);
- if (unlikely (status))
- goto FAIL;
-
- /* XXX clip */
- _cairo_gl_context_emit_rect (ctx,
- dst_x, dst_y,
- dst_x+extents->width,
- dst_y+extents->height);
- status = _cairo_gl_context_release (ctx, CAIRO_STATUS_SUCCESS);
-
-FAIL:
- _cairo_gl_composite_fini (&setup);
- cairo_surface_destroy (&mask->base);
- return status;
-}
-
-static cairo_int_status_t
-check_composite (const cairo_composite_rectangles_t *extents)
-{
- if (! _cairo_gl_operator_is_supported (extents->op))
- return UNSUPPORTED ("unsupported operator");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-const cairo_compositor_t *
-_cairo_gl_traps_compositor_get (void)
-{
- static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
- static cairo_traps_compositor_t compositor;
-
- if (_cairo_atomic_init_once_enter(&once)) {
- _cairo_traps_compositor_init (&compositor, &_cairo_fallback_compositor);
- compositor.acquire = acquire;
- compositor.release = release;
- compositor.set_clip_region = set_clip_region;
- compositor.pattern_to_surface = _cairo_gl_pattern_to_source;
- compositor.draw_image_boxes = draw_image_boxes;
- //compositor.copy_boxes = copy_boxes;
- compositor.fill_boxes = fill_boxes;
- compositor.check_composite = check_composite;
- compositor.composite = composite;
- compositor.lerp = lerp;
- //compositor.check_composite_boxes = check_composite_boxes;
- compositor.composite_boxes = composite_boxes;
- //compositor.check_composite_traps = check_composite_traps;
- compositor.composite_traps = composite_traps;
- //compositor.check_composite_tristrip = check_composite_traps;
- compositor.composite_tristrip = composite_tristrip;
- compositor.check_composite_glyphs = _cairo_gl_check_composite_glyphs;
- compositor.composite_glyphs = _cairo_gl_composite_glyphs;
-
- _cairo_atomic_init_once_leave(&once);
- }
-
- return &compositor.base;
-}
diff --git a/src/cairo-gl.h b/src/cairo-gl.h
deleted file mode 100644
index 7cd869c76..000000000
--- a/src/cairo-gl.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/* Cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 Eric Anholt
- * Copyright © 2009 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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 Eric Anholt.
- */
-
-/*
- * cairo-gl.h:
- *
- * The cairo-gl backend provides an implementation of possibly
- * hardware-accelerated cairo rendering by targeting the OpenGL API.
- * The goal of the cairo-gl backend is to provide better performance
- * with equal functionality to cairo-image where possible. It does
- * not directly provide for applying additional OpenGL effects to
- * cairo surfaces.
- *
- * Cairo-gl allows interoperability with other GL rendering through GL
- * context sharing. Cairo-gl surfaces are created in reference to a
- * #cairo_device_t, which represents a GL context created by the user.
- * When that GL context is created with its sharePtr set to another
- * context (or vice versa), its objects (textures backing cairo-gl
- * surfaces) can be accessed in the other OpenGL context. This allows
- * cairo-gl to maintain its drawing state in one context while the
- * user's 3D rendering occurs in the user's other context.
- *
- * However, as only one context can be current to a thread at a time,
- * cairo-gl may make its context current to the thread on any cairo
- * call which interacts with a cairo-gl surface or the cairo-gl
- * device. As a result, the user must make their own context current
- * between any cairo calls and their own OpenGL rendering.
- **/
-
-#ifndef CAIRO_GL_H
-#define CAIRO_GL_H
-
-#include "cairo.h"
-
-#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV2_SURFACE || CAIRO_HAS_GLESV3_SURFACE
-
-CAIRO_BEGIN_DECLS
-
-cairo_public cairo_surface_t *
-cairo_gl_surface_create (cairo_device_t *device,
- cairo_content_t content,
- int width, int height);
-
-cairo_public cairo_surface_t *
-cairo_gl_surface_create_for_texture (cairo_device_t *abstract_device,
- cairo_content_t content,
- unsigned int tex,
- int width, int height);
-cairo_public void
-cairo_gl_surface_set_size (cairo_surface_t *surface, int width, int height);
-
-cairo_public int
-cairo_gl_surface_get_width (cairo_surface_t *abstract_surface);
-
-cairo_public int
-cairo_gl_surface_get_height (cairo_surface_t *abstract_surface);
-
-cairo_public void
-cairo_gl_surface_swapbuffers (cairo_surface_t *surface);
-
-cairo_public void
-cairo_gl_device_set_thread_aware (cairo_device_t *device,
- cairo_bool_t thread_aware);
-
-#if CAIRO_HAS_GLX_FUNCTIONS
-#include <GL/glx.h>
-
-cairo_public cairo_device_t *
-cairo_glx_device_create (Display *dpy, GLXContext gl_ctx);
-
-cairo_public Display *
-cairo_glx_device_get_display (cairo_device_t *device);
-
-cairo_public GLXContext
-cairo_glx_device_get_context (cairo_device_t *device);
-
-cairo_public cairo_surface_t *
-cairo_gl_surface_create_for_window (cairo_device_t *device,
- Window win,
- int width, int height);
-#endif
-
-#if CAIRO_HAS_WGL_FUNCTIONS
-#include <windows.h>
-
-cairo_public cairo_device_t *
-cairo_wgl_device_create (HGLRC rc);
-
-cairo_public HGLRC
-cairo_wgl_device_get_context (cairo_device_t *device);
-
-cairo_public cairo_surface_t *
-cairo_gl_surface_create_for_dc (cairo_device_t *device,
- HDC dc,
- int width,
- int height);
-#endif
-
-#if CAIRO_HAS_EGL_FUNCTIONS
-#include <EGL/egl.h>
-
-cairo_public cairo_device_t *
-cairo_egl_device_create (EGLDisplay dpy, EGLContext egl);
-
-cairo_public cairo_surface_t *
-cairo_gl_surface_create_for_egl (cairo_device_t *device,
- EGLSurface egl,
- int width,
- int height);
-
-cairo_public EGLDisplay
-cairo_egl_device_get_display (cairo_device_t *device);
-
-cairo_public EGLSurface
-cairo_egl_device_get_context (cairo_device_t *device);
-
-#endif
-
-CAIRO_END_DECLS
-
-#else /* CAIRO_HAS_GL_SURFACE */
-# error Cairo was not compiled with support for the GL backend
-#endif /* CAIRO_HAS_GL_SURFACE */
-
-#endif /* CAIRO_GL_H */
diff --git a/src/cairo-glx-context.c b/src/cairo-glx-context.c
deleted file mode 100644
index 66f5a0d1b..000000000
--- a/src/cairo-glx-context.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 Eric Anholt
- * Copyright © 2009 Chris Wilson
- * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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):
- * Carl Worth <cworth@cworth.org>
- * Chris Wilson <chris@chris-wilson.co.uk>
- */
-
-#include "cairoint.h"
-
-#include "cairo-gl-private.h"
-
-#include "cairo-error-private.h"
-
-#include <X11/Xutil.h>
-
-/* XXX needs hooking into XCloseDisplay() */
-
-typedef struct _cairo_glx_context {
- cairo_gl_context_t base;
-
- Display *display;
- Window dummy_window;
- GLXContext context;
-
- GLXDrawable previous_drawable;
- GLXContext previous_context;
-
- cairo_bool_t has_multithread_makecurrent;
-} cairo_glx_context_t;
-
-typedef struct _cairo_glx_surface {
- cairo_gl_surface_t base;
-
- Window win;
-} cairo_glx_surface_t;
-
-static cairo_bool_t
-_context_acquisition_changed_glx_state (cairo_glx_context_t *ctx,
- GLXDrawable current_drawable)
-{
- return ctx->previous_drawable != current_drawable ||
- ctx->previous_context != ctx->context;
-}
-
-static GLXDrawable
-_glx_get_current_drawable (cairo_glx_context_t *ctx)
-{
- if (ctx->base.current_target == NULL ||
- _cairo_gl_surface_is_texture (ctx->base.current_target)) {
- return ctx->dummy_window;
- }
-
- return ((cairo_glx_surface_t *) ctx->base.current_target)->win;
-}
-
-static void
-_glx_query_current_state (cairo_glx_context_t * ctx)
-{
- ctx->previous_drawable = glXGetCurrentDrawable ();
- ctx->previous_context = glXGetCurrentContext ();
-
- /* If any of the values were none, assume they are all none. Not all
- drivers seem well behaved when it comes to using these values across
- multiple threads. */
- if (ctx->previous_drawable == None ||
- ctx->previous_context == None) {
- ctx->previous_drawable = None;
- ctx->previous_context = None;
- }
-}
-
-static void
-_glx_acquire (void *abstract_ctx)
-{
- cairo_glx_context_t *ctx = abstract_ctx;
- GLXDrawable current_drawable = _glx_get_current_drawable (ctx);
-
- _glx_query_current_state (ctx);
- if (!_context_acquisition_changed_glx_state (ctx, current_drawable))
- return;
-
- glXMakeCurrent (ctx->display, current_drawable, ctx->context);
-}
-
-static void
-_glx_make_current (void *abstract_ctx, cairo_gl_surface_t *abstract_surface)
-{
- cairo_glx_context_t *ctx = abstract_ctx;
- cairo_glx_surface_t *surface = (cairo_glx_surface_t *) abstract_surface;
-
- /* Set the window as the target of our context. */
- glXMakeCurrent (ctx->display, surface->win, ctx->context);
-}
-
-static void
-_glx_release (void *abstract_ctx)
-{
- cairo_glx_context_t *ctx = abstract_ctx;
-
- if (ctx->has_multithread_makecurrent || !ctx->base.thread_aware ||
- !_context_acquisition_changed_glx_state (ctx,
- _glx_get_current_drawable (ctx))) {
- return;
- }
-
- glXMakeCurrent (ctx->display, None, None);
-}
-
-static void
-_glx_swap_buffers (void *abstract_ctx,
- cairo_gl_surface_t *abstract_surface)
-{
- cairo_glx_context_t *ctx = abstract_ctx;
- cairo_glx_surface_t *surface = (cairo_glx_surface_t *) abstract_surface;
-
- glXSwapBuffers (ctx->display, surface->win);
-}
-
-static void
-_glx_destroy (void *abstract_ctx)
-{
- cairo_glx_context_t *ctx = abstract_ctx;
-
- if (ctx->dummy_window != None)
- XDestroyWindow (ctx->display, ctx->dummy_window);
-
- glXMakeCurrent (ctx->display, None, None);
-}
-
-static cairo_status_t
-_glx_dummy_window (Display *dpy, GLXContext gl_ctx, Window *dummy)
-{
- int attr[3] = { GLX_FBCONFIG_ID, 0, None };
- GLXFBConfig *config;
- XVisualInfo *vi;
- Colormap cmap;
- XSetWindowAttributes swa;
- Window win = None;
- int cnt;
-
- /* Create a dummy window created for the target GLX context that we can
- * use to query the available GL/GLX extensions.
- */
- glXQueryContext (dpy, gl_ctx, GLX_FBCONFIG_ID, &attr[1]);
-
- cnt = 0;
- config = glXChooseFBConfig (dpy, DefaultScreen (dpy), attr, &cnt);
- if (unlikely (cnt == 0))
- return _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
-
- vi = glXGetVisualFromFBConfig (dpy, config[0]);
- XFree (config);
-
- if (unlikely (vi == NULL))
- return _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
-
- cmap = XCreateColormap (dpy,
- RootWindow (dpy, vi->screen),
- vi->visual,
- AllocNone);
- swa.colormap = cmap;
- swa.border_pixel = 0;
- win = XCreateWindow (dpy, RootWindow (dpy, vi->screen),
- -1, -1, 1, 1, 0,
- vi->depth,
- InputOutput,
- vi->visual,
- CWBorderPixel | CWColormap, &swa);
- XFreeColormap (dpy, cmap);
- XFree (vi);
-
- XFlush (dpy);
- if (unlikely (! glXMakeCurrent (dpy, win, gl_ctx))) {
- XDestroyWindow (dpy, win);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- }
-
- *dummy = win;
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_device_t *
-cairo_glx_device_create (Display *dpy, GLXContext gl_ctx)
-{
- cairo_glx_context_t *ctx;
- cairo_status_t status;
- Window dummy = None;
- const char *glx_extensions;
-
- ctx = calloc (1, sizeof (cairo_glx_context_t));
- if (unlikely (ctx == NULL))
- return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
-
- /* glx_dummy_window will call glXMakeCurrent, so we need to
- * query the current state of the context now. */
- _glx_query_current_state (ctx);
-
- status = _glx_dummy_window (dpy, gl_ctx, &dummy);
- if (unlikely (status)) {
- free (ctx);
- return _cairo_gl_context_create_in_error (status);
- }
-
- ctx->display = dpy;
- ctx->dummy_window = dummy;
- ctx->context = gl_ctx;
-
- ctx->base.acquire = _glx_acquire;
- ctx->base.release = _glx_release;
- ctx->base.make_current = _glx_make_current;
- ctx->base.swap_buffers = _glx_swap_buffers;
- ctx->base.destroy = _glx_destroy;
-
- status = _cairo_gl_dispatch_init (&ctx->base.dispatch,
- (cairo_gl_get_proc_addr_func_t) glXGetProcAddress);
- if (unlikely (status)) {
- free (ctx);
- return _cairo_gl_context_create_in_error (status);
- }
-
- status = _cairo_gl_context_init (&ctx->base);
- if (unlikely (status)) {
- free (ctx);
- return _cairo_gl_context_create_in_error (status);
- }
-
- glx_extensions = glXQueryExtensionsString (dpy, DefaultScreen (dpy));
- if (strstr(glx_extensions, "GLX_MESA_multithread_makecurrent")) {
- ctx->has_multithread_makecurrent = TRUE;
- }
-
- ctx->base.release (ctx);
-
- return &ctx->base.base;
-}
-
-Display *
-cairo_glx_device_get_display (cairo_device_t *device)
-{
- cairo_glx_context_t *ctx;
-
- if (device->backend->type != CAIRO_DEVICE_TYPE_GL) {
- _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
- return NULL;
- }
-
- ctx = (cairo_glx_context_t *) device;
-
- return ctx->display;
-}
-
-GLXContext
-cairo_glx_device_get_context (cairo_device_t *device)
-{
- cairo_glx_context_t *ctx;
-
- if (device->backend->type != CAIRO_DEVICE_TYPE_GL) {
- _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
- return NULL;
- }
-
- ctx = (cairo_glx_context_t *) device;
-
- return ctx->context;
-}
-
-cairo_surface_t *
-cairo_gl_surface_create_for_window (cairo_device_t *device,
- Window win,
- int width,
- int height)
-{
- cairo_glx_surface_t *surface;
-
- if (unlikely (device->status))
- return _cairo_surface_create_in_error (device->status);
-
- if (device->backend->type != CAIRO_DEVICE_TYPE_GL)
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
-
- if (width <= 0 || height <= 0)
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
-
- surface = calloc (1, sizeof (cairo_glx_surface_t));
- if (unlikely (surface == NULL))
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
-
- _cairo_gl_surface_init (device, &surface->base,
- CAIRO_CONTENT_COLOR_ALPHA, width, height);
- surface->win = win;
-
- return &surface->base.base;
-}
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index a8c67e718..8a253468d 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -1145,7 +1145,7 @@ _cairo_gstate_mask (cairo_gstate_t *gstate,
}
_cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask);
- if (source->type == CAIRO_PATTERN_TYPE_SOLID &&
+ if (source->type == CAIRO_PATTERN_TYPE_SOLID && !source->is_foreground_marker &&
mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
_cairo_operator_bounded_by_source (op))
{
@@ -1748,11 +1748,12 @@ void
_cairo_gstate_set_font_options (cairo_gstate_t *gstate,
const cairo_font_options_t *options)
{
- if (memcmp (options, &gstate->font_options, sizeof (cairo_font_options_t)) == 0)
+ if (_cairo_font_options_compare (options, &gstate->font_options))
return;
_cairo_gstate_unset_scaled_font (gstate);
+ _cairo_font_options_fini (&gstate->font_options);
_cairo_font_options_init_copy (&gstate->font_options, options);
}
@@ -1760,7 +1761,8 @@ void
_cairo_gstate_get_font_options (cairo_gstate_t *gstate,
cairo_font_options_t *options)
{
- *options = gstate->font_options;
+ _cairo_font_options_fini (options);
+ _cairo_font_options_init_copy (options, &gstate->font_options);
}
cairo_status_t
diff --git a/src/cairo-image-info.c b/src/cairo-image-info.c
index f207ae887..9693e487f 100644
--- a/src/cairo-image-info.c
+++ b/src/cairo-image-info.c
@@ -162,9 +162,15 @@ static const unsigned char _jpx_signature[] = {
};
static const unsigned char *
-_jpx_next_box (const unsigned char *p)
+_jpx_next_box (const unsigned char *p, const unsigned char *end)
{
- return p + get_unaligned_be32 (p);
+ if (p + 4 < end) {
+ uint32_t length = get_unaligned_be32 (p);
+ if (p + length < end)
+ return p + length;
+ }
+
+ return end;
}
static const unsigned char *
@@ -193,19 +199,25 @@ _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);
+ p = _jpx_next_box (p, end);
}
return NULL;
}
-static void
-_jpx_extract_info (const unsigned char *p, cairo_image_info_t *info)
+static cairo_int_status_t
+_jpx_extract_info (const unsigned char *p, cairo_image_info_t *info, const unsigned char *end)
{
+ if (p + 11 >= end) {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
info->height = get_unaligned_be32 (p);
info->width = get_unaligned_be32 (p + 4);
info->num_components = (p[8] << 8) + p[9];
info->bits_per_component = p[10];
+
+ return CAIRO_STATUS_SUCCESS;
}
cairo_int_status_t
@@ -227,7 +239,7 @@ _cairo_image_info_get_jpx_info (cairo_image_info_t *info,
if (! _jpx_match_box (p, end, JPX_FILETYPE))
return CAIRO_INT_STATUS_UNSUPPORTED;
- p = _jpx_next_box (p);
+ p = _jpx_next_box (p, end);
/* Locate the JP2 header box. */
p = _jpx_find_box (p, end, JPX_JP2_HEADER);
@@ -242,9 +254,7 @@ _cairo_image_info_get_jpx_info (cairo_image_info_t *info,
/* Get the image info */
p = _jpx_get_box_contents (p);
- _jpx_extract_info (p, info);
-
- return CAIRO_STATUS_SUCCESS;
+ return _jpx_extract_info (p, info, end);
}
/* PNG (image/png)
@@ -348,6 +358,8 @@ _jbig2_get_next_segment (const unsigned char *p,
num_segs = p[0] >> 5;
if (num_segs == 7) {
+ if (p + 4 >= end)
+ return NULL;
num_segs = get_unaligned_be32 (p) & 0x1fffffff;
ref_seg_bytes = 4 + ((num_segs + 1)/8);
} else {
diff --git a/src/cairo-image-source.c b/src/cairo-image-source.c
index c56845ab2..aafdaeded 100644
--- a/src/cairo-image-source.c
+++ b/src/cairo-image-source.c
@@ -1207,6 +1207,8 @@ _pixman_image_for_recording (cairo_image_surface_t *dst,
clone = _cairo_image_surface_create_with_content (source->content,
limit.width,
limit.height);
+ if (dst->base.foreground_source)
+ clone->foreground_source = cairo_pattern_reference (dst->base.foreground_source);
}
m = NULL;
@@ -1223,7 +1225,9 @@ _pixman_image_for_recording (cairo_image_surface_t *dst,
/* Handle recursion by returning future reads from the current image */
proxy = attach_proxy (source, clone);
- status = _cairo_recording_surface_replay_with_clip (source, m, clone, NULL);
+ status = _cairo_recording_surface_replay_with_clip (source, m, clone, NULL, FALSE);
+ if (clone->foreground_used)
+ dst->base.foreground_used = clone->foreground_used;
detach_proxy (source, proxy);
if (unlikely (status)) {
cairo_surface_destroy (clone);
diff --git a/src/cairo-lzw.c b/src/cairo-lzw.c
index f27b3c338..e17cdfc1c 100644
--- a/src/cairo-lzw.c
+++ b/src/cairo-lzw.c
@@ -369,10 +369,10 @@ _cairo_lzw_compress (unsigned char *data, unsigned long *size_in_out)
* lookup. */
_lzw_buf_store_bits (&buf, prev, code_bits);
- if (bytes_remaining == 0)
- break;
+ if (likely (slot != NULL))
+ LZW_SYMBOL_SET_CODE (*slot, code_next, prev, next);
- LZW_SYMBOL_SET_CODE (*slot, code_next++, prev, next);
+ code_next++;
if (code_next > LZW_BITS_BOUNDARY(code_bits))
{
@@ -384,6 +384,9 @@ _cairo_lzw_compress (unsigned char *data, unsigned long *size_in_out)
code_next = LZW_CODE_FIRST;
}
}
+
+ if (bytes_remaining == 0)
+ break;
}
/* The LZW footer is an end-of-data code. */
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index f3cf684c9..e8fd097ae 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -304,6 +304,7 @@ cairo_matrix_rotate (cairo_matrix_t *matrix, double radians)
cairo_matrix_multiply (matrix, &tmp, matrix);
}
+slim_hidden_def (cairo_matrix_rotate);
/**
* cairo_matrix_multiply:
@@ -372,15 +373,10 @@ _cairo_matrix_multiply (cairo_matrix_t *r,
* the returned vector is as follows:
*
* <programlisting>
- * dx2 = dx1 * a + dy1 * c;
- * dy2 = dx1 * b + dy1 * d;
+ * dx_new = xx * dx + xy * dy;
+ * dy_new = yx * dx + yy * dy;
* </programlisting>
*
- * Affine transformations are position invariant, so the same vector
- * always transforms to the same vector. If (@x1,@y1) transforms
- * to (@x2,@y2) then (@x1+@dx1,@y1+@dy1) will transform to
- * (@x1+@dx2,@y1+@dy2) for all values of @x1 and @x2.
- *
* Since: 1.0
**/
void
diff --git a/src/cairo-mesh-pattern-rasterizer.c b/src/cairo-mesh-pattern-rasterizer.c
index e7f0db666..f47800c8a 100644
--- a/src/cairo-mesh-pattern-rasterizer.c
+++ b/src/cairo-mesh-pattern-rasterizer.c
@@ -659,7 +659,7 @@ draw_bezier_curve (unsigned char *data, int width, int height, int stride,
* width, height are the dimensions of the image
* stride is the stride in bytes between adjacent rows
* vshift is log2(n) if n is the number of desired steps
- * p[i][j], p[i][j] are the the nodes of the Bezier patch
+ * p[i][j], p[i][j] are the nodes of the Bezier patch
* col[i][j] is the j-th color component of the i-th corner
*
* Output: data will be changed to have the requested patch drawn in
diff --git a/src/cairo-misc.c b/src/cairo-misc.c
index bf8a62730..6f6f9937e 100644
--- a/src/cairo-misc.c
+++ b/src/cairo-misc.c
@@ -176,6 +176,8 @@ cairo_status_to_string (cairo_status_t status)
return "invalid tag name, attributes, or nesting";
case CAIRO_STATUS_DWRITE_ERROR:
return "Window Direct Write error";
+ case CAIRO_STATUS_SVG_FONT_ERROR:
+ return "error occured while rendering an OpenType-SVG font";
default:
case CAIRO_STATUS_LAST_STATUS:
return "<unknown error status>";
@@ -888,6 +890,33 @@ _cairo_strtod (const char *nptr, char **endptr)
}
#endif
+#ifndef HAVE_STRNDUP
+char *
+_cairo_strndup (const char *s, size_t n)
+{
+ const char *end;
+ size_t len;
+ char *sdup;
+
+ if (s == NULL)
+ return NULL;
+
+ end = memchr (s, 0, n);
+ if (end)
+ len = end - s;
+ else
+ len = n;
+
+ sdup = (char *) _cairo_malloc (len + 1);
+ if (sdup != NULL) {
+ memcpy (sdup, s, len);
+ sdup[len] = '\0';
+ }
+
+ return sdup;
+}
+#endif
+
/**
* _cairo_fopen:
* @filename: filename to open
@@ -949,15 +978,6 @@ _cairo_fopen (const char *filename, const char *mode, FILE **file_out)
#ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
-/* We require Windows 2000 features such as ETO_PDY */
-#if !defined(WINVER) || (WINVER < 0x0500)
-# define WINVER 0x0500
-#endif
-#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
-# define _WIN32_WINNT 0x0500
-#endif
-
#include <windows.h>
#include <io.h>
diff --git a/src/cairo-mutex-impl-private.h b/src/cairo-mutex-impl-private.h
index de0c9b21b..b9430beef 100644
--- a/src/cairo-mutex-impl-private.h
+++ b/src/cairo-mutex-impl-private.h
@@ -179,15 +179,6 @@
#elif defined(_WIN32) /******************************************************/
-#define WIN32_LEAN_AND_MEAN
-/* We require Windows 2000 features such as ETO_PDY */
-#if !defined(WINVER) || (WINVER < 0x0500)
-# define WINVER 0x0500
-#endif
-#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
-# define _WIN32_WINNT 0x0500
-#endif
-
# include <windows.h>
typedef CRITICAL_SECTION cairo_mutex_impl_t;
diff --git a/src/cairo-mutex-list-private.h b/src/cairo-mutex-list-private.h
index 70d566ebb..af5cc0517 100644
--- a/src/cairo-mutex-list-private.h
+++ b/src/cairo-mutex-list-private.h
@@ -64,10 +64,6 @@ CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex)
CAIRO_MUTEX_DECLARE (_cairo_xcb_connections_mutex)
#endif
-#if CAIRO_HAS_GL_SURFACE
-CAIRO_MUTEX_DECLARE (_cairo_gl_context_mutex)
-#endif
-
#if !defined (HAS_ATOMIC_OPS) || defined (ATOMIC_OP_NEEDS_MEMORY_BARRIER)
CAIRO_MUTEX_DECLARE (_cairo_atomic_mutex)
#endif
diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c
index 826c9cf8e..7305b52ca 100644
--- a/src/cairo-output-stream.c
+++ b/src/cairo-output-stream.c
@@ -259,11 +259,13 @@ void
_cairo_output_stream_write (cairo_output_stream_t *stream,
const void *data, size_t length)
{
- if (length == 0)
+ if (length == 0 || stream->status)
return;
- if (stream->status)
+ if (stream->closed) {
+ stream->status = CAIRO_STATUS_WRITE_ERROR;
return;
+ }
stream->status = stream->write_func (stream, data, length);
stream->position += length;
@@ -278,9 +280,6 @@ _cairo_output_stream_write_hex_string (cairo_output_stream_t *stream,
char buffer[2];
unsigned int i, column;
- if (stream->status)
- return;
-
for (i = 0, column = 0; i < length; i++, column++) {
if (column == 38) {
_cairo_output_stream_write (stream, "\n", 1);
@@ -407,9 +406,6 @@ _cairo_output_stream_vprintf (cairo_output_stream_t *stream,
int length_modifier, width;
cairo_bool_t var_width;
- if (stream->status)
- return;
-
f = fmt;
p = buffer;
while (*f != '\0') {
@@ -786,9 +782,6 @@ _cairo_memory_stream_copy (cairo_output_stream_t *base,
{
memory_stream_t *stream = (memory_stream_t *) base;
- if (dest->status)
- return;
-
if (base->status) {
dest->status = base->status;
return;
diff --git a/src/cairo-paginated-private.h b/src/cairo-paginated-private.h
index 89f1c99a2..cc8fd1c7b 100644
--- a/src/cairo-paginated-private.h
+++ b/src/cairo-paginated-private.h
@@ -178,7 +178,7 @@ _cairo_surface_is_paginated (cairo_surface_t *surface);
cairo_private cairo_status_t
_cairo_paginated_surface_set_size (cairo_surface_t *surface,
- int width,
- int height);
+ double width,
+ double height);
#endif /* CAIRO_PAGINATED_H */
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index a3f7cd9b2..e079a9a28 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -1,3 +1,4 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
@@ -166,8 +167,8 @@ _cairo_paginated_surface_get_recording (cairo_surface_t *surface)
cairo_status_t
_cairo_paginated_surface_set_size (cairo_surface_t *surface,
- int width,
- int height)
+ double width,
+ double height)
{
cairo_paginated_surface_t *paginated_surface;
cairo_status_t status;
@@ -401,11 +402,12 @@ _paint_page (cairo_paginated_surface_t *surface)
cairo_surface_t *analysis;
cairo_int_status_t status;
cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback;
+ unsigned int regions_id = 0;
if (unlikely (surface->target->status))
return surface->target->status;
- analysis = _cairo_analysis_surface_create (surface->target);
+ analysis = _cairo_analysis_surface_create (surface->target, TRUE);
if (unlikely (analysis->status))
return _cairo_surface_set_error (surface->target, analysis->status);
@@ -414,21 +416,26 @@ _paint_page (cairo_paginated_surface_t *surface)
if (unlikely (status))
goto FAIL;
+ status = _cairo_recording_surface_region_array_attach (surface->recording_surface, &regions_id);
+ if (status)
+ goto FAIL;
+
status = _cairo_recording_surface_replay_and_create_regions (surface->recording_surface,
+ regions_id,
NULL, analysis, FALSE);
if (status)
goto FAIL;
assert (analysis->status == CAIRO_STATUS_SUCCESS);
- if (surface->backend->set_bounding_box) {
- cairo_box_t bbox;
+ if (surface->backend->set_bounding_box) {
+ cairo_box_t bbox;
- _cairo_analysis_surface_get_bounding_box (analysis, &bbox);
- status = surface->backend->set_bounding_box (surface->target, &bbox);
- if (unlikely (status))
- goto FAIL;
- }
+ _cairo_analysis_surface_get_bounding_box (analysis, &bbox);
+ status = surface->backend->set_bounding_box (surface->target, &bbox);
+ if (unlikely (status))
+ goto FAIL;
+ }
if (surface->backend->set_fallback_images_required) {
cairo_bool_t has_fallbacks = _cairo_analysis_surface_has_unsupported (analysis);
@@ -467,6 +474,7 @@ _paint_page (cairo_paginated_surface_t *surface)
goto FAIL;
status = _cairo_recording_surface_replay_region (surface->recording_surface,
+ regions_id,
NULL,
surface->target,
CAIRO_RECORDING_REGION_NATIVE);
@@ -525,6 +533,9 @@ _paint_page (cairo_paginated_surface_t *surface)
}
FAIL:
+ if (regions_id)
+ _cairo_recording_surface_region_array_remove (surface->recording_surface, regions_id);
+
cairo_surface_destroy (analysis);
return _cairo_surface_set_error (surface->target, status);
@@ -745,6 +756,14 @@ _cairo_paginated_surface_tag (void *abstract_surface,
begin, tag_name, attributes);
}
+static cairo_bool_t
+_cairo_paginated_surface_supports_color_glyph (void *abstract_surface,
+ cairo_scaled_font_t *scaled_font,
+ unsigned long glyph_index)
+{
+ return TRUE;
+}
+
static cairo_surface_t *
_cairo_paginated_surface_snapshot (void *abstract_other)
{
@@ -800,4 +819,5 @@ static const cairo_surface_backend_t cairo_paginated_surface_backend = {
_cairo_paginated_surface_show_text_glyphs,
_cairo_paginated_surface_get_supported_mime_types,
_cairo_paginated_surface_tag,
+ _cairo_paginated_surface_supports_color_glyph,
};
diff --git a/src/cairo-path-stroke-polygon.c b/src/cairo-path-stroke-polygon.c
index 3f7c49802..44b6675e8 100644
--- a/src/cairo-path-stroke-polygon.c
+++ b/src/cairo-path-stroke-polygon.c
@@ -399,16 +399,16 @@ outer_close (struct stroker *stroker,
switch (stroker->style.line_join) {
case CAIRO_LINE_JOIN_ROUND:
- /* construct a fan around the common midpoint */
if ((in->dev_slope.x * out->dev_slope.x +
in->dev_slope.y * out->dev_slope.y) < stroker->spline_cusp_tolerance)
{
+ /* construct a fan around the common midpoint */
add_fan (stroker,
&in->dev_vector, &out->dev_vector, &in->point,
clockwise, outer);
- break;
- }
- /* else fall through */
+ } /* else: bevel join */
+ break;
+
case CAIRO_LINE_JOIN_MITER:
default: {
/* dot product of incoming slope vector with outgoing slope vector */
@@ -587,10 +587,14 @@ outer_join (struct stroker *stroker,
switch (stroker->style.line_join) {
case CAIRO_LINE_JOIN_ROUND:
- /* construct a fan around the common midpoint */
- add_fan (stroker,
- &in->dev_vector, &out->dev_vector, &in->point,
- clockwise, outer);
+ if ((in->dev_slope.x * out->dev_slope.x +
+ in->dev_slope.y * out->dev_slope.y) < stroker->spline_cusp_tolerance)
+ {
+ /* construct a fan around the common midpoint */
+ add_fan (stroker,
+ &in->dev_vector, &out->dev_vector, &in->point,
+ clockwise, outer);
+ } /* else: bevel join */
break;
case CAIRO_LINE_JOIN_MITER:
@@ -1291,17 +1295,72 @@ _cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path,
stroker.ctm_inverse = ctm_inverse;
stroker.tolerance = tolerance;
stroker.half_line_width = style->line_width / 2.;
- /* To test whether we need to join two segments of a spline using
- * a round-join or a bevel-join, we can inspect the angle between the
- * two segments. If the difference between the chord distance
- * (half-line-width times the cosine of the bisection angle) and the
- * half-line-width itself is greater than tolerance then we need to
- * inject a point.
+
+ /* If `CAIRO_LINE_JOIN_ROUND` is selected and a joint's `arc height`
+ * is greater than `tolerance` then two segments are joined with
+ * round-join, otherwise bevel-join is used.
+ *
+ * (See https://gitlab.freedesktop.org/cairo/cairo/-/merge_requests/372#note_1698225
+ * for an illustration.)
+ *
+ * `Arc height` is the distance from the center of arc's chord to
+ * the center of the arc. It is also the difference of arc's radius
+ * and the "distance from a point where segments are joined to the
+ * chord" (distance to the chord). Arc's radius is the half of a line
+ * width and the "distance to the chord" is equal to "half of a line width"
+ * times `cos(half the angle between segment vectors)`. So
+ *
+ * arc_height = w/2 - w/2 * cos(phi/2),
+ *
+ * where `w/2` is the "half of a line width".
+ *
+ * Using the double angle cosine formula we can express the `cos(phi/2)`
+ * with just `cos(phi)` which is also the dot product of segments'
+ * unit vectors.
+ *
+ * cos(phi/2) = sqrt ( (1 + cos(phi)) / 2 );
+ * cos(phi/2) is in [0; 1] range, cannot be negative;
+ *
+ * cos(phi) = a . b = (ax * bx + ay * by),
+ *
+ * where `a` and `b` are unit vectors of the segments to be joined.
+ *
+ * Since `arc height` should be greater than the `tolerance` to produce
+ * a round-join we can write
+ *
+ * w/2 * (1 - cos(phi/2)) > tolerance;
+ * 1 - tolerance / (w/2) > cos(phi/2); [!]
+ *
+ * which can be rewritten with the above double angle formula to
+ *
+ * cos(phi) < 2 * ( 1 - tolerance / (w/2) )^2 - 1,
+ *
+ * [!] Note that `w/2` is in [tolerance; +inf] range, since `cos(phi/2)`
+ * cannot be negative. The left part of the above inequality is the
+ * dot product and the right part is the `spline_cusp_tolerance`:
+ *
+ * (ax * bx + ay * by) < spline_cusp_tolerance.
+ *
+ * In the code below only the `spline_cusp_tolerance` is calculated.
+ * The dot product is calculated later, in the condition expression
+ * itself. "Half of a line width" must be scaled with CTM for tolerance
+ * condition to be properly met. Also, since `arch height` cannot exceed
+ * the "half of a line width" and since `cos(phi/2)` cannot be negative,
+ * when `tolerance` is greater than the "half of a line width" the
+ * bevel-join should be produced.
*/
- stroker.spline_cusp_tolerance = 1 - tolerance / stroker.half_line_width;
- stroker.spline_cusp_tolerance *= stroker.spline_cusp_tolerance;
- stroker.spline_cusp_tolerance *= 2;
- stroker.spline_cusp_tolerance -= 1;
+ double scaled_hlw = hypot(stroker.half_line_width * ctm->xx,
+ stroker.half_line_width * ctm->yx);
+
+ if (scaled_hlw <= tolerance) {
+ stroker.spline_cusp_tolerance = -1.0;
+ } else {
+ stroker.spline_cusp_tolerance = 1 - tolerance / scaled_hlw;
+ stroker.spline_cusp_tolerance *= stroker.spline_cusp_tolerance;
+ stroker.spline_cusp_tolerance *= 2;
+ stroker.spline_cusp_tolerance -= 1;
+ }
+
stroker.ctm_det_positive =
_cairo_matrix_compute_determinant (ctm) >= 0.0;
diff --git a/src/cairo-path-stroke-traps.c b/src/cairo-path-stroke-traps.c
index eab978235..4eabf6583 100644
--- a/src/cairo-path-stroke-traps.c
+++ b/src/cairo-path-stroke-traps.c
@@ -102,17 +102,29 @@ stroker_init (struct stroker *stroker,
stroker->tolerance = tolerance;
stroker->traps = traps;
- /* To test whether we need to join two segments of a spline using
- * a round-join or a bevel-join, we can inspect the angle between the
- * two segments. If the difference between the chord distance
- * (half-line-width times the cosine of the bisection angle) and the
- * half-line-width itself is greater than tolerance then we need to
- * inject a point.
+ /* If `CAIRO_LINE_JOIN_ROUND` is selected and a joint's `arc height`
+ * is greater than `tolerance` then two segments are joined with
+ * round-join, otherwise bevel-join is used.
+ *
+ * `Arc height` is the difference of the "half of a line width" and
+ * the "half of a line width" times `cos(half the angle between segment vectors)`.
+ *
+ * See detailed description in the `_cairo_path_fixed_stroke_to_polygon()`
+ * function in the `cairo-path-stroke-polygon.c` file or follow the
+ * https://gitlab.freedesktop.org/cairo/cairo/-/merge_requests/372#note_1698225
+ * link to see the detailed description with an illustration.
*/
- stroker->spline_cusp_tolerance = 1 - tolerance / stroker->half_line_width;
- stroker->spline_cusp_tolerance *= stroker->spline_cusp_tolerance;
- stroker->spline_cusp_tolerance *= 2;
- stroker->spline_cusp_tolerance -= 1;
+ double scaled_hlw = hypot(stroker->half_line_width * ctm->xx,
+ stroker->half_line_width * ctm->yx);
+
+ if (scaled_hlw <= tolerance) {
+ stroker->spline_cusp_tolerance = -1.0;
+ } else {
+ stroker->spline_cusp_tolerance = 1 - tolerance / scaled_hlw;
+ stroker->spline_cusp_tolerance *= stroker->spline_cusp_tolerance;
+ stroker->spline_cusp_tolerance *= 2;
+ stroker->spline_cusp_tolerance -= 1;
+ }
stroker->ctm_determinant = _cairo_matrix_compute_determinant (stroker->ctm);
stroker->ctm_det_positive = stroker->ctm_determinant >= 0.0;
diff --git a/src/cairo-pattern-private.h b/src/cairo-pattern-private.h
index f6138fb70..d061b39c4 100644
--- a/src/cairo-pattern-private.h
+++ b/src/cairo-pattern-private.h
@@ -72,7 +72,7 @@ struct _cairo_pattern {
cairo_filter_t filter;
cairo_extend_t extend;
cairo_bool_t has_component_alpha;
- cairo_bool_t is_userfont_foreground;
+ cairo_bool_t is_foreground_marker;
cairo_matrix_t matrix;
double opacity;
@@ -87,6 +87,12 @@ typedef struct _cairo_surface_pattern {
cairo_pattern_t base;
cairo_surface_t *surface;
+
+ /* This field is only used by the wrapper surface for retreiving
+ * the region id from the target during create regions and passing
+ * the region id to the target surface during playback.
+ */
+ unsigned int region_array_id;
} cairo_surface_pattern_t;
typedef struct _cairo_gradient_stop {
@@ -234,6 +240,9 @@ _cairo_pattern_fini (cairo_pattern_t *pattern);
cairo_private cairo_pattern_t *
_cairo_pattern_create_solid (const cairo_color_t *color);
+cairo_private cairo_pattern_t *
+_cairo_pattern_create_foreground_marker (void);
+
cairo_private void
_cairo_pattern_transform (cairo_pattern_t *pattern,
const cairo_matrix_t *ctm_inverse);
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 6bd3edfd8..2c0ba31f8 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -76,7 +76,7 @@ static const cairo_solid_pattern_t _cairo_pattern_nil = {
CAIRO_FILTER_DEFAULT, /* filter */
CAIRO_EXTEND_GRADIENT_DEFAULT, /* extend */
FALSE, /* has component alpha */
- FALSE, /* is_userfont_foreground */
+ FALSE, /* is_foreground_marker */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
1.0 /* opacity */
}
@@ -93,7 +93,7 @@ static const cairo_solid_pattern_t _cairo_pattern_nil_null_pointer = {
CAIRO_FILTER_DEFAULT, /* filter */
CAIRO_EXTEND_GRADIENT_DEFAULT, /* extend */
FALSE, /* has component alpha */
- FALSE, /* is_userfont_foreground */
+ FALSE, /* is_foreground_marker */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
1.0 /* opacity */
}
@@ -110,7 +110,7 @@ const cairo_solid_pattern_t _cairo_pattern_black = {
CAIRO_FILTER_NEAREST, /* filter */
CAIRO_EXTEND_REPEAT, /* extend */
FALSE, /* has component alpha */
- FALSE, /* is_userfont_foreground */
+ FALSE, /* is_foreground_marker */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
1.0 /* opacity */
},
@@ -128,7 +128,7 @@ const cairo_solid_pattern_t _cairo_pattern_clear = {
CAIRO_FILTER_NEAREST, /* filter */
CAIRO_EXTEND_REPEAT, /* extend */
FALSE, /* has component alpha */
- FALSE, /* is_userfont_foreground */
+ FALSE, /* is_foreground_marker */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
1.0 /* opacity */
},
@@ -146,7 +146,7 @@ const cairo_solid_pattern_t _cairo_pattern_white = {
CAIRO_FILTER_NEAREST, /* filter */
CAIRO_EXTEND_REPEAT, /* extend */
FALSE, /* has component alpha */
- FALSE, /* is_userfont_foreground */
+ FALSE, /* is_foreground_marker */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
1.0 /* opacity */
},
@@ -238,7 +238,7 @@ _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
pattern->opacity = 1.0;
pattern->has_component_alpha = FALSE;
- pattern->is_userfont_foreground = FALSE;
+ pattern->is_foreground_marker = FALSE;
cairo_matrix_init_identity (&pattern->matrix);
@@ -561,6 +561,7 @@ _cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern,
_cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SURFACE);
pattern->surface = cairo_surface_reference (surface);
+ pattern->region_array_id = 0;
}
static void
@@ -624,6 +625,14 @@ _cairo_pattern_create_solid (const cairo_color_t *color)
}
cairo_pattern_t *
+_cairo_pattern_create_foreground_marker (void)
+{
+ cairo_pattern_t *pattern = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK);
+ pattern->is_foreground_marker = TRUE;
+ return pattern;
+}
+
+cairo_pattern_t *
_cairo_pattern_create_in_error (cairo_status_t status)
{
cairo_pattern_t *pattern;
@@ -681,6 +690,8 @@ slim_hidden_def (cairo_pattern_create_rgb);
* 1. If the values passed in are outside that range, they will be
* clamped.
*
+ * The color is specified in the same way as in cairo_set_source_rgb().
+ *
* Return value: the newly created #cairo_pattern_t if successful, or
* an error pattern in case of no memory. The caller owns the
* returned object and should call cairo_pattern_destroy() when
@@ -810,6 +821,7 @@ cairo_pattern_create_linear (double x0, double y0, double x1, double y1)
return &pattern->base.base;
}
+slim_hidden_def (cairo_pattern_create_linear);
/**
* cairo_pattern_create_radial:
@@ -864,6 +876,7 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0,
return &pattern->base.base;
}
+slim_hidden_def (cairo_pattern_create_radial);
/* This order is specified in the diagram in the documentation for
* cairo_pattern_create_mesh() */
@@ -1044,6 +1057,7 @@ cairo_pattern_create_mesh (void)
return &pattern->base;
}
+slim_hidden_def (cairo_pattern_create_mesh);
/**
* cairo_pattern_reference:
@@ -1091,6 +1105,7 @@ cairo_pattern_get_type (cairo_pattern_t *pattern)
{
return pattern->type;
}
+slim_hidden_def (cairo_pattern_get_type);
/**
* cairo_pattern_status:
@@ -1278,7 +1293,7 @@ cairo_mesh_pattern_begin_patch (cairo_pattern_t *pattern)
for (i = 0; i < 4; i++)
mesh->has_color[i] = FALSE;
}
-
+slim_hidden_def (cairo_mesh_pattern_begin_patch);
static void
_calc_control_point (cairo_mesh_patch_t *patch, int control_point)
@@ -1395,6 +1410,7 @@ cairo_mesh_pattern_end_patch (cairo_pattern_t *pattern)
mesh->current_patch = NULL;
}
+slim_hidden_def (cairo_mesh_pattern_end_patch);
/**
* cairo_mesh_pattern_curve_to:
@@ -2115,6 +2131,7 @@ cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend)
pattern->extend = extend;
_cairo_pattern_notify_observers (pattern, CAIRO_PATTERN_NOTIFY_EXTEND);
}
+slim_hidden_def (cairo_pattern_set_extend);
/**
* cairo_pattern_get_extend:
@@ -3422,9 +3439,10 @@ use_bilinear(double x, double y, double t)
/**
* _cairo_pattern_analyze_filter:
* @pattern: surface pattern
- * Returns: the optimized #cairo_filter_t to use with @pattern.
*
* Possibly optimize the filter to a simpler value depending on transformation
+ *
+ * Returns: the optimized #cairo_filter_t to use with @pattern.
**/
cairo_filter_t
_cairo_pattern_analyze_filter (const cairo_pattern_t *pattern)
@@ -4160,6 +4178,8 @@ _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b)
*
* Gets the solid color for a solid color pattern.
*
+ * Note that the color and alpha values are not premultiplied.
+ *
* Return value: %CAIRO_STATUS_SUCCESS, or
* %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a solid
* color pattern.
@@ -4193,6 +4213,7 @@ cairo_pattern_get_rgba (cairo_pattern_t *pattern,
return CAIRO_STATUS_SUCCESS;
}
+slim_hidden_def (cairo_pattern_get_rgba);
/**
* cairo_pattern_get_surface:
@@ -4242,6 +4263,8 @@ cairo_pattern_get_surface (cairo_pattern_t *pattern,
* where n is the number returned
* by cairo_pattern_get_color_stop_count().
*
+ * Note that the color and alpha values are not premultiplied.
+ *
* Return value: %CAIRO_STATUS_SUCCESS, or %CAIRO_STATUS_INVALID_INDEX
* if @index is not valid for the given pattern. If the pattern is
* not a gradient pattern, %CAIRO_STATUS_PATTERN_TYPE_MISMATCH is
@@ -4549,6 +4572,8 @@ slim_hidden_def (cairo_mesh_pattern_get_path);
* Valid values for @corner_num are from 0 to 3 and identify the
* corners as explained in cairo_pattern_create_mesh().
*
+ * Note that the color and alpha values are not premultiplied.
+ *
* Return value: %CAIRO_STATUS_SUCCESS, or %CAIRO_STATUS_INVALID_INDEX
* if @patch_num or @corner_num is not valid for @pattern. If
* @pattern is not a mesh pattern, %CAIRO_STATUS_PATTERN_TYPE_MISMATCH
diff --git a/src/cairo-pdf-surface-private.h b/src/cairo-pdf-surface-private.h
index 87f5ffa25..c97affe6b 100644
--- a/src/cairo-pdf-surface-private.h
+++ b/src/cairo-pdf-surface-private.h
@@ -95,6 +95,7 @@ typedef struct _cairo_pdf_source_surface_entry {
typedef struct _cairo_pdf_source_surface {
cairo_pattern_type_t type;
cairo_surface_t *surface;
+ unsigned int region_id;
cairo_pattern_t *raster_pattern;
cairo_pdf_source_surface_entry_t *hash_entry;
} cairo_pdf_source_surface_t;
@@ -257,6 +258,13 @@ typedef struct _cairo_pdf_interchange {
} cairo_pdf_interchange_t;
+typedef struct _cairo_pdf_color_glyph {
+ cairo_hash_entry_t base;
+ cairo_scaled_font_t *scaled_font;
+ unsigned long glyph_index;
+ cairo_bool_t supported;
+} cairo_pdf_color_glyph_t;
+
/* pdf surface data */
typedef struct _cairo_pdf_surface cairo_pdf_surface_t;
@@ -279,14 +287,15 @@ struct _cairo_pdf_surface {
cairo_array_t pages;
cairo_array_t rgb_linear_functions;
cairo_array_t alpha_linear_functions;
- cairo_array_t page_patterns;
- cairo_array_t page_surfaces;
- cairo_array_t doc_surfaces;
+ cairo_array_t page_patterns; /* cairo_pdf_pattern_t */
+ cairo_array_t page_surfaces; /* cairo_pdf_source_surface_t */
+ cairo_array_t doc_surfaces; /* cairo_pdf_source_surface_t */
cairo_hash_table_t *all_surfaces;
cairo_array_t smask_groups;
cairo_array_t knockout_group;
cairo_array_t jbig2_global;
cairo_array_t page_heights;
+ cairo_hash_table_t *color_glyphs;
cairo_scaled_font_subsets_t *font_subsets;
cairo_array_t fonts;
@@ -334,11 +343,13 @@ struct _cairo_pdf_surface {
cairo_pdf_operators_t pdf_operators;
cairo_paginated_mode_t paginated_mode;
+ cairo_bool_t type3_replay;
cairo_bool_t select_pattern_gstate_saved;
cairo_bool_t force_fallbacks;
cairo_operator_t current_operator;
+ cairo_bool_t reset_gs_required;
cairo_bool_t current_pattern_is_solid_color;
cairo_bool_t current_color_is_stroke;
double current_color_red;
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 9b2b93252..2b1bf72e4 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -54,6 +54,7 @@
#include "cairo-error-private.h"
#include "cairo-image-surface-inline.h"
#include "cairo-image-info-private.h"
+#include "cairo-recording-surface-inline.h"
#include "cairo-recording-surface-private.h"
#include "cairo-output-stream-private.h"
#include "cairo-paginated-private.h"
@@ -132,10 +133,10 @@
* The PDF surface is used to render cairo graphics to Adobe
* PDF files and is a multi-page vector surface backend.
*
- * The following mime types are supported: %CAIRO_MIME_TYPE_JPEG,
- * %CAIRO_MIME_TYPE_JP2, %CAIRO_MIME_TYPE_UNIQUE_ID,
- * %CAIRO_MIME_TYPE_JBIG2, %CAIRO_MIME_TYPE_JBIG2_GLOBAL,
- * %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID,
+ * The following mime types are supported on source patterns:
+ * %CAIRO_MIME_TYPE_JPEG, %CAIRO_MIME_TYPE_JP2,
+ * %CAIRO_MIME_TYPE_UNIQUE_ID, %CAIRO_MIME_TYPE_JBIG2,
+ * %CAIRO_MIME_TYPE_JBIG2_GLOBAL, %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID,
* %CAIRO_MIME_TYPE_CCITT_FAX, %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS.
*
* # JBIG2 Images #
@@ -279,7 +280,8 @@ typedef struct _cairo_pdf_alpha_linear_function {
} cairo_pdf_alpha_linear_function_t;
static void
-_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface);
+_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface,
+ cairo_bool_t clear_doc_surfaces);
static void
_cairo_pdf_smask_group_destroy (cairo_pdf_smask_group_t *group);
@@ -337,6 +339,9 @@ _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface);
static cairo_bool_t
_cairo_pdf_source_surface_equal (const void *key_a, const void *key_b);
+static cairo_bool_t
+_cairo_pdf_color_glyph_equal (const void *key_a, const void *key_b);
+
static const cairo_surface_backend_t cairo_pdf_surface_backend;
static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend;
@@ -484,12 +489,18 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
goto BAIL0;
}
+ surface->color_glyphs = _cairo_hash_table_create (_cairo_pdf_color_glyph_equal);
+ if (unlikely (surface->color_glyphs == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto BAIL1;
+ }
+
_cairo_pdf_group_resources_init (&surface->resources);
surface->font_subsets = _cairo_scaled_font_subsets_create_composite ();
if (! surface->font_subsets) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL1;
+ goto BAIL2;
}
_cairo_scaled_font_subsets_enable_latin_subset (surface->font_subsets, TRUE);
@@ -498,7 +509,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
surface->pages_resource = _cairo_pdf_surface_new_object (surface);
if (surface->pages_resource.id == 0) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto BAIL2;
+ goto BAIL3;
}
surface->struct_tree_root.id = 0;
@@ -514,11 +525,13 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
_cairo_array_init (&surface->object_stream.objects, sizeof (cairo_xref_stream_object_t));
surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
+ surface->type3_replay = FALSE;
surface->force_fallbacks = FALSE;
surface->select_pattern_gstate_saved = FALSE;
surface->current_pattern_is_solid_color = FALSE;
surface->current_operator = CAIRO_OPERATOR_OVER;
+ surface->reset_gs_required = FALSE;
surface->header_emitted = FALSE;
_cairo_surface_clipper_init (&surface->clipper,
@@ -536,7 +549,7 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
status = _cairo_pdf_interchange_init (surface);
if (unlikely (status))
- goto BAIL2;
+ goto BAIL3;
surface->page_parent_tree = -1;
_cairo_array_init (&surface->page_annots, sizeof (cairo_pdf_resource_t));
@@ -567,8 +580,10 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output,
return surface->paginated_surface;
}
-BAIL2:
+BAIL3:
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
+BAIL2:
+ _cairo_hash_table_destroy (surface->color_glyphs);
BAIL1:
_cairo_hash_table_destroy (surface->all_surfaces);
BAIL0:
@@ -779,7 +794,7 @@ cairo_pdf_get_versions (cairo_pdf_version_t const **versions,
const char *
cairo_pdf_version_to_string (cairo_pdf_version_t version)
{
- if (version >= CAIRO_PDF_VERSION_LAST)
+ if (version < 0 || version >= CAIRO_PDF_VERSION_LAST)
return NULL;
return _cairo_pdf_version_strings[version];
@@ -997,12 +1012,14 @@ cairo_pdf_surface_set_thumbnail_size (cairo_surface_t *surface,
}
static void
-_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
+_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface,
+ cairo_bool_t clear_doc_surfaces)
{
int i, size;
cairo_pdf_pattern_t *pattern;
cairo_pdf_source_surface_t *src_surface;
cairo_pdf_smask_group_t *group;
+ cairo_pdf_source_surface_t doc_surface;
size = _cairo_array_num_elements (&surface->page_patterns);
for (i = 0; i < size; i++) {
@@ -1014,7 +1031,13 @@ _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
size = _cairo_array_num_elements (&surface->page_surfaces);
for (i = 0; i < size; i++) {
src_surface = (cairo_pdf_source_surface_t *) _cairo_array_index (&surface->page_surfaces, i);
- cairo_surface_destroy (src_surface->surface);
+ if (src_surface->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
+ cairo_pattern_destroy (src_surface->raster_pattern);
+ } else {
+ if (_cairo_surface_is_recording (src_surface->surface) && src_surface->region_id != 0)
+ _cairo_recording_surface_region_array_remove (src_surface->surface, src_surface->region_id);
+ cairo_surface_destroy (src_surface->surface);
+ }
}
_cairo_array_truncate (&surface->page_surfaces, 0);
@@ -1030,6 +1053,21 @@ _cairo_pdf_surface_clear (cairo_pdf_surface_t *surface)
if (surface->thumbnail_image)
cairo_surface_destroy (&surface->thumbnail_image->base);
surface->thumbnail_image = NULL;
+
+ if (clear_doc_surfaces) {
+ size = _cairo_array_num_elements (&surface->doc_surfaces);
+ for (i = 0; i < size; i++) {
+ _cairo_array_copy_element (&surface->doc_surfaces, i, &doc_surface);
+ if (doc_surface.type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
+ cairo_pattern_destroy (doc_surface.raster_pattern);
+ } else {
+ if (_cairo_surface_is_recording (doc_surface.surface) && doc_surface.region_id != 0)
+ _cairo_recording_surface_region_array_remove (doc_surface.surface, doc_surface.region_id);
+ cairo_surface_destroy (doc_surface.surface);
+ }
+ }
+ _cairo_array_truncate (&surface->doc_surfaces, 0);
+ }
}
static void
@@ -1436,6 +1474,25 @@ _cairo_pdf_source_surface_init_key (cairo_pdf_source_surface_entry_t *key)
}
}
+static cairo_bool_t
+_cairo_pdf_color_glyph_equal (const void *key_a, const void *key_b)
+{
+ const cairo_pdf_color_glyph_t *a = key_a;
+ const cairo_pdf_color_glyph_t *b = key_b;
+
+ if (a->scaled_font != b->scaled_font)
+ return FALSE;
+
+ return (a->glyph_index == b->glyph_index);
+}
+
+static void
+_cairo_pdf_color_glyph_init_key (cairo_pdf_color_glyph_t *key)
+{
+ key->base.hash = _cairo_hash_uintptr (_CAIRO_HASH_INIT_VALUE, (uintptr_t)key->scaled_font);
+ key->base.hash = _cairo_hash_uintptr (key->base.hash, key->glyph_index);
+}
+
static cairo_int_status_t
_cairo_pdf_surface_acquire_source_image_from_pattern (cairo_pdf_surface_t *surface,
const cairo_pattern_t *pattern,
@@ -1723,6 +1780,7 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
_cairo_pdf_source_surface_init_key (surface_entry);
src_surface.hash_entry = surface_entry;
+ src_surface.region_id = 0;
if (source_pattern && source_pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) {
src_surface.type = CAIRO_PATTERN_TYPE_RASTER_SOURCE;
src_surface.surface = NULL;
@@ -1734,6 +1792,16 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
src_surface.type = CAIRO_PATTERN_TYPE_SURFACE;
src_surface.surface = cairo_surface_reference (source_surface);
src_surface.raster_pattern = NULL;
+ if (source_pattern) {
+ cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source_pattern;
+ src_surface.region_id = surface_pattern->region_array_id;
+ if (_cairo_surface_is_recording (surface_pattern->surface) &&
+ surface_pattern->region_array_id != 0)
+ {
+ _cairo_recording_surface_region_array_reference (surface_pattern->surface,
+ surface_pattern->region_array_id);
+ }
+ }
}
surface_entry->surface_res = _cairo_pdf_surface_new_object (surface);
@@ -2113,7 +2181,7 @@ _cairo_pdf_surface_open_group (cairo_pdf_surface_t *surface,
surface->group_stream.bbox = *bbox;
/* Reset gstate */
- _cairo_output_stream_printf (surface->output, "/gs0 gs\n");
+ surface->reset_gs_required = TRUE;
surface->current_pattern_is_solid_color = FALSE;
surface->current_operator = CAIRO_OPERATOR_OVER;
_cairo_pdf_operators_reset (&surface->pdf_operators);
@@ -2470,15 +2538,26 @@ _cairo_pdf_source_surface_entry_pluck (void *entry, void *closure)
free (surface_entry);
}
+static void
+_cairo_pdf_color_glyph_pluck (void *entry, void *closure)
+{
+ cairo_pdf_color_glyph_t *glyph_entry = entry;
+ cairo_hash_table_t *patterns = closure;
+
+ _cairo_hash_table_remove (patterns, &glyph_entry->base);
+ cairo_scaled_font_destroy (glyph_entry->scaled_font);
+
+ free (glyph_entry);
+}
+
static cairo_status_t
_cairo_pdf_surface_finish (void *abstract_surface)
{
cairo_pdf_surface_t *surface = abstract_surface;
long long offset;
cairo_pdf_resource_t catalog;
- cairo_status_t status, status2;
+ cairo_status_t status = CAIRO_STATUS_SUCCESS, status2;
int size, i;
- cairo_pdf_source_surface_t doc_surface;
cairo_pdf_jbig2_global_t *global;
char *label;
cairo_pdf_resource_t xref_res;
@@ -2487,7 +2566,7 @@ _cairo_pdf_surface_finish (void *abstract_surface)
if (surface->base.status != CAIRO_STATUS_SUCCESS)
goto CLEANUP;
- _cairo_pdf_surface_clear (surface);
+ _cairo_pdf_surface_clear (surface, FALSE);
status = _cairo_pdf_surface_open_object_stream (surface);
if (unlikely (status))
@@ -2496,10 +2575,17 @@ _cairo_pdf_surface_finish (void *abstract_surface)
/* Emit unbounded surfaces */
_cairo_pdf_surface_write_patterns_and_smask_groups (surface, TRUE);
+ _cairo_pdf_surface_clear (surface, TRUE);
+
status = surface->base.status;
if (status == CAIRO_STATUS_SUCCESS)
status = _cairo_pdf_surface_emit_font_subsets (surface);
+ /* Emit any new patterns or surfaces created by the Type 3 font subset. */
+ _cairo_pdf_surface_write_patterns_and_smask_groups (surface, TRUE);
+
+ _cairo_pdf_surface_clear (surface, TRUE);
+
status = _cairo_pdf_surface_write_pages (surface);
if (unlikely (status))
return status;
@@ -2590,11 +2676,6 @@ _cairo_pdf_surface_finish (void *abstract_surface)
_cairo_array_fini (&surface->page_surfaces);
_cairo_array_fini (&surface->object_stream.objects);
- size = _cairo_array_num_elements (&surface->doc_surfaces);
- for (i = 0; i < size; i++) {
- _cairo_array_copy_element (&surface->doc_surfaces, i, &doc_surface);
- cairo_surface_destroy (doc_surface.surface);
- }
_cairo_array_fini (&surface->doc_surfaces);
_cairo_hash_table_foreach (surface->all_surfaces,
_cairo_pdf_source_surface_entry_pluck,
@@ -2606,6 +2687,11 @@ _cairo_pdf_surface_finish (void *abstract_surface)
_cairo_array_fini (&surface->page_annots);
_cairo_array_fini (&surface->forward_links);
+ _cairo_hash_table_foreach (surface->color_glyphs,
+ _cairo_pdf_color_glyph_pluck,
+ surface->color_glyphs);
+ _cairo_hash_table_destroy (surface->color_glyphs);
+
if (surface->font_subsets) {
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
surface->font_subsets = NULL;
@@ -3535,9 +3621,10 @@ _cairo_pdf_surface_emit_ccitt_image (cairo_pdf_surface_t *surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
/* ensure params_string is null terminated */
- params = malloc (ccitt_params_string_len + 1);
- memcpy (params, ccitt_params_string, ccitt_params_string_len);
- params[ccitt_params_string_len] = 0;
+ params = _cairo_strndup ((const char *)ccitt_params_string, ccitt_params_string_len);
+ if (unlikely (params == NULL))
+ return _cairo_surface_set_error (&surface->base, CAIRO_STATUS_NO_MEMORY);
+
status = _cairo_tag_parse_ccitt_params (params, &ccitt_params);
if (unlikely(status))
return source->status;
@@ -3702,7 +3789,7 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface,
goto err;
/* Reset gstate */
- _cairo_output_stream_printf (surface->output, "/gs0 gs\n");
+ surface->reset_gs_required = TRUE;
if (source->content == CAIRO_CONTENT_COLOR) {
status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha);
@@ -3719,6 +3806,7 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface,
}
status = _cairo_recording_surface_replay_region (source,
+ pdf_source->region_id,
is_subsurface ? extents : NULL,
&surface->base,
CAIRO_RECORDING_REGION_NATIVE);
@@ -5054,6 +5142,7 @@ _cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface,
alpha != 1.0, /* need_transp_group */
extents,
smask_res,
+
&pdf_source,
&x_offset,
&y_offset,
@@ -5241,6 +5330,11 @@ _cairo_pdf_surface_select_operator (cairo_pdf_surface_t *surface,
{
cairo_int_status_t status;
+ if (surface->reset_gs_required) {
+ _cairo_output_stream_printf (surface->output, "/gs0 gs\n");
+ surface->reset_gs_required = FALSE;
+ }
+
if (op == surface->current_operator)
return CAIRO_STATUS_SUCCESS;
@@ -5404,7 +5498,7 @@ _cairo_pdf_surface_show_page (void *abstract_surface)
if (unlikely (status))
return status;
- _cairo_pdf_surface_clear (surface);
+ _cairo_pdf_surface_clear (surface, FALSE);
return CAIRO_STATUS_SUCCESS;
}
@@ -6454,42 +6548,203 @@ _cairo_pdf_emit_imagemask (cairo_image_surface_t *image,
}
static cairo_int_status_t
-_cairo_pdf_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_subset,
- void *closure)
-{
- cairo_pdf_surface_t *surface = closure;
- cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
- cairo_int_status_t status2;
- unsigned int i;
- cairo_surface_t *type3_surface;
- cairo_output_stream_t *null_stream;
+cairo_pdf_surface_emit_color_glyph (cairo_pdf_surface_t *surface,
+ cairo_scaled_font_t *scaled_font,
+ unsigned long glyph_index,
+ cairo_box_t *bbox,
+ double *width)
+{
+ cairo_rectangle_int_t extents;
+ cairo_scaled_glyph_t *scaled_glyph;
+ cairo_matrix_t mat;
+ cairo_int_status_t status;
+ double x_advance, y_advance;
+ cairo_matrix_t font_matrix_inverse;
+ cairo_surface_t *analysis;
+ cairo_rectangle_int_t old_surface_extents;
+ cairo_bool_t old_surface_bounded;
+ cairo_paginated_mode_t old_paginated_mode;
+ cairo_surface_t *glyph_surface = NULL;
+ unsigned int regions_id = 0;
+ cairo_surface_pattern_t surface_pattern;
+
+ _cairo_scaled_font_freeze_cache (scaled_font);
+ status = _cairo_scaled_glyph_lookup (scaled_font,
+ glyph_index,
+ CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE,
+ NULL, /* foreground color */
+ &scaled_glyph);
+ if (status == CAIRO_INT_STATUS_SUCCESS)
+ glyph_surface = cairo_surface_reference (scaled_glyph->recording_surface);
- null_stream = _cairo_null_stream_create ();
- type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
- null_stream,
- _cairo_pdf_emit_imagemask,
- surface->font_subsets,
- FALSE);
- if (unlikely (type3_surface->status)) {
- status2 = _cairo_output_stream_destroy (null_stream);
- return type3_surface->status;
+ _cairo_scaled_font_thaw_cache (scaled_font);
+ if (unlikely (status))
+ return status;
+
+ analysis = _cairo_analysis_surface_create (&surface->base, TRUE);
+ if (unlikely (analysis->status)) {
+ status = _cairo_surface_set_error (&surface->base, analysis->status);
+ goto cleanup;
}
- _cairo_type3_glyph_surface_set_font_subsets_callback (type3_surface,
- _cairo_pdf_surface_add_font,
- surface);
+ extents.x = _cairo_fixed_to_double (scaled_glyph->bbox.p1.x);
+ extents.y = _cairo_fixed_to_double (scaled_glyph->bbox.p1.y);
+ extents.width = _cairo_fixed_to_double (scaled_glyph->bbox.p2.x) - extents.x;
+ extents.height = _cairo_fixed_to_double (scaled_glyph->bbox.p2.y) - extents.y;
- for (i = 0; i < font_subset->num_glyphs; i++) {
- status = _cairo_type3_glyph_surface_analyze_glyph (type3_surface,
- font_subset->glyphs[i]);
- if (unlikely (status))
- break;
+ old_surface_extents = surface->surface_extents;
+ old_surface_bounded = surface->surface_bounded;
+ old_paginated_mode = surface->paginated_mode;
+ surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
+ surface->type3_replay = TRUE;
+ surface->surface_extents = extents;
+ surface->surface_bounded = TRUE;
+
+ status = _cairo_recording_surface_region_array_attach (glyph_surface, &regions_id);
+ if (status)
+ goto cleanup;
+
+ status = _cairo_recording_surface_replay_and_create_regions (glyph_surface, regions_id,
+ NULL, analysis, TRUE);
+ if (status)
+ goto cleanup;
+
+ surface->surface_extents = old_surface_extents;
+ surface->surface_bounded = old_surface_bounded;
+ surface->paginated_mode = old_paginated_mode;
+ surface->type3_replay = FALSE;
+
+ if (status == CAIRO_INT_STATUS_SUCCESS &&
+ _cairo_analysis_surface_has_unsupported (analysis))
+ {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
}
- cairo_surface_destroy (type3_surface);
- status2 = _cairo_output_stream_destroy (null_stream);
- if (status == CAIRO_INT_STATUS_SUCCESS)
- status = status2;
+ cairo_surface_destroy (analysis);
+ if (status)
+ goto cleanup;
+
+ _cairo_pattern_init_for_surface (&surface_pattern, glyph_surface);
+ surface_pattern.region_array_id = regions_id;
+
+ cairo_matrix_init_identity (&mat);
+ cairo_matrix_multiply (&mat, &mat, &scaled_font->scale_inverse);
+
+ /* transform glyph extents to operation space */
+ cairo_box_t box;
+ _cairo_box_from_rectangle (&box, &extents);
+ _cairo_matrix_transform_bounding_box_fixed (&mat, &box, NULL);
+ _cairo_box_round_to_rectangle (&box, &extents);
+
+ status = cairo_matrix_invert (&mat);
+ if (status) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
+ }
+
+ cairo_pattern_set_matrix (&surface_pattern.base, &mat);
+
+ x_advance = scaled_glyph->metrics.x_advance;
+ y_advance = scaled_glyph->metrics.y_advance;
+ font_matrix_inverse = scaled_font->font_matrix;
+ status = cairo_matrix_invert (&font_matrix_inverse);
+ if (status) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto cleanup;
+ }
+
+ cairo_matrix_transform_distance (&font_matrix_inverse, &x_advance, &y_advance);
+ *width = x_advance;
+
+ *bbox = scaled_glyph->bbox;
+ _cairo_matrix_transform_bounding_box_fixed (&scaled_font->scale_inverse,
+ bbox, NULL);
+
+ _cairo_output_stream_printf (surface->output,
+ "%f 0 d0\n",
+ x_advance);
+
+ _cairo_pdf_surface_paint_surface_pattern (surface,
+ CAIRO_OPERATOR_OVER,
+ &surface_pattern.base,
+ &extents,
+ 1.0, /* alpha */
+ NULL, /* smask_res */
+ FALSE); /* mask */
+
+ cleanup:
+ cairo_surface_destroy (glyph_surface);
+
+ return status;
+}
+
+static cairo_int_status_t
+cairo_pdf_surface_emit_color_glyph_image (cairo_pdf_surface_t *surface,
+ cairo_scaled_font_t *scaled_font,
+ unsigned long glyph_index,
+ cairo_box_t *bbox,
+ double *width)
+{
+ cairo_rectangle_int_t extents;
+ cairo_pattern_t *image_pattern;
+ cairo_scaled_glyph_t *scaled_glyph;
+ cairo_matrix_t mat;
+ cairo_int_status_t status, status2;
+ double x_advance, y_advance;
+ cairo_matrix_t font_matrix_inverse;
+
+ _cairo_scaled_font_freeze_cache (scaled_font);
+ status = _cairo_scaled_glyph_lookup (scaled_font,
+ glyph_index,
+ CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE,
+ NULL, /* foreground color */
+ &scaled_glyph);
+ if (unlikely (status))
+ goto FAIL;
+
+ extents.x = _cairo_fixed_to_double (scaled_glyph->bbox.p1.x);
+ extents.y = _cairo_fixed_to_double (scaled_glyph->bbox.p1.y);
+ extents.width = _cairo_fixed_to_double (scaled_glyph->bbox.p2.x) - extents.x;
+ extents.height = _cairo_fixed_to_double (scaled_glyph->bbox.p2.y) - extents.y;
+
+ image_pattern = cairo_pattern_create_for_surface (&scaled_glyph->color_surface->base);
+
+ cairo_matrix_init_translate (&mat, extents.x, extents.y);
+ cairo_matrix_multiply (&mat, &mat, &scaled_font->scale_inverse);
+ status2 = cairo_matrix_invert (&mat);
+ cairo_pattern_set_matrix (image_pattern, &mat);
+
+ x_advance = scaled_glyph->metrics.x_advance;
+ y_advance = scaled_glyph->metrics.y_advance;
+ font_matrix_inverse = scaled_font->font_matrix;
+ status2 = cairo_matrix_invert (&font_matrix_inverse);
+
+ /* The invertability of font_matrix is tested in
+ * pdf_operators_show_glyphs before any glyphs are mapped to the
+ * subset. */
+ assert (status2 == CAIRO_INT_STATUS_SUCCESS);
+
+ cairo_matrix_transform_distance (&font_matrix_inverse, &x_advance, &y_advance);
+ *width = x_advance;
+
+ *bbox = scaled_glyph->bbox;
+ _cairo_matrix_transform_bounding_box_fixed (&scaled_font->scale_inverse,
+ bbox, NULL);
+
+ _cairo_output_stream_printf (surface->output,
+ "%f 0 d0\n",
+ x_advance);
+
+ _cairo_pdf_surface_paint_surface_pattern (surface,
+ CAIRO_OPERATOR_OVER,
+ image_pattern,
+ &extents,
+ 1.0, /* alpha */
+ NULL, /* smask_res */
+ FALSE); /* mask */
+ cairo_pattern_destroy (image_pattern);
+ FAIL:
+ _cairo_scaled_font_thaw_cache (scaled_font);
return status;
}
@@ -6556,6 +6811,20 @@ _cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface,
font_subset->glyphs[i],
&bbox,
&widths[i]);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ status = cairo_pdf_surface_emit_color_glyph (surface,
+ font_subset->scaled_font,
+ font_subset->glyphs[i],
+ &bbox,
+ &widths[i]);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ status = cairo_pdf_surface_emit_color_glyph_image (surface,
+ font_subset->scaled_font,
+ font_subset->glyphs[i],
+ &bbox,
+ &widths[i]);
+ }
+ }
if (unlikely (status))
break;
@@ -6731,12 +7000,6 @@ _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface)
{
cairo_int_status_t status;
- status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
- _cairo_pdf_surface_analyze_user_font_subset,
- surface);
- if (unlikely (status))
- goto BAIL;
-
status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets,
_cairo_pdf_surface_emit_unscaled_font_subset,
surface);
@@ -6746,12 +7009,6 @@ _cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface)
status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
_cairo_pdf_surface_emit_scaled_font_subset,
surface);
- if (unlikely (status))
- goto BAIL;
-
- status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
- _cairo_pdf_surface_emit_scaled_font_subset,
- surface);
BAIL:
_cairo_scaled_font_subsets_destroy (surface->font_subsets);
@@ -7630,7 +7887,7 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface,
if (_cairo_surface_get_extents (surface_pattern->surface, &rec_extents)) {
if (_cairo_fixed_integer_ceil(box.p1.x) < rec_extents.x ||
_cairo_fixed_integer_ceil(box.p1.y) < rec_extents.y ||
- _cairo_fixed_integer_floor(box.p2.y) > rec_extents.x + rec_extents.width ||
+ _cairo_fixed_integer_floor(box.p2.x) > rec_extents.x + rec_extents.width ||
_cairo_fixed_integer_floor(box.p2.y) > rec_extents.y + rec_extents.height)
{
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -7648,6 +7905,9 @@ _cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface,
/* The SOURCE operator is supported if the pattern is opaque or if
* there is nothing painted underneath. */
if (op == CAIRO_OPERATOR_SOURCE) {
+ if (surface->type3_replay)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
@@ -8783,6 +9043,13 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
return status;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
+ /* Enabling text in Type 3 fonts currently crashes cairo. Most
+ * PDF viewers don't seem to suport text in Type 3 so we let
+ * this go to image fallback.
+ */
+ if (surface->type3_replay)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded);
goto cleanup;
}
@@ -8936,6 +9203,68 @@ _cairo_pdf_surface_tag (void *abstract_surface,
return status;
}
+/* The Type 3 font subset support will the embed the
+ * CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE image if vector operations
+ * are not supported. The only case we don't currently handle is if a
+ * foreground color is used.
+ */
+static cairo_bool_t
+_cairo_pdf_surface_supports_color_glyph (void *abstract_surface,
+ cairo_scaled_font_t *scaled_font,
+ unsigned long glyph_index)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+ cairo_pdf_color_glyph_t glyph_key;
+ cairo_pdf_color_glyph_t *glyph_entry;
+ cairo_scaled_glyph_t *scaled_glyph;
+ cairo_status_t status;
+
+ glyph_key.scaled_font = scaled_font;
+ glyph_key.glyph_index = glyph_index;
+
+ _cairo_pdf_color_glyph_init_key (&glyph_key);
+ glyph_entry = _cairo_hash_table_lookup (surface->color_glyphs, &glyph_key.base);
+ if (glyph_entry)
+ return glyph_entry->supported;
+
+ glyph_entry = _cairo_malloc (sizeof (cairo_pdf_color_glyph_t));
+ if (glyph_entry == NULL) {
+ status = _cairo_surface_set_error (&surface->base,
+ _cairo_error (CAIRO_STATUS_NO_MEMORY));
+ return FALSE;
+ }
+
+ glyph_entry->scaled_font = cairo_scaled_font_reference (scaled_font);
+ glyph_entry->glyph_index = glyph_index;
+ _cairo_pdf_color_glyph_init_key (glyph_entry);
+
+ glyph_entry->supported = FALSE;
+ _cairo_scaled_font_freeze_cache (scaled_font);
+ status = _cairo_scaled_glyph_lookup (scaled_font,
+ glyph_index,
+ CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE,
+ NULL, /* foreground color */
+ &scaled_glyph);
+ if (unlikely (status))
+ goto done;
+
+ glyph_entry->supported = !(scaled_glyph->recording_uses_foreground_color ||
+ scaled_glyph->recording_uses_foreground_marker);
+
+ done:
+ _cairo_scaled_font_thaw_cache (scaled_font);
+
+ status = _cairo_hash_table_insert (surface->color_glyphs,
+ &glyph_entry->base);
+ if (unlikely(status)) {
+ status = _cairo_surface_set_error (&surface->base,
+ _cairo_error (CAIRO_STATUS_NO_MEMORY));
+ return FALSE;
+ }
+
+ return glyph_entry->supported;
+}
+
static cairo_int_status_t
_cairo_pdf_surface_set_paginated_mode (void *abstract_surface,
cairo_paginated_mode_t paginated_mode)
@@ -8994,6 +9323,7 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
_cairo_pdf_surface_show_text_glyphs,
_cairo_pdf_surface_get_supported_mime_types,
_cairo_pdf_surface_tag,
+ _cairo_pdf_surface_supports_color_glyph,
};
static const cairo_paginated_surface_backend_t
diff --git a/src/cairo-png.c b/src/cairo-png.c
index 4b7c34081..5b9c58447 100644
--- a/src/cairo-png.c
+++ b/src/cairo-png.c
@@ -987,3 +987,4 @@ cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func,
return read_png (&png_closure);
}
+slim_hidden_def (cairo_image_surface_create_from_png_stream);
diff --git a/src/cairo-ps-surface-private.h b/src/cairo-ps-surface-private.h
index f18403190..e825b57fd 100644
--- a/src/cairo-ps-surface-private.h
+++ b/src/cairo-ps-surface-private.h
@@ -56,6 +56,7 @@ typedef struct _cairo_ps_form {
cairo_bool_t is_image;
int id;
cairo_surface_t *src_surface;
+ unsigned int regions_id;
cairo_rectangle_int_t src_surface_extents;
cairo_bool_t src_surface_bounded;
cairo_filter_t filter;
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 5645aae4a..381b4cf75 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -66,18 +66,19 @@
#include "cairo-composite-rectangles-private.h"
#include "cairo-default-context-private.h"
#include "cairo-error-private.h"
+#include "cairo-image-info-private.h"
#include "cairo-image-surface-inline.h"
#include "cairo-list-inline.h"
-#include "cairo-scaled-font-subsets-private.h"
+#include "cairo-output-stream-private.h"
#include "cairo-paginated-private.h"
+#include "cairo-recording-surface-inline.h"
#include "cairo-recording-surface-private.h"
+#include "cairo-scaled-font-subsets-private.h"
#include "cairo-surface-clipper-private.h"
#include "cairo-surface-snapshot-inline.h"
#include "cairo-surface-subsurface-private.h"
-#include "cairo-output-stream-private.h"
-#include "cairo-type3-glyph-surface-private.h"
-#include "cairo-image-info-private.h"
#include "cairo-tag-attributes-private.h"
+#include "cairo-type3-glyph-surface-private.h"
#include <stdio.h>
#include <ctype.h>
@@ -118,9 +119,8 @@ static char *ctime_r(const time_t *timep, char *buf)
* The PostScript surface is used to render cairo graphics to Adobe
* PostScript files and is a multi-page vector surface backend.
*
- * The following mime types are supported: %CAIRO_MIME_TYPE_JPEG,
- * %CAIRO_MIME_TYPE_UNIQUE_ID,
- * %CAIRO_MIME_TYPE_CCITT_FAX, %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS,
+ * The following mime types are supported on source patterns:
+ * %CAIRO_MIME_TYPE_JPEG, %CAIRO_MIME_TYPE_UNIQUE_ID,
* %CAIRO_MIME_TYPE_CCITT_FAX, %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS,
* %CAIRO_MIME_TYPE_EPS, %CAIRO_MIME_TYPE_EPS_PARAMS.
*
@@ -148,7 +148,7 @@ static char *ctime_r(const time_t *timep, char *buf)
* ury]" that specifies the bounding box (in PS coordinates) of the
* EPS graphics. The parameters are: lower left x, lower left y, upper
* right x, upper right y. Normally the bbox data is identical to the
- * %%%BoundingBox data in the EPS file.
+ * \%\%\%BoundingBox data in the EPS file.
*
**/
@@ -176,6 +176,7 @@ typedef enum {
typedef struct {
/* input params */
cairo_surface_t *src_surface;
+ unsigned int regions_id;
cairo_operator_t op;
const cairo_rectangle_int_t *src_surface_extents;
cairo_bool_t src_surface_bounded;
@@ -217,8 +218,11 @@ static const char * _cairo_ps_level_strings[CAIRO_PS_LEVEL_LAST] =
static const char *_cairo_ps_supported_mime_types[] =
{
CAIRO_MIME_TYPE_JPEG,
+ CAIRO_MIME_TYPE_UNIQUE_ID,
CAIRO_MIME_TYPE_CCITT_FAX,
CAIRO_MIME_TYPE_CCITT_FAX_PARAMS,
+ CAIRO_MIME_TYPE_EPS,
+ CAIRO_MIME_TYPE_EPS_PARAMS,
NULL
};
@@ -286,6 +290,8 @@ _cairo_ps_form_pluck (void *entry, void *closure)
_cairo_hash_table_remove (patterns, &surface_entry->base);
free (surface_entry->unique_id);
+ if (_cairo_surface_is_recording (surface_entry->src_surface) && surface_entry->regions_id != 0)
+ _cairo_recording_surface_region_array_remove (surface_entry->src_surface, surface_entry->regions_id);
cairo_surface_destroy (surface_entry->src_surface);
free (surface_entry);
}
@@ -734,34 +740,6 @@ _cairo_ps_emit_imagemask (cairo_image_surface_t *image,
return _cairo_output_stream_get_status (stream);
}
-static cairo_int_status_t
-_cairo_ps_surface_analyze_user_font_subset (cairo_scaled_font_subset_t *font_subset,
- void *closure)
-{
- cairo_ps_surface_t *surface = closure;
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
- unsigned int i;
- cairo_surface_t *type3_surface;
-
- type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font,
- NULL,
- _cairo_ps_emit_imagemask,
- surface->font_subsets,
- TRUE);
-
- for (i = 0; i < font_subset->num_glyphs; i++) {
- status = _cairo_type3_glyph_surface_analyze_glyph (type3_surface,
- font_subset->glyphs[i]);
- if (unlikely (status))
- break;
-
- }
- cairo_surface_finish (type3_surface);
- cairo_surface_destroy (type3_surface);
-
- return status;
-}
-
static cairo_status_t
_cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface,
cairo_scaled_font_subset_t *font_subset)
@@ -928,30 +906,17 @@ _cairo_ps_surface_emit_font_subsets (cairo_ps_surface_t *surface)
"%% _cairo_ps_surface_emit_font_subsets\n");
#endif
- status = _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
- _cairo_ps_surface_analyze_user_font_subset,
- surface);
- if (unlikely (status))
- return status;
-
status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets,
_cairo_ps_surface_emit_unscaled_font_subset,
surface);
if (unlikely (status))
return status;
- status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
- _cairo_ps_surface_emit_scaled_font_subset,
- surface);
- if (unlikely (status))
- return status;
-
- return _cairo_scaled_font_subsets_foreach_user (surface->font_subsets,
- _cairo_ps_surface_emit_scaled_font_subset,
- surface);
+ return _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets,
+ _cairo_ps_surface_emit_scaled_font_subset,
+ surface);
}
-
static cairo_int_status_t
_cairo_ps_surface_emit_forms (cairo_ps_surface_t *surface)
{
@@ -3095,9 +3060,10 @@ _cairo_ps_surface_emit_ccitt_image (cairo_ps_surface_t *surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
/* ensure params_string is null terminated */
- ccitt_params_string = malloc (ccitt_params_data_len + 1);
- memcpy (ccitt_params_string, ccitt_params_data, ccitt_params_data_len);
- ccitt_params_string[ccitt_params_data_len] = 0;
+ ccitt_params_string = _cairo_strndup ((const char *)ccitt_params_data, ccitt_params_data_len);
+ if (unlikely (ccitt_params_string == NULL))
+ return _cairo_surface_set_error (&surface->base, CAIRO_STATUS_NO_MEMORY);
+
status = _cairo_tag_parse_ccitt_params (ccitt_params_string, &ccitt_params);
if (unlikely(status))
return status;
@@ -3280,9 +3246,10 @@ _cairo_ps_surface_emit_eps (cairo_ps_surface_t *surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
/* ensure params_string is null terminated */
- params_string = malloc (eps_params_string_len + 1);
- memcpy (params_string, eps_params_string, eps_params_string_len);
- params_string[eps_params_string_len] = 0;
+ params_string = _cairo_strndup ((const char *)eps_params_string, eps_params_string_len);
+ if (unlikely (params_string == NULL))
+ return _cairo_surface_set_error (&surface->base, CAIRO_STATUS_NO_MEMORY);
+
status = _cairo_tag_parse_eps_params (params_string, &eps_params);
if (unlikely(status))
return status;
@@ -3327,7 +3294,11 @@ _cairo_ps_surface_emit_eps (cairo_ps_surface_t *surface,
eps_width,
eps_height);
+ _cairo_output_stream_printf (surface->stream,
+ "%%%%BeginDocument: Document%d\n",
+ params->src_surface->unique_id);
_cairo_output_stream_write (surface->stream, eps_data, eps_data_len);
+ _cairo_output_stream_printf (surface->stream, "%%%%EndDocument");
_cairo_output_stream_printf (surface->stream, "\ncairo_eps_end\n");
return CAIRO_STATUS_SUCCESS;
@@ -3336,6 +3307,7 @@ _cairo_ps_surface_emit_eps (cairo_ps_surface_t *surface,
static cairo_status_t
_cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t *surface,
cairo_surface_t *recording_surface,
+ unsigned int regions_id,
const cairo_rectangle_int_t *recording_extents,
cairo_bool_t subsurface)
{
@@ -3406,6 +3378,7 @@ _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t *surface,
}
status = _cairo_recording_surface_replay_region (recording_surface,
+ regions_id,
subsurface ? recording_extents : NULL,
&surface->base,
CAIRO_RECORDING_REGION_NATIVE);
@@ -3558,6 +3531,9 @@ _cairo_ps_surface_use_form (cairo_ps_surface_t *surface,
source_entry->unique_id = unique_id;
source_entry->id = surface->num_forms++;
source_entry->src_surface = cairo_surface_reference (params->src_surface);
+ source_entry->regions_id = params->regions_id;
+ if (_cairo_surface_is_recording (source_entry->src_surface) && source_entry->regions_id != 0)
+ _cairo_recording_surface_region_array_reference (source_entry->src_surface, source_entry->regions_id);
source_entry->src_surface_extents = *params->src_surface_extents;
source_entry->src_surface_bounded = params->src_surface_bounded;
source_entry->required_extents = *params->src_op_extents;
@@ -3690,11 +3666,13 @@ _cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface,
cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) params->src_surface;
status = _cairo_ps_surface_emit_recording_surface (surface,
sub->target,
+ params->regions_id,
&sub->extents,
TRUE);
} else {
status = _cairo_ps_surface_emit_recording_surface (surface,
params->src_surface,
+ params->regions_id,
params->src_op_extents,
FALSE);
}
@@ -3713,11 +3691,11 @@ _cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface,
status = _cairo_memory_stream_destroy (surface->stream, &data, &length);
free (data);
+ surface->stream = old_stream;
if (unlikely (status))
return status;
params->approx_size = length;
- surface->stream = old_stream;
_cairo_pdf_operators_set_stream (&surface->pdf_operators,
surface->stream);
}
@@ -3737,6 +3715,7 @@ _cairo_ps_form_emit (void *entry, void *closure)
cairo_output_stream_t *old_stream;
params.src_surface = form->src_surface;
+ params.regions_id = form->regions_id;
params.op = CAIRO_OPERATOR_OVER;
params.src_surface_extents = &form->src_surface_extents;
params.src_surface_bounded = form->src_surface_bounded;
@@ -3878,11 +3857,17 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface,
cairo_path_fixed_t path;
cairo_emit_surface_params_t params;
cairo_image_surface_t *image = NULL;
+ unsigned int region_id = 0;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (unlikely (status))
return status;
+ if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
+ region_id = surface_pattern->region_array_id;
+ }
+
status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface,
pattern,
extents,
@@ -3968,6 +3953,7 @@ _cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface,
cairo_matrix_translate (&ps_p2d, x_offset, y_offset);
params.src_surface = image ? &image->base : source_surface;
+ params.regions_id = image ? 0 : region_id;
params.op = op;
params.src_surface_extents = &src_surface_extents;
params.src_surface_bounded = src_surface_bounded;
@@ -4022,12 +4008,18 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
cairo_rectangle_int_t src_op_extents;
cairo_emit_surface_params_t params;
cairo_extend_t extend = cairo_pattern_get_extend (pattern);
+ unsigned int region_id = 0;
cairo_p2d = pattern->matrix;
status = cairo_matrix_invert (&cairo_p2d);
/* cairo_pattern_set_matrix ensures the matrix is invertible */
assert (status == CAIRO_STATUS_SUCCESS);
+ if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
+ region_id = surface_pattern->region_array_id;
+ }
+
status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface,
pattern,
extents,
@@ -4121,6 +4113,7 @@ _cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface,
old_paint_proc = surface->paint_proc;
surface->paint_proc = TRUE;
params.src_surface = image ? &image->base : source_surface;
+ params.regions_id = image ? 0 : region_id;
params.op = op;
params.src_surface_extents = &pattern_extents;
params.src_surface_bounded = bounded;
diff --git a/src/cairo-quartz-font.c b/src/cairo-quartz-font.c
index 641a2dfc7..1e7531356 100644
--- a/src/cairo-quartz-font.c
+++ b/src/cairo-quartz-font.c
@@ -656,7 +656,7 @@ _cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font,
cairo_surface_mark_dirty (&surface->base);
if (is_color)
- _cairo_scaled_glyph_set_color_surface (scaled_glyph, &font->base, surface, fg_color != NULL);
+ _cairo_scaled_glyph_set_color_surface (scaled_glyph, &font->base, surface, fg_color);
else
_cairo_scaled_glyph_set_surface (scaled_glyph, &font->base, surface);
diff --git a/src/cairo-quartz-image-surface.c b/src/cairo-quartz-image-surface.c
index 30d92d6be..d09f5b5bc 100644
--- a/src/cairo-quartz-image-surface.c
+++ b/src/cairo-quartz-image-surface.c
@@ -49,12 +49,6 @@
#define SURFACE_ERROR_INVALID_SIZE (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_SIZE)))
#define SURFACE_ERROR_INVALID_FORMAT (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_FORMAT)))
-static void
-DataProviderReleaseCallback (void *image_info, const void *data, size_t size)
-{
- free (image_info);
-}
-
static cairo_surface_t *
_cairo_quartz_image_surface_create_similar (void *asurface,
cairo_content_t content,
@@ -87,8 +81,9 @@ _cairo_quartz_image_surface_finish (void *asurface)
{
cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
- CGImageRelease (surface->image);
- cairo_surface_destroy ( (cairo_surface_t*) surface->imageSurface);
+ CGContextRelease (surface->cgContext);
+ if (surface->imageSurface)
+ cairo_surface_destroy ( (cairo_surface_t*) surface->imageSurface);
return CAIRO_STATUS_SUCCESS;
}
@@ -134,47 +129,6 @@ _cairo_quartz_image_surface_get_extents (void *asurface,
return TRUE;
}
-/* we assume some drawing happened to the image buffer; make sure it's
- * represented in the CGImage on flush()
- */
-
-static cairo_status_t
-_cairo_quartz_image_surface_flush (void *asurface,
- unsigned flags)
-{
- cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
- CGImageRef oldImage = surface->image;
- CGImageRef newImage = NULL;
- void *image_data;
- const unsigned int size = surface->imageSurface->height * surface->imageSurface->stride;
- if (flags)
- return CAIRO_STATUS_SUCCESS;
-
- /* XXX only flush if the image has been modified. */
-
- image_data = _cairo_malloc_ab ( surface->imageSurface->height,
- surface->imageSurface->stride);
- if (unlikely (!image_data))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- memcpy (image_data, surface->imageSurface->data,
- surface->imageSurface->height * surface->imageSurface->stride);
- newImage = CairoQuartzCreateCGImage (surface->imageSurface->format,
- surface->imageSurface->width,
- surface->imageSurface->height,
- surface->imageSurface->stride,
- image_data,
- TRUE,
- NULL,
- DataProviderReleaseCallback,
- image_data);
-
- surface->image = newImage;
- CGImageRelease (oldImage);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
static cairo_int_status_t
_cairo_quartz_image_surface_paint (void *abstract_surface,
cairo_operator_t op,
@@ -275,7 +229,7 @@ static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
_cairo_quartz_image_surface_get_extents,
NULL, /* get_font_options */
- _cairo_quartz_image_surface_flush,
+ NULL, /*surface_flush */
NULL, /* mark_dirty_rectangle */
_cairo_quartz_image_surface_paint,
@@ -290,12 +244,9 @@ static const cairo_surface_backend_t cairo_quartz_image_surface_backend = {
* cairo_quartz_image_surface_create:
* @image_surface: a cairo image surface to wrap with a quartz image surface
*
- * Creates a Quartz surface backed by a CGImageRef that references the
+ * Creates a Quartz surface backed by a CGBitmapContext that references the
* given image surface. The resulting surface can be rendered quickly
- * when used as a source when rendering to a #cairo_quartz_surface. If
- * the data in the image surface is ever updated, cairo_surface_flush()
- * must be called on the #cairo_quartz_image_surface to ensure that the
- * CGImageRef refers to the updated data.
+ * when used as a source when rendering to a #cairo_quartz_surface.
*
* Return value: the newly created surface.
*
@@ -305,13 +256,11 @@ cairo_surface_t *
cairo_quartz_image_surface_create (cairo_surface_t *surface)
{
cairo_quartz_image_surface_t *qisurf;
-
- CGImageRef image;
-
cairo_image_surface_t *image_surface;
int width, height, stride;
cairo_format_t format;
- void *image_data;
+ CGBitmapInfo bitinfo = kCGBitmapByteOrder32Host;
+ CGColorSpaceRef colorspace;
if (surface->status)
return surface;
@@ -338,54 +287,100 @@ cairo_quartz_image_surface_create (cairo_surface_t *surface)
if (qisurf == NULL)
return SURFACE_ERROR_NO_MEMORY;
- memset (qisurf, 0, sizeof(cairo_quartz_image_surface_t));
-
- image_data = _cairo_malloc_ab (height, stride);
- if (unlikely (!image_data)) {
- free(qisurf);
- return SURFACE_ERROR_NO_MEMORY;
- }
-
- memcpy (image_data, image_surface->data, height * stride);
- image = CairoQuartzCreateCGImage (format,
- width, height,
- stride,
- image_data,
- TRUE,
- NULL,
- DataProviderReleaseCallback,
- image_data);
-
- if (!image) {
- free (qisurf);
- return SURFACE_ERROR_NO_MEMORY;
- }
-
_cairo_surface_init (&qisurf->base,
&cairo_quartz_image_surface_backend,
NULL, /* device */
_cairo_content_from_format (format),
FALSE); /* is_vector */
+ if (_cairo_surface_is_quartz (surface) || _cairo_surface_is_quartz_image (surface)) {
+ CGContextRef context = cairo_quartz_surface_get_cg_context(surface);
+ colorspace = _cairo_quartz_create_color_space (context);
+ }
+ else {
+ colorspace = CGDisplayCopyColorSpace (CGMainDisplayID ());
+ }
+
+ bitinfo |= format == CAIRO_FORMAT_ARGB32 ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
+
qisurf->width = width;
qisurf->height = height;
- qisurf->image = image;
+ qisurf->cgContext = CGBitmapContextCreate (image_surface->data, width, height, 8, image_surface->stride,
+ colorspace, bitinfo);
qisurf->imageSurface = (cairo_image_surface_t*) cairo_surface_reference(surface);
+ CGColorSpaceRelease (colorspace);
return &qisurf->base;
}
+/**
+ * cairo_quartz_image_surface_get_image:
+ * @surface: a #cairo_surface_t
+ *
+ * Returns a #cairo_surface_t image surface that refers to the same bits
+ * as the image of the quartz surface.
+ *
+ * Return value: a #cairo_surface_t (owned by the quartz #cairo_surface_t),
+ * or %NULL if the quartz surface is not an image surface.
+ *
+ * Since: 1.6
+ */
cairo_surface_t *
-cairo_quartz_image_surface_get_image (cairo_surface_t *asurface)
+cairo_quartz_image_surface_get_image (cairo_surface_t *surface)
{
- cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t*) asurface;
+ cairo_quartz_image_surface_t *qsurface = (cairo_quartz_image_surface_t*) surface;
/* Throw an error for a non-quartz surface */
- if (! _cairo_surface_is_quartz (asurface)) {
+ if (! _cairo_surface_is_quartz (surface)) {
return SURFACE_ERROR_TYPE_MISMATCH;
}
- return (cairo_surface_t*) surface->imageSurface;
+ return (cairo_surface_t*) qsurface->imageSurface;
+}
+
+/*
+ * _cairo_quartz_image_surface_get_cg_context:
+ * @surface: the Cairo Quartz surface
+ *
+ * Returns the CGContextRef that the given Quartz surface is backed
+ * by.
+ *
+ * A call to cairo_surface_flush() is required before using the
+ * CGContextRef to ensure that all pending drawing operations are
+ * finished and to restore any temporary modification cairo has made
+ * to its state. A call to cairo_surface_mark_dirty() is required
+ * after the state or the content of the CGContextRef has been
+ * modified.
+ *
+ * Return value: the CGContextRef for the given surface.
+ *
+ **/
+CGContextRef
+_cairo_quartz_image_surface_get_cg_context (cairo_surface_t *surface)
+{
+ if (surface && _cairo_surface_is_quartz_image (surface)) {
+ cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t *) surface;
+ return quartz->cgContext;
+ } else
+ return NULL;
+}
+
+/*
+ * _cairo_surface_is_quartz_image:
+ * @surface: a #cairo_surface_t
+ *
+ * Checks if a surface is a #cairo_quartz_surface_t
+ *
+ * Return value: True if the surface is an quartz surface
+ **/
+cairo_bool_t
+_cairo_surface_is_quartz_image (const cairo_surface_t *surface) {
+ return surface->backend == &cairo_quartz_image_surface_backend;
+}
+
+cairo_bool_t
+_cairo_quartz_image_surface_is_zero (const cairo_quartz_image_surface_t *surface) {
+ return surface->width == 0 || surface->height == 0;
}
diff --git a/src/cairo-quartz-private.h b/src/cairo-quartz-private.h
index f142f8471..bdfdf8c2b 100644
--- a/src/cairo-quartz-private.h
+++ b/src/cairo-quartz-private.h
@@ -81,8 +81,7 @@ typedef struct cairo_quartz_image_surface {
cairo_surface_t base;
int width, height;
-
- CGImageRef image;
+ CGContextRef cgContext;
cairo_image_surface_t *imageSurface;
} cairo_quartz_image_surface_t;
@@ -92,16 +91,15 @@ _cairo_quartz_verify_surface_size(int width, int height);
cairo_private cairo_bool_t
_cairo_surface_is_quartz (const cairo_surface_t *surface);
-cairo_private CGImageRef
-CairoQuartzCreateCGImage (cairo_format_t format,
- unsigned int width,
- unsigned int height,
- unsigned int stride,
- void *data,
- cairo_bool_t interpolate,
- CGColorSpaceRef colorSpaceOverride,
- CGDataProviderReleaseDataCallback releaseCallback,
- void *releaseInfo);
+cairo_private cairo_bool_t
+_cairo_surface_is_quartz_image (const cairo_surface_t *surface);
+cairo_private cairo_bool_t
+_cairo_quartz_image_surface_is_zero (const cairo_quartz_image_surface_t *surface);
+
+cairo_private CGColorSpaceRef
+_cairo_quartz_create_color_space (CGContextRef context);
+cairo_private CGContextRef
+_cairo_quartz_image_surface_get_cg_context (cairo_surface_t *surface);
cairo_private CGFontRef
_cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont);
@@ -112,6 +110,9 @@ _cairo_quartz_font_face_create_for_ctfont (CTFontRef ctFont);
cairo_private void
_cairo_quartz_set_antialiasing (CGContextRef context, cairo_antialias_t antialias);
+cairo_status_t _cairo_quartz_surface_to_png (cairo_surface_t *abstract_surface, const char *dest);
+cairo_private void _cairo_quartz_image_to_png (CGImageRef, const char *dest);
+
#else
# error Cairo was not compiled with support for the quartz backend
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index 6676dc960..d8a8065d0 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -37,6 +37,7 @@
#include "cairoint.h"
#include "cairo-quartz-private.h"
+#include "cairo-quartz-image.h"
#include "cairo-composite-rectangles-private.h"
#include "cairo-compositor-private.h"
@@ -55,6 +56,7 @@
#endif
#include <limits.h>
+#include <assert.h>
#undef QUARTZ_DEBUG
@@ -64,13 +66,30 @@
#define ND(_x) do {} while(0)
#endif
-#define IS_EMPTY(s) ((s)->extents.width == 0 || (s)->extents.height == 0)
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
#define FONT_ORIENTATION_HORIZONTAL kCTFontHorizontalOrientation
#else
#define FONT_ORIENTATION_HORIZONTAL kCTFontOrientationHorizontal
#endif
+static inline cairo_bool_t
+_is_quartz_surface (cairo_surface_t *surface) {
+ return _cairo_surface_is_quartz (surface) || _cairo_surface_is_quartz_image (surface);
+}
+
+static inline cairo_bool_t
+_cairo_quartz_surface_is_zero (cairo_quartz_surface_t* surface) {
+ return surface->extents.width == 0 || surface->extents.height == 0;
+}
+
+static inline cairo_bool_t
+_cairo_quartz_is_zero_surface (cairo_surface_t* surface) {
+ assert (_is_quartz_surface (surface));
+ if (_cairo_surface_is_quartz (surface))
+ return (_cairo_quartz_surface_is_zero ((cairo_quartz_surface_t*) surface));
+ else
+ return (_cairo_quartz_image_surface_is_zero ((cairo_quartz_image_surface_t*) surface));
+}
/**
* SECTION:cairo-quartz
@@ -94,6 +113,20 @@
/*
* macOS Private functions
*/
+typedef enum {
+ kCGContextTypeUnknown,
+ kCGContextTypePDF,
+ kCGContextTypePostScript,
+ kCGContextTypeWindow,
+ kCGContextTypeBitmap,
+ kCGContextTypeGL,
+ kCGContextTypeDisplayList,
+ kCGContextTypeKSeparation,
+ kCGContextTypeIOSurface,
+ kCGContextTypeCount
+} CGContextType;
+
+
static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL;
static unsigned int (*CGContextGetTypePtr) (CGContextRef) = NULL;
static void
@@ -108,20 +141,15 @@ quartz_ensure_symbols()
}
}
-#ifdef QUARTZ_DEBUG
-static void quartz_surface_to_png (cairo_quartz_surface_t *nq, const char *dest);
-static void quartz_image_to_png (CGImageRef, const char *dest);
-#endif
-
typedef struct
{
cairo_surface_t base;
CGImageRef image;
} cairo_quartz_snapshot_t;
-static cairo_surface_t* _cairo_quartz_snapshot_create (cairo_quartz_surface_t *surface);
-static cairo_status_t _cairo_quartz_snapshot_finish (void* surface);
-static CGImageRef _cairo_quartz_surface_snapshot_get_image (cairo_quartz_surface_t *surface);
+static cairo_surface_t* _cairo_quartz_snapshot_create (cairo_surface_t *surface);
+static cairo_status_t _cairo_quartz_snapshot_finish (void *surface);
+static CGImageRef _cairo_quartz_surface_snapshot_get_image (cairo_surface_t *surface);
static const cairo_surface_backend_t cairo_quartz_snapshot_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_QUARTZ_SNAPSHOT,
@@ -134,102 +162,72 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext,
unsigned int width,
unsigned int height);
-CGImageRef
-CairoQuartzCreateCGImage (cairo_format_t format,
- unsigned int width,
- unsigned int height,
- unsigned int stride,
- void *data,
- cairo_bool_t interpolate,
- CGColorSpaceRef colorSpaceOverride,
- CGDataProviderReleaseDataCallback releaseCallback,
- void *releaseInfo)
+CGColorSpaceRef
+_cairo_quartz_create_color_space (CGContextRef context)
{
- CGImageRef image = NULL;
- CGDataProviderRef dataProvider = NULL;
- CGColorSpaceRef colorSpace = colorSpaceOverride;
- CGBitmapInfo bitinfo = kCGBitmapByteOrder32Host;
- int bitsPerComponent, bitsPerPixel;
-
- switch (format) {
- case CAIRO_FORMAT_ARGB32:
- if (colorSpace == NULL)
- colorSpace = CGColorSpaceCreateDeviceRGB ();
- bitinfo |= kCGImageAlphaPremultipliedFirst;
- bitsPerComponent = 8;
- bitsPerPixel = 32;
- break;
-
- case CAIRO_FORMAT_RGB24:
- if (colorSpace == NULL)
- colorSpace = CGColorSpaceCreateDeviceRGB ();
- bitinfo |= kCGImageAlphaNoneSkipFirst;
- bitsPerComponent = 8;
- bitsPerPixel = 32;
- break;
-
- case CAIRO_FORMAT_A8:
- bitsPerComponent = 8;
- bitsPerPixel = 8;
- break;
-
- case CAIRO_FORMAT_A1:
-#ifdef WORDS_BIGENDIAN
- bitsPerComponent = 1;
- bitsPerPixel = 1;
- break;
-#endif
-
- case CAIRO_FORMAT_RGB30:
- case CAIRO_FORMAT_RGB16_565:
- case CAIRO_FORMAT_RGB96F:
- case CAIRO_FORMAT_RGBA128F:
- case CAIRO_FORMAT_INVALID:
- default:
- return NULL;
- }
-
- dataProvider = CGDataProviderCreateWithData (releaseInfo,
- data,
- height * stride,
- releaseCallback);
+ CGColorSpaceRef color_space = NULL;
+ CGContextType cgtype = kCGContextTypeUnknown;
- if (unlikely (!dataProvider)) {
- // manually release
- if (releaseCallback)
- releaseCallback (releaseInfo, data, height * stride);
- goto FINISH;
+ if (context)
+ {
+ if (CGBitmapContextGetBitsPerPixel (context) < 24)
+ return 0;
+
+ quartz_ensure_symbols();
+ cgtype = CGContextGetTypePtr (context);
+ switch (cgtype)
+ {
+ case kCGContextTypeUnknown:
+ break;
+ case kCGContextTypePDF:
+ color_space = CGColorSpaceCreateDeviceRGB ();
+ break;
+ case kCGContextTypePostScript:
+ case kCGContextTypeWindow:
+ break;
+ case kCGContextTypeBitmap:
+ color_space = CGBitmapContextGetColorSpace (context);
+ color_space = CGColorSpaceRetain (color_space);
+ break;
+ case kCGContextTypeGL:
+ case kCGContextTypeDisplayList:
+ case kCGContextTypeKSeparation:
+ case kCGContextTypeIOSurface:
+ case kCGContextTypeCount:
+ default:
+ break;
+ }
+ if (color_space)
+ return color_space;
}
+ if (!color_space)
+ color_space = CGDisplayCopyColorSpace (CGMainDisplayID ());
- if (format == CAIRO_FORMAT_A8 || format == CAIRO_FORMAT_A1) {
- cairo_quartz_float_t decode[] = {1.0, 0.0};
- image = CGImageMaskCreate (width, height,
- bitsPerComponent,
- bitsPerPixel,
- stride,
- dataProvider,
- decode,
- interpolate);
- } else
- image = CGImageCreate (width, height,
- bitsPerComponent,
- bitsPerPixel,
- stride,
- colorSpace,
- bitinfo,
- dataProvider,
- NULL,
- interpolate,
- kCGRenderingIntentDefault);
-
-FINISH:
+ if (!color_space)
+ color_space = CGColorSpaceCreateDeviceRGB ();
- CGDataProviderRelease (dataProvider);
+ return color_space;
+}
- if (colorSpace != colorSpaceOverride)
- CGColorSpaceRelease (colorSpace);
+static CGColorRef
+_cairo_quartz_create_cgcolor (CGColorSpaceRef cs, CGFloat red, CGFloat green,
+ CGFloat blue, CGFloat alpha)
+{
+ CGFloat colors[4] = { red, green, blue, alpha };
+ CGColorRef cgc;
+ if (!CGColorSpaceRetain(cs))
+ {
+ cs = _cairo_quartz_create_color_space (NULL);
+ }
+ cgc = CGColorCreate (cs, colors);
+ CGColorSpaceRelease (cs);
+ return cgc;
+}
- return image;
+static CGColorRef
+_cairo_quartz_black (CGColorSpaceRef cs)
+{
+ return _cairo_quartz_create_cgcolor (cs, 0.0, 0.0, 0.0, 1.0);
}
static inline cairo_bool_t
@@ -241,7 +239,7 @@ _cairo_quartz_is_cgcontext_bitmap_context (CGContextRef cgc)
quartz_ensure_symbols ();
if (likely (CGContextGetTypePtr)) {
/* 4 is the type value of a bitmap context */
- return CGContextGetTypePtr (cgc) == 4;
+ return CGContextGetTypePtr (cgc) == kCGContextTypeBitmap;
}
/* This will cause a (harmless) warning to be printed if called on a non-bitmap context */
@@ -682,12 +680,6 @@ CairoQuartzCreateGradientFunction (const cairo_gradient_pattern_t *gradient,
&gradient_callbacks);
}
-static void
-DataProviderReleaseCallback (void *info, const void *data, size_t size)
-{
- free (info);
-}
-
static cairo_status_t
_cairo_surface_to_cgimage (cairo_surface_t *source,
cairo_rectangle_int_t *extents,
@@ -697,25 +689,19 @@ _cairo_surface_to_cgimage (cairo_surface_t *source,
CGImageRef *image_out)
{
cairo_status_t status;
- cairo_image_surface_t *image_surface;
- void *image_data, *image_extra;
+ cairo_quartz_image_surface_t *image_surface;
+ void *image_extra;
cairo_bool_t acquired = FALSE;
- if (source->backend && source->backend->type == CAIRO_SURFACE_TYPE_QUARTZ_IMAGE) {
- cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) source;
- *image_out = CGImageRetain (surface->image);
- return CAIRO_STATUS_SUCCESS;
- }
-
- if (_cairo_surface_is_quartz (source)) {
- cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) source;
- if (IS_EMPTY (surface)) {
+ if (_is_quartz_surface (source)) {
+ CGContextRef cgContext = cairo_quartz_surface_get_cg_context(source);
+ if (_cairo_quartz_is_zero_surface (source)) {
*image_out = NULL;
return CAIRO_INT_STATUS_NOTHING_TO_DO;
}
- if (_cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext)) {
- *image_out = _cairo_quartz_surface_snapshot_get_image (surface);
+ if (_cairo_quartz_is_cgcontext_bitmap_context (cgContext)) {
+ *image_out = _cairo_quartz_surface_snapshot_get_image (source);
return CAIRO_STATUS_SUCCESS;
}
@@ -724,79 +710,60 @@ _cairo_surface_to_cgimage (cairo_surface_t *source,
}
if (source->type == CAIRO_SURFACE_TYPE_RECORDING) {
- image_surface = (cairo_image_surface_t *)
- cairo_image_surface_create (format, extents->width, extents->height);
- if (unlikely (image_surface->base.status)) {
- status = image_surface->base.status;
- cairo_surface_destroy (&image_surface->base);
+ cairo_image_surface_t *surface =
+ (cairo_image_surface_t*)cairo_image_surface_create (format, extents->width,
+ extents->height);
+ if (unlikely (surface->base.status)) {
+ status = surface->base.status;
+ cairo_surface_destroy (&surface->base);
return status;
}
status = _cairo_recording_surface_replay_with_clip (source,
matrix,
- &image_surface->base,
- NULL);
+ &surface->base,
+ NULL,
+ FALSE);
if (unlikely (status)) {
- cairo_surface_destroy (&image_surface->base);
+ cairo_surface_destroy (&surface->base);
return status;
}
+ image_surface =
+ (cairo_quartz_image_surface_t*)cairo_quartz_image_surface_create (&surface->base);
cairo_matrix_init_identity (matrix);
}
else {
- status = _cairo_surface_acquire_source_image (source, &image_surface,
+ cairo_image_surface_t *surface;
+ status = _cairo_surface_acquire_source_image (source, &surface,
&image_extra);
if (unlikely (status))
return status;
- acquired = TRUE;
- }
-
- if (image_surface->width == 0 || image_surface->height == 0) {
- *image_out = NULL;
- if (acquired)
- _cairo_surface_release_source_image (source, image_surface, image_extra);
+ image_surface =
+ (cairo_quartz_image_surface_t*)cairo_quartz_image_surface_create (&surface->base);
+ status = image_surface->base.status;
+ if (status)
+ _cairo_surface_release_source_image (source, surface, image_extra);
else
- cairo_surface_destroy (&image_surface->base);
-
- return status;
+ acquired = TRUE;
}
- image_data = _cairo_malloc_ab (image_surface->height, image_surface->stride);
- if (unlikely (!image_data))
- {
- if (acquired)
- _cairo_surface_release_source_image (source, image_surface, image_extra);
- else
- cairo_surface_destroy (&image_surface->base);
-
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ *image_out = NULL;
+ if (image_surface->width > 0 && image_surface->height > 0) {
+ *image_out = _cairo_quartz_surface_snapshot_get_image (&image_surface->base);
+ status = CAIRO_STATUS_SUCCESS;
}
- // The last row of data may have less than stride bytes so make sure we
- // only copy the minimum amount required from that row.
- memcpy (image_data, image_surface->data,
- (image_surface->height - 1) * image_surface->stride +
- cairo_format_stride_for_width (image_surface->format,
- image_surface->width));
- *image_out = CairoQuartzCreateCGImage (image_surface->format,
- image_surface->width,
- image_surface->height,
- image_surface->stride,
- image_data,
- TRUE,
- NULL,
- DataProviderReleaseCallback,
- image_data);
+ if (acquired) {
+ _cairo_surface_release_source_image (source, image_surface->imageSurface, image_extra);
+ image_surface->imageSurface = NULL;
+ }
+ cairo_surface_destroy (&image_surface->base);
/* TODO: differentiate memory error and unsupported surface type */
if (unlikely (*image_out == NULL))
status = CAIRO_INT_STATUS_UNSUPPORTED;
- if (acquired)
- _cairo_surface_release_source_image (source, image_surface, image_extra);
- else
- cairo_surface_destroy (&image_surface->base);
-
return status;
}
@@ -901,7 +868,7 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t
switch (spattern->base.extend) {
case CAIRO_EXTEND_NONE:
- break;
+ case CAIRO_EXTEND_PAD:
case CAIRO_EXTEND_REPEAT:
pbounds.size.width = extents.width;
pbounds.size.height = extents.height;
@@ -911,10 +878,6 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t
pbounds.size.height = 2.0 * extents.height;
info->do_reflect = TRUE;
break;
- case CAIRO_EXTEND_PAD:
- pbounds.size.width = extents.width;
- pbounds.size.height = extents.height;
- break;
}
rw = pbounds.size.width;
rh = pbounds.size.height;
@@ -996,6 +959,7 @@ _cairo_quartz_setup_pattern_source (cairo_quartz_drawing_state_t *state,
CGColorSpaceRef patternSpace;
CGPatternRef cgpat = NULL;
cairo_int_status_t status;
+ CGColorRef black = _cairo_quartz_black (_cairo_quartz_create_color_space (state->cgDrawContext));
_cairo_surface_get_extents (&surface->base, &extents);
@@ -1051,7 +1015,7 @@ _cairo_quartz_setup_pattern_source (cairo_quartz_drawing_state_t *state,
-state->clipRect.origin.y);
}
- CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 1);
+ CGContextSetFillColorWithColor (state->cgDrawContext, black);
state->rect = CGRectMake (0, 0, pattern_extents.width, pattern_extents.height);
state->action = DO_IMAGE;
@@ -1090,6 +1054,7 @@ _cairo_quartz_setup_pattern_source (cairo_quartz_drawing_state_t *state,
CGContextSetPatternPhase (state->cgDrawContext, CGSizeMake (0, 0));
CGPatternRelease (cgpat);
+ CGColorRelease (black);
state->action = DO_DIRECT;
return CAIRO_STATUS_SUCCESS;
@@ -1129,7 +1094,7 @@ _cairo_quartz_setup_gradient_source (cairo_quartz_drawing_state_t *state,
if (unlikely (gradFunc == NULL))
return CAIRO_INT_STATUS_UNSUPPORTED;
- rgb = CGColorSpaceCreateDeviceRGB ();
+ rgb = _cairo_quartz_create_color_space (NULL);
if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
state->shading = CGShadingCreateAxial (rgb,
@@ -1200,9 +1165,11 @@ _cairo_quartz_setup_state (cairo_quartz_drawing_state_t *state,
state->filter = _cairo_quartz_filter_to_quartz (source->filter);
if (op == CAIRO_OPERATOR_CLEAR) {
- CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 1);
+ CGColorRef black = _cairo_quartz_black (_cairo_quartz_create_color_space (surface->cgContext));
+ CGContextSetFillColorWithColor (state->cgDrawContext, black);
state->action = DO_DIRECT;
+ CGColorRelease (black);
return CAIRO_STATUS_SUCCESS;
}
@@ -1239,18 +1206,17 @@ _cairo_quartz_setup_state (cairo_quartz_drawing_state_t *state,
if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
+ CGColorRef color = _cairo_quartz_create_cgcolor (_cairo_quartz_create_color_space (state->cgDrawContext),
+ solid->color.red,
+ solid->color.green,
+ solid->color.blue,
+ solid->color.alpha);
+
- CGContextSetRGBStrokeColor (state->cgDrawContext,
- solid->color.red,
- solid->color.green,
- solid->color.blue,
- solid->color.alpha);
- CGContextSetRGBFillColor (state->cgDrawContext,
- solid->color.red,
- solid->color.green,
- solid->color.blue,
- solid->color.alpha);
+ CGContextSetStrokeColorWithColor (state->cgDrawContext, color);
+ CGContextSetFillColorWithColor (state->cgDrawContext, color);
+ CGColorRelease (color);
state->action = DO_DIRECT;
return CAIRO_STATUS_SUCCESS;
}
@@ -1304,6 +1270,9 @@ static inline void
_cairo_quartz_draw_cgcontext (cairo_quartz_drawing_state_t *state,
cairo_operator_t op)
{
+ CGColorSpaceRef cs = _cairo_quartz_create_color_space (state->cgDrawContext);
+ CGColorRef transparent = _cairo_quartz_create_cgcolor (cs, 0.0, 0.0, 0.0, 0.0); //releases cs
+
if (! (op == CAIRO_OPERATOR_SOURCE &&
state->cgDrawContext == state->cgMaskContext))
return;
@@ -1318,8 +1287,9 @@ _cairo_quartz_draw_cgcontext (cairo_quartz_drawing_state_t *state,
CGContextAddRect (state->cgDrawContext, state->clipRect);
- CGContextSetRGBFillColor (state->cgDrawContext, 0, 0, 0, 0);
+ CGContextSetFillColorWithColor (state->cgDrawContext, transparent);
CGContextEOFillPath (state->cgDrawContext);
+ CGColorRelease (transparent);
}
@@ -1370,7 +1340,7 @@ _cairo_quartz_surface_map_to_image (void *abstract_surface,
unsigned char *imageData;
cairo_format_t format;
- if (IS_EMPTY (surface))
+ if (_cairo_quartz_is_zero_surface (&surface->base))
return (cairo_image_surface_t *) cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
if (! _cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext))
@@ -1380,8 +1350,9 @@ _cairo_quartz_surface_map_to_image (void *abstract_surface,
bpp = CGBitmapContextGetBitsPerPixel (surface->cgContext);
// let's hope they don't add YUV under us
- colorspace = CGBitmapContextGetColorSpace (surface->cgContext);
+ colorspace = _cairo_quartz_create_color_space (surface->cgContext);
color_comps = CGColorSpaceGetNumberOfComponents (colorspace);
+ CGColorSpaceRelease (colorspace);
/* XXX TODO: We can handle many more data formats by
* converting to pixman_format_t */
@@ -1442,7 +1413,7 @@ _cairo_quartz_surface_finish (void *abstract_surface)
ND ((stderr, "_cairo_quartz_surface_finish[%p] cgc: %p\n", surface, surface->cgContext));
- if (IS_EMPTY (surface))
+ if (_cairo_quartz_is_zero_surface (&surface->base))
return CAIRO_STATUS_SUCCESS;
/* Restore our saved gstate that we use to reset clipping */
@@ -1904,7 +1875,7 @@ _cairo_quartz_cg_glyphs (const cairo_compositor_t *compositor,
cairo_bool_t overlap)
{
CGAffineTransform textTransform, invTextTransform;
- CGGlyph glyphs_static[CAIRO_STACK_ARRAY_LENGTH (CGGlyph)];
+ CGGlyph glyphs_static[CAIRO_STACK_ARRAY_LENGTH (CGPoint)];
CGPoint cg_positions_static[CAIRO_STACK_ARRAY_LENGTH (CGPoint)];
CGGlyph *cg_glyphs = &glyphs_static[0];
CGPoint *cg_positions = &cg_positions_static[0];
@@ -2089,7 +2060,7 @@ _cairo_quartz_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clip
ND ((stderr, "%p _cairo_quartz_surface_intersect_clip_path path: %p\n", surface, path));
- if (IS_EMPTY (surface))
+ if (_cairo_quartz_is_zero_surface (&surface->base))
return CAIRO_STATUS_SUCCESS;
if (path == NULL) {
@@ -2187,7 +2158,7 @@ _cairo_quartz_surface_create_internal (CGContextRef cgContext,
surface->extents.height = height;
surface->virtual_extents = surface->extents;
- if (IS_EMPTY (surface)) {
+ if (_cairo_quartz_is_zero_surface (&surface->base)) {
surface->cgContext = NULL;
surface->cgContextBaseCTM = CGAffineTransformIdentity;
surface->base.is_clear = TRUE;
@@ -2237,10 +2208,9 @@ cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext,
unsigned int width,
unsigned int height)
{
- cairo_quartz_surface_t *surf;
-
- surf = _cairo_quartz_surface_create_internal (cgContext, CAIRO_CONTENT_COLOR_ALPHA,
- width, height);
+ cairo_quartz_surface_t *surf =
+ _cairo_quartz_surface_create_internal (cgContext, CAIRO_CONTENT_COLOR_ALPHA,
+ width, height);
if (likely (!surf->base.status))
CGContextRetain (cgContext);
@@ -2253,8 +2223,14 @@ cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext,
* @width: width of the surface, in pixels
* @height: height of the surface, in pixels
*
- * Creates a Quartz surface backed by a CGBitmap. The surface is
- * created using the Device RGB (or Device Gray, for A8) color space.
+ * Creates a Quartz surface backed by a CGBitmapContext using the main
+ * display's colorspace to avoid an expensive colorspace transform
+ * done serially on the CPU. This may produce slightly different
+ * colors from what's intended. Programs for which color management is
+ * important should create their own CGBitmapContext with a
+ * device-independent color space; most will expect Cairo to draw in
+ * sRGB and would use CGColorSpaceCreateWithName(kCGColorSpaceSRGB).
+ *
* All Cairo operations, including those that require software
* rendering, will succeed on this surface.
*
@@ -2286,7 +2262,7 @@ cairo_quartz_surface_create (cairo_format_t format,
if (format == CAIRO_FORMAT_ARGB32 ||
format == CAIRO_FORMAT_RGB24)
{
- cgColorspace = CGColorSpaceCreateDeviceRGB ();
+ cgColorspace = _cairo_quartz_create_color_space (NULL);
bitinfo = kCGBitmapByteOrder32Host;
if (format == CAIRO_FORMAT_ARGB32)
bitinfo |= kCGImageAlphaPremultipliedFirst;
@@ -2375,8 +2351,14 @@ cairo_quartz_surface_get_cg_context (cairo_surface_t *surface)
if (surface && _cairo_surface_is_quartz (surface)) {
cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t *) surface;
return quartz->cgContext;
- } else
- return NULL;
+ }
+
+ if (surface && _cairo_surface_is_quartz_image (surface)) {
+ cairo_quartz_image_surface_t *quartz = (cairo_quartz_image_surface_t *) surface;
+ return quartz->cgContext;
+ }
+
+ return NULL;
}
/**
@@ -2394,12 +2376,15 @@ _cairo_surface_is_quartz (const cairo_surface_t *surface)
}
cairo_surface_t*
-_cairo_quartz_snapshot_create (cairo_quartz_surface_t *surface)
+_cairo_quartz_snapshot_create (cairo_surface_t *surface)
{
cairo_quartz_snapshot_t *snapshot = NULL;
+ CGContextRef cgContext;
+ if (!surface || ! _is_quartz_surface (surface) || _cairo_quartz_is_zero_surface (surface))
+ return NULL;
- if (!surface || !_cairo_surface_is_quartz (&surface->base) || IS_EMPTY (surface) ||
- ! _cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext))
+ if (_cairo_surface_is_quartz (surface) &&
+ ! _cairo_quartz_is_cgcontext_bitmap_context (((cairo_quartz_surface_t*)surface)->cgContext))
return NULL;
snapshot = _cairo_malloc (sizeof (cairo_quartz_snapshot_t));
@@ -2408,10 +2393,13 @@ _cairo_quartz_snapshot_create (cairo_quartz_surface_t *surface)
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
memset (snapshot, 0, sizeof (cairo_quartz_snapshot_t));
+ cgContext = cairo_quartz_surface_get_cg_context (surface);
_cairo_surface_init (&snapshot->base,
&cairo_quartz_snapshot_backend,
NULL, CAIRO_CONTENT_COLOR_ALPHA, FALSE);
- snapshot->image = CGBitmapContextCreateImage (surface->cgContext);
+ snapshot->image = CGBitmapContextCreateImage (cgContext);
+ _cairo_surface_attach_snapshot (surface, &snapshot->base, NULL);
+ cairo_surface_destroy (&snapshot->base); // The surface has reffed the snapshot so we must unref it here.
return &snapshot->base;
}
@@ -2426,43 +2414,34 @@ _cairo_quartz_snapshot_finish (void *surface)
}
CGImageRef
-_cairo_quartz_surface_snapshot_get_image (cairo_quartz_surface_t *surface)
+_cairo_quartz_surface_snapshot_get_image (cairo_surface_t *surface)
{
- cairo_surface_t *snapshot =
- _cairo_surface_has_snapshot (&surface->base, &cairo_quartz_snapshot_backend);
+ cairo_surface_t *snapshot;
+ assert (_is_quartz_surface (surface));
+ snapshot =
+ _cairo_surface_has_snapshot (surface, &cairo_quartz_snapshot_backend);
if (unlikely (!snapshot))
{
snapshot = _cairo_quartz_snapshot_create (surface);
if (unlikely (!snapshot || cairo_surface_status (snapshot)))
return NULL;
- _cairo_surface_attach_snapshot (&surface->base, snapshot, NULL);
- cairo_surface_destroy (snapshot);
}
return CGImageRetain (((cairo_quartz_snapshot_t*)snapshot)->image);
}
-/* Debug stuff */
-
-#ifdef QUARTZ_DEBUG
-
void
-quartz_image_to_png (CGImageRef image, const char *dest)
+_cairo_quartz_image_to_png (CGImageRef image, const char *dest)
{
- static int sctr = 0;
- const char* image_name = "quartz-image";
- char pathbuf[100];
-
CFStringRef png_utti = CFSTR("public.png");
CFStringRef path;
CFURLRef url;
CGImageDestinationRef image_dest;
- memset (pathbuf, 0, sizeof (pathbuf));
- dest = dest ? dest : image_name;
- snprintf (pathbuf, sizeof (pathbuf), "%s/Desktop/%s%d.png",getenv ("HOME"), dest, sctr++);
- path = CFStringCreateWithCString (NULL, pathbuf, kCFStringEncodingUTF8);
+ if (!dest)
+ return;
+ path = CFStringCreateWithCString (NULL, dest, kCFStringEncodingUTF8);
url = CFURLCreateWithFileSystemPath (NULL, path, kCFURLPOSIXPathStyle, FALSE);
image_dest = CGImageDestinationCreateWithURL (url, png_utti, 1, NULL);
@@ -2473,20 +2452,20 @@ quartz_image_to_png (CGImageRef image, const char *dest)
CFRelease (path);
}
-void
-quartz_surface_to_png (cairo_quartz_surface_t *nq, const char *dest)
+cairo_status_t
+_cairo_quartz_surface_to_png (cairo_surface_t *abstract_surface, const char *dest)
{
CGImageRef image;
-
- if (nq->base.type != CAIRO_SURFACE_TYPE_QUARTZ) {
- fprintf (stderr, "** quartz_surface_to_png: surface %p isn't quartz!\n", nq);
- return;
+ cairo_quartz_surface_t *surface;
+ if (!(_cairo_surface_is_quartz (abstract_surface) &&
+ _cairo_quartz_is_cgcontext_bitmap_context (((cairo_quartz_surface_t*)abstract_surface)->cgContext))) {
+ return CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
}
- image = CGBitmapContextCreateImage (nq->cgContext);
- quartz_image_to_png (image, dest);
+ surface = (cairo_quartz_surface_t*)abstract_surface;
+ image = CGBitmapContextCreateImage (surface->cgContext);
+ _cairo_quartz_image_to_png (image, dest);
CGImageRelease (image);
+ return CAIRO_STATUS_SUCCESS;
}
-
-#endif /* QUARTZ_DEBUG */
diff --git a/src/cairo-recording-surface-private.h b/src/cairo-recording-surface-private.h
index 63b7a1de6..7d4de1ed9 100644
--- a/src/cairo-recording-surface-private.h
+++ b/src/cairo-recording-surface-private.h
@@ -1,3 +1,4 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
@@ -55,14 +56,19 @@ typedef enum {
} cairo_command_type_t;
typedef enum {
- CAIRO_RECORDING_REGION_ALL,
+ CAIRO_RECORDING_REGION_ALL = 0,
CAIRO_RECORDING_REGION_NATIVE,
CAIRO_RECORDING_REGION_IMAGE_FALLBACK
} cairo_recording_region_type_t;
+typedef enum {
+ CAIRO_RECORDING_REPLAY,
+ CAIRO_RECORDING_CREATE_REGIONS,
+ CAIRO_RECORDING_REPLAY_REGION
+} cairo_recording_replay_type_t;
+
typedef struct _cairo_command_header {
cairo_command_type_t type;
- cairo_recording_region_type_t region;
cairo_operator_t op;
cairo_rectangle_int_t extents;
cairo_clip_t *clip;
@@ -155,8 +161,27 @@ typedef struct _cairo_recording_surface {
struct bbtree *left, *right;
cairo_command_header_t *chain;
} bbtree;
+
+ /* The mutex protects modification to all subsequent fields. */
+ cairo_mutex_t mutex;
+
+ cairo_list_t region_array_list;
+
} cairo_recording_surface_t;
+typedef struct _cairo_recording_region_element {
+ cairo_recording_region_type_t region;
+ unsigned int source_id;
+ unsigned int mask_id;
+} cairo_recording_region_element_t;
+
+typedef struct _cairo_recording_region_array {
+ unsigned int id;
+ cairo_reference_count_t ref_count;
+ cairo_array_t regions; /* cairo_recording_region_element_t */
+ cairo_list_t link;
+} cairo_recording_regions_array_t;
+
slim_hidden_proto (cairo_recording_surface_create);
cairo_private cairo_int_status_t
@@ -173,26 +198,30 @@ _cairo_recording_surface_replay (cairo_surface_t *surface,
cairo_surface_t *target);
cairo_private cairo_status_t
-_cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surface,
- cairo_surface_t *target,
- const cairo_color_t *color);
+_cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surface,
+ cairo_surface_t *target,
+ const cairo_color_t *foreground_color,
+ cairo_bool_t *foreground_used);
cairo_private cairo_status_t
_cairo_recording_surface_replay_with_clip (cairo_surface_t *surface,
const cairo_matrix_t *surface_transform,
cairo_surface_t *target,
- const cairo_clip_t *target_clip);
+ const cairo_clip_t *target_clip,
+ cairo_bool_t surface_is_unbounded);
cairo_private cairo_status_t
-_cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
+_cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
+ unsigned int regions_id,
const cairo_matrix_t *surface_transform,
- cairo_surface_t *target,
- cairo_bool_t surface_is_unbounded);
+ cairo_surface_t *target,
+ cairo_bool_t surface_is_unbounded);
cairo_private cairo_status_t
_cairo_recording_surface_replay_region (cairo_surface_t *surface,
- const cairo_rectangle_int_t *surface_extents,
+ unsigned int regions_id,
+ const cairo_rectangle_int_t *surface_extents,
cairo_surface_t *target,
- cairo_recording_region_type_t region);
+ cairo_recording_region_type_t region);
cairo_private cairo_status_t
_cairo_recording_surface_get_bbox (cairo_recording_surface_t *recording,
@@ -210,4 +239,23 @@ _cairo_recording_surface_has_only_bilevel_alpha (cairo_recording_surface_t *surf
cairo_private cairo_bool_t
_cairo_recording_surface_has_only_op_over (cairo_recording_surface_t *surface);
+cairo_private cairo_status_t
+_cairo_recording_surface_region_array_attach (cairo_surface_t *surface,
+ unsigned int *id);
+
+cairo_private void
+_cairo_recording_surface_region_array_reference (cairo_surface_t *surface,
+ unsigned int id);
+
+cairo_private void
+_cairo_recording_surface_region_array_remove (cairo_surface_t *surface,
+ unsigned int id);
+
+cairo_private void
+_cairo_debug_print_recording_surface (FILE *file,
+ cairo_surface_t *surface,
+ unsigned int regions_id,
+ int indent,
+ cairo_bool_t recurse);
+
#endif /* CAIRO_RECORDING_SURFACE_H */
diff --git a/src/cairo-recording-surface.c b/src/cairo-recording-surface.c
index 065e62c46..2912f5ede 100644
--- a/src/cairo-recording-surface.c
+++ b/src/cairo-recording-surface.c
@@ -86,16 +86,12 @@
#include "cairo-default-context-private.h"
#include "cairo-error-private.h"
#include "cairo-image-surface-private.h"
+#include "cairo-list-inline.h"
#include "cairo-recording-surface-inline.h"
#include "cairo-surface-snapshot-inline.h"
#include "cairo-surface-wrapper-private.h"
#include "cairo-traps-private.h"
-typedef enum {
- CAIRO_RECORDING_REPLAY,
- CAIRO_RECORDING_CREATE_REGIONS
-} cairo_recording_replay_type_t;
-
typedef struct _cairo_recording_surface_replay_params {
const cairo_rectangle_int_t *surface_extents;
const cairo_matrix_t *surface_transform;
@@ -104,7 +100,9 @@ typedef struct _cairo_recording_surface_replay_params {
cairo_bool_t surface_is_unbounded;
cairo_recording_replay_type_t type;
cairo_recording_region_type_t region;
+ unsigned int regions_id;
const cairo_color_t *foreground_color;
+ cairo_bool_t foreground_used;
} cairo_recording_surface_replay_params_t;
static const cairo_surface_backend_t cairo_recording_surface_backend;
@@ -366,7 +364,10 @@ _cairo_recording_surface_create_bbtree (cairo_recording_surface_t *surface)
return CAIRO_STATUS_SUCCESS;
cleanup:
- bbtree_del (&surface->bbtree);
+ if (surface->bbtree.left)
+ bbtree_del (surface->bbtree.left);
+ if (surface->bbtree.right)
+ bbtree_del (surface->bbtree.right);
return status;
}
@@ -436,6 +437,10 @@ cairo_recording_surface_create (cairo_content_t content,
surface->has_bilevel_alpha = FALSE;
surface->has_only_op_over = FALSE;
+ CAIRO_MUTEX_INIT (surface->mutex);
+
+ cairo_list_init (&surface->region_array_list);
+
return &surface->base;
}
slim_hidden_def (cairo_recording_surface_create);
@@ -453,12 +458,88 @@ _cairo_recording_surface_create_similar (void *abstract_surface,
return cairo_recording_surface_create (content, &extents);
}
+static void
+destroy_pattern_region_array (const cairo_pattern_t *pattern,
+ unsigned int region_id)
+{
+ if (region_id != 0) {
+ if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
+ if (_cairo_surface_is_recording (surface_pattern->surface))
+ _cairo_recording_surface_region_array_remove (surface_pattern->surface, region_id);
+ }
+ }
+}
+
+static void
+_cairo_recording_surface_region_array_destroy (cairo_recording_surface_t *surface,
+ cairo_recording_regions_array_t *region_array)
+{
+ cairo_command_t **elements;
+ cairo_recording_region_element_t *region_elements;
+ int i, num_elements;
+
+ num_elements = surface->commands.num_elements;
+ elements = _cairo_array_index (&surface->commands, 0);
+ region_elements = _cairo_array_index (&region_array->regions, 0);
+ for (i = 0; i < num_elements; i++) {
+ cairo_command_t *command = elements[i];
+ cairo_recording_region_element_t *region_element = &region_elements[i];
+
+ switch (command->header.type) {
+ case CAIRO_COMMAND_PAINT:
+ destroy_pattern_region_array (&command->paint.source.base, region_element->source_id);
+ break;
+
+ case CAIRO_COMMAND_MASK:
+ destroy_pattern_region_array (&command->mask.source.base, region_element->source_id);
+ destroy_pattern_region_array (&command->mask.mask.base, region_element->mask_id);
+ break;
+
+ case CAIRO_COMMAND_STROKE:
+ destroy_pattern_region_array (&command->stroke.source.base, region_element->source_id);
+ break;
+
+ case CAIRO_COMMAND_FILL:
+ destroy_pattern_region_array (&command->fill.source.base, region_element->source_id);
+ break;
+
+ case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
+ destroy_pattern_region_array (&command->show_text_glyphs.source.base, region_element->source_id);
+ break;
+
+ case CAIRO_COMMAND_TAG:
+ break;
+
+ default:
+ ASSERT_NOT_REACHED;
+ }
+ }
+
+ _cairo_array_fini (&region_array->regions);
+ free (region_array);
+}
+
static cairo_status_t
_cairo_recording_surface_finish (void *abstract_surface)
{
cairo_recording_surface_t *surface = abstract_surface;
cairo_command_t **elements;
int i, num_elements;
+ cairo_recording_regions_array_t *region_array, *region_next;
+
+ /* Normally backend surfaces hold a reference to the surface as
+ * well as the region and free the region before the surface. So
+ * the regions should already be freed at this point but just in
+ * case we ensure the regions are freed before destroying the
+ * surface. */
+ cairo_list_foreach_entry_safe (region_array, region_next,
+ cairo_recording_regions_array_t,
+ &surface->region_array_list, link)
+ {
+ cairo_list_del (&region_array->link);
+ _cairo_recording_surface_region_array_destroy (surface, region_array);
+ }
num_elements = surface->commands.num_elements;
elements = _cairo_array_index (&surface->commands, 0);
@@ -614,7 +695,8 @@ _cairo_recording_surface_acquire_source_image (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
- assert (! surface->unbounded);
+ if (surface->unbounded)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
image = _cairo_image_surface_create_with_content (surface->base.content,
surface->extents.width,
surface->extents.height);
@@ -658,7 +740,6 @@ _command_init (cairo_recording_surface_t *surface,
command->type = type;
command->op = op;
- command->region = CAIRO_RECORDING_REGION_ALL;
command->extents = composite ? composite->unbounded : _cairo_empty_rectangle;
command->chain = NULL;
@@ -1153,6 +1234,14 @@ _cairo_recording_surface_tag (void *abstract_surface,
return status;
}
+static cairo_bool_t
+_cairo_recording_surface_supports_color_glyph (void *abstract_surface,
+ cairo_scaled_font_t *scaled_font,
+ unsigned long glyph_index)
+{
+ return TRUE;
+}
+
static void
_command_init_copy (cairo_recording_surface_t *surface,
cairo_command_header_t *dst,
@@ -1160,7 +1249,6 @@ _command_init_copy (cairo_recording_surface_t *surface,
{
dst->type = src->type;
dst->op = src->op;
- dst->region = CAIRO_RECORDING_REGION_ALL;
dst->extents = src->extents;
dst->chain = NULL;
@@ -1559,6 +1647,10 @@ _cairo_recording_surface_snapshot (void *abstract_other)
surface->has_bilevel_alpha = other->has_bilevel_alpha;
surface->has_only_op_over = other->has_only_op_over;
+ CAIRO_MUTEX_INIT (surface->mutex);
+
+ cairo_list_init (&surface->region_array_list);
+
_cairo_array_init (&surface->commands, sizeof (cairo_command_t *));
status = _cairo_recording_surface_copy (surface, other);
if (unlikely (status)) {
@@ -1622,8 +1714,126 @@ static const cairo_surface_backend_t cairo_recording_surface_backend = {
_cairo_recording_surface_show_text_glyphs,
NULL, /* get_supported_mime_types */
_cairo_recording_surface_tag,
+ _cairo_recording_surface_supports_color_glyph,
};
+static unsigned int
+_cairo_recording_surface_regions_allocate_unique_id (void)
+{
+ static cairo_atomic_int_t unique_id;
+
+#if CAIRO_NO_MUTEX
+ if (++unique_id == 0)
+ unique_id = 1;
+ return unique_id;
+#else
+ cairo_atomic_int_t old, id;
+
+ do {
+ old = _cairo_atomic_uint_get (&unique_id);
+ id = old + 1;
+ if (id == 0)
+ id = 1;
+ } while (! _cairo_atomic_uint_cmpxchg (&unique_id, old, id));
+
+ return id;
+#endif
+}
+
+static cairo_recording_regions_array_t *
+_cairo_recording_surface_region_array_find (cairo_recording_surface_t *surface,
+ unsigned int id)
+{
+ cairo_recording_regions_array_t *regions;
+
+ cairo_list_foreach_entry (regions, cairo_recording_regions_array_t,
+ &surface->region_array_list, link)
+ {
+ if (regions->id == id)
+ return regions;
+ }
+
+ return NULL;
+}
+
+/* Create and initialize a new #cairo_recording_regions_array_t. Attach
+ * it to the recording surface and return its id
+ */
+cairo_status_t
+_cairo_recording_surface_region_array_attach (cairo_surface_t *abstract_surface,
+ unsigned int *id)
+{
+ cairo_recording_regions_array_t *region_array;
+ cairo_recording_surface_t *surface = (cairo_recording_surface_t *) abstract_surface;
+
+ assert (_cairo_surface_is_recording (abstract_surface));
+
+ region_array = _cairo_malloc (sizeof (cairo_recording_regions_array_t));
+ if (region_array == NULL) {
+ *id = 0;
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ region_array->id = _cairo_recording_surface_regions_allocate_unique_id ();
+
+ CAIRO_REFERENCE_COUNT_INIT (&region_array->ref_count, 1);
+
+ _cairo_array_init (&region_array->regions, sizeof (cairo_recording_region_element_t));
+
+ CAIRO_MUTEX_LOCK (surface->mutex);
+ cairo_list_add (&region_array->link, &surface->region_array_list);
+ CAIRO_MUTEX_UNLOCK (surface->mutex);
+
+ *id = region_array->id;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_recording_surface_region_array_remove (cairo_surface_t *abstract_surface,
+ unsigned int id)
+{
+ cairo_recording_regions_array_t *region_array;
+ cairo_recording_surface_t *surface = (cairo_recording_surface_t *) abstract_surface;
+
+ if (id == 0)
+ return;
+
+ assert (_cairo_surface_is_recording (abstract_surface));
+
+ CAIRO_MUTEX_LOCK (surface->mutex);
+ region_array = _cairo_recording_surface_region_array_find (surface, id);
+ if (region_array) {
+ if (_cairo_reference_count_dec_and_test (&region_array->ref_count))
+ cairo_list_del (&region_array->link);
+ else
+ region_array = NULL;
+ }
+
+ CAIRO_MUTEX_UNLOCK (surface->mutex);
+
+ if (region_array)
+ _cairo_recording_surface_region_array_destroy (surface, region_array);
+}
+
+void
+_cairo_recording_surface_region_array_reference (cairo_surface_t *abstract_surface,
+ unsigned int id)
+{
+ cairo_recording_regions_array_t *region_array;
+ cairo_recording_surface_t *surface = (cairo_recording_surface_t *) abstract_surface;
+
+ assert (_cairo_surface_is_recording (abstract_surface));
+
+ CAIRO_MUTEX_LOCK (surface->mutex);
+ region_array = _cairo_recording_surface_region_array_find (surface, id);
+ if (region_array) {
+ _cairo_reference_count_inc (&region_array->ref_count);
+ }
+
+ CAIRO_MUTEX_UNLOCK (surface->mutex);
+}
+
cairo_int_status_t
_cairo_recording_surface_get_path (cairo_surface_t *abstract_surface,
cairo_path_fixed_t *path)
@@ -1797,8 +2007,8 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
{
cairo_surface_wrapper_t wrapper;
cairo_command_t **elements;
- cairo_bool_t replay_all =
- params->type == CAIRO_RECORDING_CREATE_REGIONS || params->region == CAIRO_RECORDING_REGION_ALL;
+ cairo_recording_regions_array_t *regions_array = NULL;
+ cairo_recording_region_element_t *region_elements = NULL;
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
cairo_rectangle_int_t extents;
cairo_bool_t use_indices = FALSE;
@@ -1819,6 +2029,11 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
assert (_cairo_surface_is_recording (&surface->base));
+ if (params->regions_id != 0) {
+ regions_array = _cairo_recording_surface_region_array_find (surface, params->regions_id);
+ assert (regions_array != NULL);
+ }
+
_cairo_surface_wrapper_init (&wrapper, params->target);
if (params->surface_extents)
_cairo_surface_wrapper_intersect_extents (&wrapper, params->surface_extents);
@@ -1829,7 +2044,11 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
}
_cairo_surface_wrapper_set_inverse_transform (&wrapper, params->surface_transform);
_cairo_surface_wrapper_set_clip (&wrapper, params->target_clip);
- _cairo_surface_wrapper_set_foreground_color (&wrapper, params->foreground_color);
+
+ if (params->foreground_color) {
+ params->target->foreground_source = _cairo_pattern_create_solid (params->foreground_color);
+ params->target->foreground_used = FALSE;
+ }
/* Compute the extents of the target clip in recorded device space */
if (! _cairo_surface_wrapper_get_target_extents (&wrapper, params->surface_is_unbounded, &extents))
@@ -1839,18 +2058,48 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
surface->has_only_op_over = TRUE;
num_elements = surface->commands.num_elements;
+ if (regions_array) {
+ if (params->type == CAIRO_RECORDING_CREATE_REGIONS) {
+ /* Re-running create regions with the same region id is not supported. */
+ assert (_cairo_array_num_elements (&regions_array->regions) == 0);
+ void *array_elems;
+ status = _cairo_array_allocate (&regions_array->regions, num_elements, &array_elems);
+ if (unlikely (status))
+ return status;
+
+ /* Set regions to CAIRO_RECORDING_REGION_ALL and ids to 0 */
+ memset (array_elems, 0, num_elements * sizeof (cairo_recording_region_element_t));
+ } else {
+ assert (_cairo_array_num_elements (&regions_array->regions) == num_elements);
+ }
+ }
+
elements = _cairo_array_index (&surface->commands, 0);
+ if (regions_array)
+ region_elements = _cairo_array_index (&regions_array->regions, 0);
+
if (extents.width < r->width || extents.height < r->height) {
num_elements =
_cairo_recording_surface_get_visible_commands (surface, &extents);
use_indices = num_elements != surface->commands.num_elements;
}
+ cairo_bool_t target_is_analysis = _cairo_surface_is_analysis (params->target);
+
for (i = 0; i < num_elements; i++) {
cairo_command_t *command = elements[use_indices ? surface->indices[i] : i];
+ cairo_recording_region_element_t *region_element = NULL;
+ unsigned int source_region_id = 0;
+ unsigned int mask_region_id = 0;
+
+ if (region_elements)
+ region_element = &region_elements[use_indices ? surface->indices[i] : i];
- if (! replay_all && command->header.region != params->region)
+ if (region_element && params->type == CAIRO_RECORDING_REPLAY_REGION &&
+ region_element->region != params->region)
+ {
continue;
+ }
if (! _cairo_rectangle_intersects (&extents, &command->header.extents)) {
if (command->header.type != CAIRO_COMMAND_TAG)
@@ -1859,22 +2108,35 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
switch (command->header.type) {
case CAIRO_COMMAND_PAINT:
+ if (region_element)
+ source_region_id = region_element->source_id;
+
status = _cairo_surface_wrapper_paint (&wrapper,
command->header.op,
&command->paint.source.base,
+ source_region_id,
command->header.clip);
if (params->type == CAIRO_RECORDING_CREATE_REGIONS) {
_cairo_recording_surface_merge_source_attributes (surface,
command->header.op,
&command->paint.source.base);
+ if (region_element && target_is_analysis)
+ region_element->source_id = _cairo_analysis_surface_get_source_region_id (params->target);
}
break;
case CAIRO_COMMAND_MASK:
+ if (region_element) {
+ source_region_id = region_element->source_id;
+ mask_region_id = region_element->mask_id;
+ }
+
status = _cairo_surface_wrapper_mask (&wrapper,
command->header.op,
&command->mask.source.base,
+ source_region_id,
&command->mask.mask.base,
+ mask_region_id,
command->header.clip);
if (params->type == CAIRO_RECORDING_CREATE_REGIONS) {
_cairo_recording_surface_merge_source_attributes (surface,
@@ -1883,13 +2145,21 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
_cairo_recording_surface_merge_source_attributes (surface,
command->header.op,
&command->mask.mask.base);
+ if (region_element && target_is_analysis) {
+ region_element->source_id = _cairo_analysis_surface_get_source_region_id (params->target);
+ region_element->mask_id = _cairo_analysis_surface_get_mask_region_id (params->target);
+ }
}
break;
case CAIRO_COMMAND_STROKE:
+ if (region_element)
+ source_region_id = region_element->source_id;
+
status = _cairo_surface_wrapper_stroke (&wrapper,
command->header.op,
&command->stroke.source.base,
+ source_region_id,
&command->stroke.path,
&command->stroke.style,
&command->stroke.ctm,
@@ -1901,23 +2171,39 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
_cairo_recording_surface_merge_source_attributes (surface,
command->header.op,
&command->stroke.source.base);
+ if (region_element && target_is_analysis)
+ region_element->source_id = _cairo_analysis_surface_get_source_region_id (params->target);
}
break;
case CAIRO_COMMAND_FILL:
status = CAIRO_INT_STATUS_UNSUPPORTED;
- if (_cairo_surface_wrapper_has_fill_stroke (&wrapper)) {
- cairo_command_t *stroke_command;
+ if (region_element)
+ source_region_id = region_element->source_id;
- stroke_command = NULL;
- if (params->type != CAIRO_RECORDING_CREATE_REGIONS && i < num_elements - 1)
+ if (_cairo_surface_wrapper_has_fill_stroke (&wrapper)) {
+ cairo_command_t *stroke_command = NULL;
+ cairo_recording_region_element_t *stroke_region_element = NULL;
+ unsigned stroke_region_id = 0;
+
+ /* The analysis surface does not implement
+ * fill_stroke. When creating regions the fill and
+ * stroke commands are tested separately.
+ */
+ if (params->type != CAIRO_RECORDING_CREATE_REGIONS && i < num_elements - 1) {
stroke_command = elements[i + 1];
+ if (region_elements)
+ stroke_region_element = &region_elements[i + 1];
+ }
- if (stroke_command != NULL &&
- params->type == CAIRO_RECORDING_REPLAY &&
+ if (stroke_region_element)
+ stroke_region_id = stroke_region_element->source_id;
+
+ if (stroke_command && stroke_region_element &&
+ params->type == CAIRO_RECORDING_REPLAY_REGION &&
params->region != CAIRO_RECORDING_REGION_ALL)
{
- if (stroke_command->header.region != params->region)
+ if (stroke_region_element->region != params->region)
stroke_command = NULL;
}
@@ -1931,12 +2217,14 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
status = _cairo_surface_wrapper_fill_stroke (&wrapper,
command->header.op,
&command->fill.source.base,
+ source_region_id,
command->fill.fill_rule,
command->fill.tolerance,
command->fill.antialias,
&command->fill.path,
stroke_command->header.op,
&stroke_command->stroke.source.base,
+ stroke_region_id,
&stroke_command->stroke.style,
&stroke_command->stroke.ctm,
&stroke_command->stroke.ctm_inverse,
@@ -1958,6 +2246,7 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
status = _cairo_surface_wrapper_fill (&wrapper,
command->header.op,
&command->fill.source.base,
+ source_region_id,
&command->fill.path,
command->fill.fill_rule,
command->fill.tolerance,
@@ -1967,14 +2256,20 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
_cairo_recording_surface_merge_source_attributes (surface,
command->header.op,
&command->fill.source.base);
+ if (region_element && target_is_analysis)
+ region_element->source_id = _cairo_analysis_surface_get_source_region_id (params->target);
}
}
break;
case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
+ if (region_element)
+ source_region_id = region_element->source_id;
+
status = _cairo_surface_wrapper_show_text_glyphs (&wrapper,
command->header.op,
&command->show_text_glyphs.source.base,
+ source_region_id,
command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
command->show_text_glyphs.glyphs, command->show_text_glyphs.num_glyphs,
command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
@@ -1985,6 +2280,9 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
_cairo_recording_surface_merge_source_attributes (surface,
command->header.op,
&command->show_text_glyphs.source.base);
+ if (region_element && target_is_analysis)
+ region_element->source_id = _cairo_analysis_surface_get_source_region_id (params->target);
+
}
break;
@@ -2003,11 +2301,11 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
status = CAIRO_INT_STATUS_SUCCESS;
- if (params->type == CAIRO_RECORDING_CREATE_REGIONS && command->header.region != CAIRO_RECORDING_REGION_NATIVE) {
+ if (params->type == CAIRO_RECORDING_CREATE_REGIONS && region_element) {
if (status == CAIRO_INT_STATUS_SUCCESS) {
- command->header.region = CAIRO_RECORDING_REGION_NATIVE;
+ region_element->region = CAIRO_RECORDING_REGION_NATIVE;
} else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) {
- command->header.region = CAIRO_RECORDING_REGION_IMAGE_FALLBACK;
+ region_element->region = CAIRO_RECORDING_REGION_IMAGE_FALLBACK;
status = CAIRO_INT_STATUS_SUCCESS;
} else {
assert (_cairo_int_status_is_error (status));
@@ -2019,6 +2317,12 @@ _cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface,
}
done:
+ if (params->foreground_color) {
+ cairo_pattern_destroy (params->target->foreground_source);
+ params->target->foreground_source = NULL;
+ params->foreground_used = params->target->foreground_used;
+ }
+
_cairo_surface_wrapper_fini (&wrapper);
return _cairo_surface_set_error (&surface->base, status);
}
@@ -2030,7 +2334,7 @@ _cairo_recording_surface_replay_one (cairo_recording_surface_t *surface,
{
cairo_surface_wrapper_t wrapper;
cairo_command_t **elements, *command;
- cairo_int_status_t status;
+ cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
if (unlikely (surface->base.status))
return surface->base.status;
@@ -2059,6 +2363,7 @@ _cairo_recording_surface_replay_one (cairo_recording_surface_t *surface,
status = _cairo_surface_wrapper_paint (&wrapper,
command->header.op,
&command->paint.source.base,
+ 0,
command->header.clip);
break;
@@ -2066,7 +2371,9 @@ _cairo_recording_surface_replay_one (cairo_recording_surface_t *surface,
status = _cairo_surface_wrapper_mask (&wrapper,
command->header.op,
&command->mask.source.base,
+ 0,
&command->mask.mask.base,
+ 0,
command->header.clip);
break;
@@ -2074,6 +2381,7 @@ _cairo_recording_surface_replay_one (cairo_recording_surface_t *surface,
status = _cairo_surface_wrapper_stroke (&wrapper,
command->header.op,
&command->stroke.source.base,
+ 0,
&command->stroke.path,
&command->stroke.style,
&command->stroke.ctm,
@@ -2087,6 +2395,7 @@ _cairo_recording_surface_replay_one (cairo_recording_surface_t *surface,
status = _cairo_surface_wrapper_fill (&wrapper,
command->header.op,
&command->fill.source.base,
+ 0,
&command->fill.path,
command->fill.fill_rule,
command->fill.tolerance,
@@ -2098,6 +2407,7 @@ _cairo_recording_surface_replay_one (cairo_recording_surface_t *surface,
status = _cairo_surface_wrapper_show_text_glyphs (&wrapper,
command->header.op,
&command->show_text_glyphs.source.base,
+ 0,
command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
command->show_text_glyphs.glyphs, command->show_text_glyphs.num_glyphs,
command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
@@ -2145,17 +2455,20 @@ _cairo_recording_surface_replay (cairo_surface_t *surface,
params.surface_is_unbounded = FALSE;
params.type = CAIRO_RECORDING_REPLAY;
params.region = CAIRO_RECORDING_REGION_ALL;
+ params.regions_id = 0;
params.foreground_color = NULL;
return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, &params);
}
cairo_status_t
-_cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surface,
- cairo_surface_t *target,
- const cairo_color_t *color)
+_cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surface,
+ cairo_surface_t *target,
+ const cairo_color_t *foreground_color,
+ cairo_bool_t *foreground_used)
{
cairo_recording_surface_replay_params_t params;
+ cairo_status_t status;
params.surface_extents = NULL;
params.surface_transform = NULL;
@@ -2164,16 +2477,22 @@ _cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surface,
params.surface_is_unbounded = FALSE;
params.type = CAIRO_RECORDING_REPLAY;
params.region = CAIRO_RECORDING_REGION_ALL;
- params.foreground_color = color;
+ params.regions_id = 0;
+ params.foreground_color = foreground_color;
+ params.foreground_used = FALSE;
- return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, &params);
+ status = _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, &params);
+ *foreground_used = params.foreground_used;
+
+ return status;
}
cairo_status_t
_cairo_recording_surface_replay_with_clip (cairo_surface_t *surface,
const cairo_matrix_t *surface_transform,
cairo_surface_t *target,
- const cairo_clip_t *target_clip)
+ const cairo_clip_t *target_clip,
+ cairo_bool_t surface_is_unbounded)
{
cairo_recording_surface_replay_params_t params;
@@ -2181,9 +2500,10 @@ _cairo_recording_surface_replay_with_clip (cairo_surface_t *surface,
params.surface_transform = surface_transform;
params.target = target;
params.target_clip = target_clip;
- params.surface_is_unbounded = FALSE;
+ params.surface_is_unbounded = surface_is_unbounded;
params.type = CAIRO_RECORDING_REPLAY;
params.region = CAIRO_RECORDING_REGION_ALL;
+ params.regions_id = 0;
params.foreground_color = NULL;
return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, &params);
@@ -2197,6 +2517,7 @@ _cairo_recording_surface_replay_with_clip (cairo_surface_t *surface,
*/
cairo_status_t
_cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
+ unsigned int regions_id,
const cairo_matrix_t *surface_transform,
cairo_surface_t *target,
cairo_bool_t surface_is_unbounded)
@@ -2210,6 +2531,7 @@ _cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
params.surface_is_unbounded = surface_is_unbounded;
params.type = CAIRO_RECORDING_CREATE_REGIONS;
params.region = CAIRO_RECORDING_REGION_ALL;
+ params.regions_id = regions_id;
params.foreground_color = NULL;
return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, &params);
@@ -2217,6 +2539,7 @@ _cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
cairo_status_t
_cairo_recording_surface_replay_region (cairo_surface_t *surface,
+ unsigned int regions_id,
const cairo_rectangle_int_t *surface_extents,
cairo_surface_t *target,
cairo_recording_region_type_t region)
@@ -2228,8 +2551,9 @@ _cairo_recording_surface_replay_region (cairo_surface_t *surface,
params.target = target;
params.target_clip = NULL;
params.surface_is_unbounded = FALSE;
- params.type = CAIRO_RECORDING_REPLAY;
+ params.type = CAIRO_RECORDING_REPLAY_REGION;
params.region = region;
+ params.regions_id = regions_id;
params.foreground_color = NULL;
return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, &params);
@@ -2245,7 +2569,7 @@ _recording_surface_get_ink_bbox (cairo_recording_surface_t *surface,
cairo_status_t status;
null_surface = _cairo_null_surface_create (surface->base.content);
- analysis_surface = _cairo_analysis_surface_create (null_surface);
+ analysis_surface = _cairo_analysis_surface_create (null_surface, FALSE);
cairo_surface_destroy (null_surface);
status = analysis_surface->status;
@@ -2309,6 +2633,7 @@ DONE:
if (height)
*height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y);
}
+slim_hidden_def (cairo_recording_surface_ink_extents);
cairo_status_t
_cairo_recording_surface_get_bbox (cairo_recording_surface_t *surface,
@@ -2376,3 +2701,186 @@ _cairo_recording_surface_has_only_op_over (cairo_recording_surface_t *surface)
{
return surface->has_only_op_over;
}
+
+static void
+print_indent (FILE *file, int indent)
+{
+ fprintf (file, "%*s", indent * 2, "");
+}
+
+static void
+print_pattern (FILE *file,
+ const cairo_pattern_t *pattern,
+ unsigned int region_id,
+ int indent,
+ cairo_bool_t recurse)
+{
+ switch (pattern->type) {
+ case CAIRO_PATTERN_TYPE_SOLID: {
+ cairo_solid_pattern_t *p = (cairo_solid_pattern_t *) pattern;
+ if (pattern->is_foreground_marker) {
+ fprintf (file, "solid foreground\n");
+ } else {
+ fprintf (file, "solid rgba: %f %f %f %f\n",
+ p->color.red,
+ p->color.green,
+ p->color.blue,
+ p->color.alpha);
+ }
+ } break;
+ case CAIRO_PATTERN_TYPE_SURFACE: {
+ cairo_surface_pattern_t *p = (cairo_surface_pattern_t *) pattern;
+ fprintf (file, "surface ");
+ if (p->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
+ fprintf (file, "recording id: %d\n", p->surface->unique_id);
+ if (recurse) {
+ _cairo_debug_print_recording_surface (file, p->surface,
+ region_id,
+ indent + 1, recurse);
+ }
+ } else if (p->surface->type == CAIRO_SURFACE_TYPE_IMAGE) {
+ cairo_image_surface_t *image = (cairo_image_surface_t *)p->surface;
+ fprintf (file, "image format: ");
+ switch (image->format) {
+ case CAIRO_FORMAT_INVALID: fputs ("INVALID", file); break;
+ case CAIRO_FORMAT_ARGB32: fputs ("ARGB32", file); break;
+ case CAIRO_FORMAT_RGB24: fputs ("RGB24", file); break;
+ case CAIRO_FORMAT_A8: fputs ("A8", file); break;
+ case CAIRO_FORMAT_A1: fputs ("A1", file); break;
+ case CAIRO_FORMAT_RGB16_565: fputs ("RGB16_565", file); break;
+ case CAIRO_FORMAT_RGB30: fputs ("RGB30", file); break;
+ case CAIRO_FORMAT_RGB96F: fputs ("RGB96F", file); break;
+ case CAIRO_FORMAT_RGBA128F: fputs ("RGBA128F", file); break;
+ }
+ fprintf (file, " width: %d height: %d\n", image->width, image->height);
+ } else {
+ fprintf (file, "type %d\n", p->surface->type);
+ }
+ } break;
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ fprintf (file, "linear\n");
+ break;
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ fprintf (file, "radial\n");
+ break;
+ case CAIRO_PATTERN_TYPE_MESH:
+ fprintf (file, "mesh\n");
+ break;
+ case CAIRO_PATTERN_TYPE_RASTER_SOURCE:
+ fprintf (file, "raster\n");
+ break;
+ }
+}
+
+void
+_cairo_debug_print_recording_surface (FILE *file,
+ cairo_surface_t *surface,
+ unsigned int regions_id,
+ int indent,
+ cairo_bool_t recurse)
+{
+ cairo_command_t **elements;
+ cairo_recording_region_element_t *region_elements = NULL;
+ unsigned int i, num_elements;
+ cairo_recording_surface_t *recording_surface;
+ cairo_surface_t *free_me = NULL;
+ char common[100];
+
+ if (_cairo_surface_is_snapshot (surface))
+ free_me = surface = _cairo_surface_snapshot_get_target (surface);
+
+ assert (_cairo_surface_is_recording (surface));
+ recording_surface = (cairo_recording_surface_t *)surface;
+
+ print_indent (file, indent);
+ indent++;
+ fprintf(file, "recording surface id: %d regions id: %d\n", recording_surface->base.unique_id, regions_id);
+ num_elements = recording_surface->commands.num_elements;
+ elements = _cairo_array_index (&recording_surface->commands, 0);
+
+ if (regions_id != 0) {
+ cairo_recording_regions_array_t *regions_array;
+ regions_array = _cairo_recording_surface_region_array_find (recording_surface, regions_id);
+ assert (regions_array != NULL);
+ assert (_cairo_array_num_elements (&regions_array->regions) == num_elements);
+ region_elements = _cairo_array_index (&regions_array->regions, 0);
+ }
+
+ for (i = 0; i < num_elements; i++) {
+ cairo_command_t *command = elements[i];
+ unsigned int source_region_id = 0;
+ unsigned int mask_region_id = 0;
+
+ common[0] = 0;
+ if (region_elements) {
+ cairo_recording_region_element_t *region_element = &region_elements[i];
+ strcpy (common, "region: ");
+ switch (region_element->region) {
+ case CAIRO_RECORDING_REGION_ALL: strcat (common, "all"); break;
+ case CAIRO_RECORDING_REGION_NATIVE: strcat (common, "native"); break;
+ case CAIRO_RECORDING_REGION_IMAGE_FALLBACK: strcat (common, "fallback"); break;
+ }
+ source_region_id = region_element->source_id;
+ mask_region_id = region_element->mask_id;
+ }
+ sprintf (common + strlen(common), " op: %s", _cairo_debug_operator_to_string (command->header.op));
+
+ switch (command->header.type) {
+ case CAIRO_COMMAND_PAINT:
+ print_indent (file, indent);
+ fprintf(file, "%d PAINT %s source: ", i, common);
+ print_pattern (file, &command->paint.source.base, source_region_id, indent + 1, recurse);
+ break;
+
+ case CAIRO_COMMAND_MASK:
+ print_indent (file, indent);
+ fprintf(file, "%d MASK %s\n", i, common);
+ print_indent (file, indent + 1);
+ fprintf(file, "source: ");
+ print_pattern (file, &command->mask.source.base, source_region_id, indent + 1, recurse);
+ print_indent (file, indent + 1);
+ fprintf(file, "mask: ");
+ print_pattern (file, &command->mask.mask.base, mask_region_id, indent + 1, recurse);
+ break;
+
+ case CAIRO_COMMAND_STROKE:
+ print_indent (file, indent);
+ fprintf(file, "%d STROKE %s source:", i, common);
+ print_pattern (file, &command->stroke.source.base, source_region_id, indent + 1, recurse);
+ break;
+
+ case CAIRO_COMMAND_FILL:
+ print_indent (file, indent);
+ fprintf(file, "%d FILL %s source: ", i, common);
+ print_pattern (file, &command->fill.source.base, source_region_id, indent + 1, recurse);
+ break;
+
+ case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
+ print_indent (file, indent);
+ fprintf(file, "%d SHOW_TEXT_GLYPHS %s font_type: ", i, common);
+ switch (command->show_text_glyphs.scaled_font->backend->type) {
+ case CAIRO_FONT_TYPE_TOY: fputs ("toy", file); break;
+ case CAIRO_FONT_TYPE_FT: fputs ("ft", file); break;
+ case CAIRO_FONT_TYPE_WIN32: fputs ("win32", file); break;
+ case CAIRO_FONT_TYPE_QUARTZ: fputs ("quartz", file); break;
+ case CAIRO_FONT_TYPE_USER: fputs ("user", file); break;
+ case CAIRO_FONT_TYPE_DWRITE: fputs ("dwrite", file); break;
+ }
+ fprintf (file, " glyphs:");
+ for (unsigned j = 0; j < command->show_text_glyphs.num_glyphs; j++)
+ fprintf (file, " %ld", command->show_text_glyphs.glyphs[j].index);
+ fprintf (file, " source:");
+ print_pattern (file, &command->show_text_glyphs.source.base, source_region_id, indent + 1, recurse);
+ break;
+
+ case CAIRO_COMMAND_TAG:
+ print_indent (file, indent);
+ fprintf(file, "%d TAG\n", i);
+ break;
+
+ default:
+ ASSERT_NOT_REACHED;
+ }
+ }
+ cairo_surface_destroy (free_me);
+}
diff --git a/src/cairo-region.c b/src/cairo-region.c
index eb78cf4a8..d38f50d92 100644
--- a/src/cairo-region.c
+++ b/src/cairo-region.c
@@ -112,6 +112,7 @@ _cairo_region_create_in_error (cairo_status_t status)
case CAIRO_STATUS_WIN32_GDI_ERROR:
case CAIRO_STATUS_TAG_ERROR:
case CAIRO_STATUS_DWRITE_ERROR:
+ case CAIRO_STATUS_SVG_FONT_ERROR:
default:
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_region_t *) &_cairo_region_nil;
diff --git a/src/cairo-scaled-font-private.h b/src/cairo-scaled-font-private.h
index 6fd772bdb..64abbe0f5 100644
--- a/src/cairo-scaled-font-private.h
+++ b/src/cairo-scaled-font-private.h
@@ -107,7 +107,7 @@ struct _cairo_scaled_font {
cairo_font_extents_t fs_extents; /* font space */
/* The mutex protects modification to all subsequent fields. */
- cairo_mutex_t mutex;
+ cairo_recursive_mutex_t mutex;
cairo_hash_table_t *glyphs;
cairo_list_t glyph_pages;
@@ -149,8 +149,12 @@ struct _cairo_scaled_glyph {
cairo_list_t dev_privates;
cairo_color_t foreground_color; /* only used for color glyphs */
- /* TRUE if the color_surface required the foreground_color to render. */
- unsigned uses_foreground_color : 1;
+
+ /* TRUE if the recording_surface used the foreground_source to render. */
+ unsigned recording_uses_foreground_color : 1;
+
+ /* TRUE if the recording surface uses the foreground marker. */
+ unsigned recording_uses_foreground_marker : 1;
/* TRUE if color_glyph specifies if glyph is color or non color, FALSE if glyph color type unknown. */
unsigned color_glyph_set : 1;
diff --git a/src/cairo-scaled-font-subsets-private.h b/src/cairo-scaled-font-subsets-private.h
index 5b531d298..2599bb6c3 100644
--- a/src/cairo-scaled-font-subsets-private.h
+++ b/src/cairo-scaled-font-subsets-private.h
@@ -204,7 +204,7 @@ _cairo_scaled_font_subsets_enable_latin_subset (cairo_scaled_font_subsets_t *fon
* @x_advance, @y_advance: When @is_scaled is true, @x_advance and @y_advance contain
* the x and y advance for the mapped glyph in device space.
* When @is_scaled is false, @x_advance and @y_advance contain the x and y advance for
- * the the mapped glyph from an unhinted 1 point font.
+ * the mapped glyph from an unhinted 1 point font.
* @utf8_is_mapped: If true the utf8 string provided to _cairo_scaled_font_subsets_map_glyph()
* is (or already was) the utf8 string mapped to this glyph. If false the glyph is already
* mapped to a different utf8 string.
@@ -297,41 +297,6 @@ _cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t
void *closure);
/**
- * _cairo_scaled_font_subsets_foreach_user:
- * @font_subsets: a #cairo_scaled_font_subsets_t
- * @font_subset_callback: a function to be called for each font subset
- * @closure: closure data for the callback function
- *
- * Iterate over each unique scaled font subset as created by calls to
- * _cairo_scaled_font_subsets_map_glyph(). A subset is determined by
- * unique pairs of (font_id, subset_id) as returned by
- * _cairo_scaled_font_subsets_map_glyph().
- *
- * For each subset, @font_subset_callback will be called and will be
- * provided with both a #cairo_scaled_font_subset_t object containing
- * all the glyphs in the subset as well as the value of @closure.
- *
- * The #cairo_scaled_font_subset_t object contains the scaled_font,
- * the font_id, and the subset_id corresponding to all glyphs
- * belonging to the subset. In addition, it contains an array providing
- * a mapping between subset glyph indices and the original scaled font
- * glyph indices.
- *
- * The index of the array corresponds to subset_glyph_index values
- * returned by _cairo_scaled_font_subsets_map_glyph() while the
- * values of the array correspond to the scaled_font_glyph_index
- * values passed as input to the same function.
- *
- * Return value: %CAIRO_STATUS_SUCCESS if successful, or a non-zero
- * value indicating an error. Possible errors include
- * %CAIRO_STATUS_NO_MEMORY.
- **/
-cairo_private cairo_status_t
-_cairo_scaled_font_subsets_foreach_user (cairo_scaled_font_subsets_t *font_subsets,
- cairo_scaled_font_subset_callback_func_t font_subset_callback,
- void *closure);
-
-/**
* _cairo_scaled_font_subset_create_glyph_names:
* @font_subsets: a #cairo_scaled_font_subsets_t
*
diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c
index 94a7aae26..2a9e8144c 100644
--- a/src/cairo-scaled-font-subsets.c
+++ b/src/cairo-scaled-font-subsets.c
@@ -1,3 +1,4 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2003 University of Southern California
@@ -61,7 +62,6 @@ typedef enum {
typedef enum {
CAIRO_SUBSETS_FOREACH_UNSCALED,
CAIRO_SUBSETS_FOREACH_SCALED,
- CAIRO_SUBSETS_FOREACH_USER
} cairo_subsets_foreach_type_t;
typedef struct _cairo_sub_font {
@@ -69,7 +69,6 @@ typedef struct _cairo_sub_font {
cairo_bool_t is_scaled;
cairo_bool_t is_composite;
- cairo_bool_t is_user;
cairo_bool_t use_latin_subset;
cairo_bool_t reserve_notdef;
cairo_scaled_font_subsets_t *parent;
@@ -283,8 +282,7 @@ _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent,
sub_font->is_scaled = is_scaled;
sub_font->is_composite = is_composite;
- sub_font->is_user = _cairo_font_face_is_user (scaled_font->font_face);
- sub_font->reserve_notdef = !sub_font->is_user;
+ sub_font->reserve_notdef = !sub_font->is_scaled;
_cairo_sub_font_init_key (sub_font, scaled_font);
sub_font->parent = parent;
@@ -294,7 +292,7 @@ _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent,
sub_font->use_latin_subset = parent->use_latin_subset;
/* latin subsets of Type 3 and CID CFF fonts are not supported */
- if (sub_font->is_user || sub_font->is_scaled ||
+ if (sub_font->is_scaled ||
_cairo_cff_scaled_font_is_cid_cff (scaled_font) )
{
sub_font->use_latin_subset = FALSE;
@@ -404,12 +402,10 @@ _cairo_sub_font_glyph_lookup_unicode (cairo_scaled_font_t *scaled_font,
if (unicode != (uint32_t) -1) {
len = _cairo_ucs4_to_utf8 (unicode, buf);
if (len > 0) {
- *utf8_out = _cairo_malloc (len + 1);
- if (unlikely (*utf8_out == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ *utf8_out = _cairo_strndup (buf, len);
+ if (unlikely (*utf8_out == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- memcpy (*utf8_out, buf, len);
- (*utf8_out)[len] = 0;
*utf8_len_out = len;
}
}
@@ -441,12 +437,10 @@ _cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
}
} else {
/* No existing mapping. Use the requested mapping */
- sub_font_glyph->utf8 = _cairo_malloc (utf8_len + 1);
- if (unlikely (sub_font_glyph->utf8 == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ sub_font_glyph->utf8 = _cairo_strndup (utf8, utf8_len);
+ if (unlikely (sub_font_glyph->utf8 == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
- memcpy (sub_font_glyph->utf8, utf8, utf8_len);
- sub_font_glyph->utf8[utf8_len] = 0;
sub_font_glyph->utf8_len = utf8_len;
*is_mapped = TRUE;
}
@@ -612,25 +606,22 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
if (ucs4_len == 1) {
font_unicode = ucs4[0];
free (font_utf8);
- font_utf8 = _cairo_malloc (text_utf8_len + 1);
- if (font_utf8 == NULL) {
- free (ucs4);
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ font_utf8 = _cairo_strndup (text_utf8, text_utf8_len);
+ if (font_utf8 == NULL) {
+ free (ucs4);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
- memcpy (font_utf8, text_utf8, text_utf8_len);
- font_utf8[text_utf8_len] = 0;
font_utf8_len = text_utf8_len;
}
free (ucs4);
}
}
- /* If glyph is in the winansi encoding and font is not a user
+ /* If glyph is in the winansi encoding and font is not a scaled
* font, put glyph in the latin subset. */
is_latin = FALSE;
latin_character = -1;
- if (sub_font->use_latin_subset &&
- (! _cairo_font_face_is_user (sub_font->scaled_font->font_face)))
+ if (sub_font->use_latin_subset && !sub_font->is_scaled)
{
latin_character = _cairo_unicode_to_winansi (font_unicode);
if (latin_character > 0)
@@ -844,6 +835,9 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
cairo_int_status_t status;
int max_glyphs;
cairo_bool_t type1_font;
+ cairo_bool_t has_path;
+ cairo_bool_t has_color;
+ cairo_bool_t is_user;
/* Lookup glyph in unscaled subsets */
if (subsets->type != CAIRO_SUBSETS_SCALED) {
@@ -877,30 +871,47 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
/* Glyph not found. Determine whether the glyph is outline or
* bitmap and add to the appropriate subset.
- *
- * glyph_index 0 (the .notdef glyph) is a special case. Some fonts
+ */
+ is_user = _cairo_font_face_is_user (scaled_font->font_face);
+ _cairo_scaled_font_freeze_cache (scaled_font);
+ /* Check if glyph is color */
+ status = _cairo_scaled_glyph_lookup (scaled_font,
+ scaled_font_glyph_index,
+ CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE,
+ NULL, /* foreground color */
+ &scaled_glyph);
+ has_color = (status == CAIRO_INT_STATUS_SUCCESS);
+
+ /* Check if glyph has a path */
+ status = _cairo_scaled_glyph_lookup (scaled_font,
+ scaled_font_glyph_index,
+ CAIRO_SCALED_GLYPH_INFO_PATH,
+ NULL, /* foreground color */
+ &scaled_glyph);
+ has_path = (status == CAIRO_INT_STATUS_SUCCESS);
+
+ /* glyph_index 0 (the .notdef glyph) is a special case. Some fonts
* will return CAIRO_INT_STATUS_UNSUPPORTED when doing a
* _scaled_glyph_lookup(_GLYPH_INFO_PATH). Type1-fallback creates
* empty glyphs in this case so we can put the glyph in a unscaled
- * subset. */
- if (scaled_font_glyph_index == 0 ||
- _cairo_font_face_is_user (scaled_font->font_face)) {
- status = CAIRO_STATUS_SUCCESS;
- } else {
- _cairo_scaled_font_freeze_cache (scaled_font);
- status = _cairo_scaled_glyph_lookup (scaled_font,
- scaled_font_glyph_index,
- CAIRO_SCALED_GLYPH_INFO_PATH,
+ * subset.
+ */
+ if (scaled_font_glyph_index == 0 && !is_user)
+ has_path = TRUE;
+
+ /* If this fails there is nothing we can do with this glyph. */
+ status = _cairo_scaled_glyph_lookup (scaled_font,
+ scaled_font_glyph_index,
+ CAIRO_SCALED_GLYPH_INFO_SURFACE,
NULL, /* foreground color */
- &scaled_glyph);
- _cairo_scaled_font_thaw_cache (scaled_font);
- }
+ &scaled_glyph);
+ _cairo_scaled_font_thaw_cache (scaled_font);
if (_cairo_int_status_is_error (status))
return status;
- if (status == CAIRO_INT_STATUS_SUCCESS &&
- subsets->type != CAIRO_SUBSETS_SCALED &&
- ! _cairo_font_face_is_user (scaled_font->font_face))
+ /* Type 3 glyphs (is_user and has_color) must be added to scaled subset */
+ if (subsets->type != CAIRO_SUBSETS_SCALED &&
+ has_path && !has_color && !is_user)
{
/* Path available. Add to unscaled subset. */
key.is_scaled = FALSE;
@@ -1012,19 +1023,12 @@ _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t
{
cairo_sub_font_collection_t collection;
cairo_sub_font_t *sub_font;
- cairo_bool_t is_scaled, is_user;
+ cairo_bool_t is_scaled;
is_scaled = FALSE;
- is_user = FALSE;
- if (type == CAIRO_SUBSETS_FOREACH_USER)
- is_user = TRUE;
-
- if (type == CAIRO_SUBSETS_FOREACH_SCALED ||
- type == CAIRO_SUBSETS_FOREACH_USER)
- {
+ if (type == CAIRO_SUBSETS_FOREACH_SCALED)
is_scaled = TRUE;
- }
if (is_scaled)
collection.glyphs_size = font_subsets->max_glyphs_per_scaled_subset_used;
@@ -1060,9 +1064,7 @@ _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t
sub_font = font_subsets->unscaled_sub_fonts_list;
while (sub_font) {
- if (sub_font->is_user == is_user)
- _cairo_sub_font_collect (sub_font, &collection);
-
+ _cairo_sub_font_collect (sub_font, &collection);
sub_font = sub_font->next;
}
free (collection.utf8);
@@ -1095,17 +1097,6 @@ _cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t *fo
CAIRO_SUBSETS_FOREACH_UNSCALED);
}
-cairo_status_t
-_cairo_scaled_font_subsets_foreach_user (cairo_scaled_font_subsets_t *font_subsets,
- cairo_scaled_font_subset_callback_func_t font_subset_callback,
- void *closure)
-{
- return _cairo_scaled_font_subsets_foreach_internal (font_subsets,
- font_subset_callback,
- closure,
- CAIRO_SUBSETS_FOREACH_USER);
-}
-
static cairo_bool_t
_cairo_string_equal (const void *key_a, const void *key_b)
{
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 5fe81110f..75640f723 100755
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -788,7 +788,7 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
cairo_font_face_reference (font_face);
scaled_font->original_font_face = NULL;
- CAIRO_MUTEX_INIT (scaled_font->mutex);
+ CAIRO_RECURSIVE_MUTEX_INIT (scaled_font->mutex);
cairo_list_init (&scaled_font->dev_privates);
@@ -1176,9 +1176,7 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
status = font_face->backend->scaled_font_create (font_face, font_matrix,
ctm, options, &scaled_font);
- /* Did we leave the backend in an error state? */
if (unlikely (status)) {
- status = _cairo_font_face_set_error (font_face, status);
_cairo_scaled_font_map_unlock ();
if (font_face != original_font_face)
cairo_font_face_destroy (font_face);
@@ -2655,10 +2653,21 @@ _cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph,
scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_PATH;
}
+/**
+ * _cairo_scaled_glyph_set_recording_surface:
+ * @scaled_glyph: a #cairo_scaled_glyph_t
+ * @scaled_font: a #cairo_scaled_font_t
+ * @recording_surface: The recording surface
+ * @foreground_color: The foreground color that was used to record the
+ * glyph, or NULL if foreground color not required.
+ *
+ * Sets the surface that was used to record the glyph.
+ */
void
_cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph,
- cairo_scaled_font_t *scaled_font,
- cairo_surface_t *recording_surface)
+ cairo_scaled_font_t *scaled_font,
+ cairo_surface_t *recording_surface,
+ const cairo_color_t * foreground_color)
{
if (scaled_glyph->recording_surface != NULL) {
cairo_surface_finish (scaled_glyph->recording_surface);
@@ -2666,6 +2675,9 @@ _cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph,
}
scaled_glyph->recording_surface = recording_surface;
+ scaled_glyph->recording_uses_foreground_color = foreground_color != NULL;
+ if (foreground_color)
+ scaled_glyph->foreground_color = *foreground_color;
if (recording_surface != NULL)
scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE;
@@ -2673,11 +2685,22 @@ _cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph,
scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE;
}
+/**
+ * _cairo_scaled_glyph_set_color_surface:
+ * @scaled_glyph: a #cairo_scaled_glyph_t
+ * @scaled_font: a #cairo_scaled_font_t
+ * @surface: The image surface
+ * @foreground_marker_color: The foreground color that was used to
+ * substitute the foreground_marker, or NULL if foreground_marker not
+ * used when rendering the surface color.
+ *
+ * Sets the color surface of the glyph.
+ */
void
-_cairo_scaled_glyph_set_color_surface (cairo_scaled_glyph_t *scaled_glyph,
- cairo_scaled_font_t *scaled_font,
+_cairo_scaled_glyph_set_color_surface (cairo_scaled_glyph_t *scaled_glyph,
+ cairo_scaled_font_t *scaled_font,
cairo_image_surface_t *surface,
- cairo_bool_t uses_foreground_color)
+ const cairo_color_t *foreground_marker_color)
{
if (scaled_glyph->color_surface != NULL)
cairo_surface_destroy (&scaled_glyph->color_surface->base);
@@ -2685,7 +2708,9 @@ _cairo_scaled_glyph_set_color_surface (cairo_scaled_glyph_t *scaled_glyph,
/* sanity check the backend glyph contents */
_cairo_debug_check_image_surface_is_defined (&surface->base);
scaled_glyph->color_surface = surface;
- scaled_glyph->uses_foreground_color = uses_foreground_color;
+ scaled_glyph->recording_uses_foreground_marker = foreground_marker_color != NULL;
+ if (foreground_marker_color)
+ scaled_glyph->foreground_color = *foreground_marker_color;
if (surface != NULL)
scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE;
@@ -2703,7 +2728,16 @@ _cairo_scaled_glyph_page_can_remove (const void *closure)
cairo_scaled_font_t *scaled_font;
scaled_font = page->scaled_font;
- return CAIRO_MUTEX_TRY_LOCK (scaled_font->mutex);
+
+ if (!CAIRO_MUTEX_TRY_LOCK (scaled_font->mutex))
+ return FALSE;
+
+ if (scaled_font->cache_frozen != 0) {
+ CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
+ return FALSE;
+ }
+
+ return TRUE;
}
static cairo_status_t
@@ -2807,8 +2841,11 @@ _cairo_scaled_font_free_last_glyph (cairo_scaled_font_t *scaled_font,
* @index: the glyph to create
* @info: a #cairo_scaled_glyph_info_t marking which portions of
* the glyph should be filled in.
- * @foreground_color - foreground color to use when rendering color fonts. Use NULL
- * if not requesting CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE or foreground color is unknown.
+ * @foreground_color - foreground color to use when rendering color
+ * fonts. Use NULL if not requesting
+ * CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE or
+ * CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE, or foreground color is
+ * unknown.
* @scaled_glyph_ret: a #cairo_scaled_glyph_t where the glyph
* is returned.
*
@@ -2902,14 +2939,24 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
scaled_glyph->color_glyph_set && !scaled_glyph->color_glyph)
return CAIRO_INT_STATUS_UNSUPPORTED;
- /* If requesting a color surface for a glyph that has used the
- * foreground color to render the color_surface, and the
+ /* If requesting a color surface or recording for a glyph that has
+ * used the foreground color to render the recording, and the
+ * foreground color has changed, request a new recording. */
+ if ((info & (CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE | CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) &&
+ scaled_glyph->recording_uses_foreground_color &&
+ !_cairo_color_equal (foreground_color, &scaled_glyph->foreground_color))
+ {
+ need_info |= CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE;
+ }
+
+ /* If requesting a color surface for a glyph that has
+ * used the foreground color to render the color_surface, and the
* foreground color has changed, request a new image. */
- if ((info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) &&
- scaled_glyph->uses_foreground_color &&
+ if (info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE &&
+ (scaled_glyph->recording_uses_foreground_marker || scaled_glyph->recording_uses_foreground_color) &&
!_cairo_color_equal (foreground_color, &scaled_glyph->foreground_color))
{
- need_info |= CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE;
+ need_info |= CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE;
}
if (need_info) {
@@ -3066,6 +3113,7 @@ cairo_scaled_font_get_font_options (cairo_scaled_font_t *scaled_font,
return;
}
+ _cairo_font_options_fini (options);
_cairo_font_options_init_copy (options, &scaled_font->options);
}
slim_hidden_def (cairo_scaled_font_get_font_options);
diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index b96d7d182..058626321 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -1882,7 +1882,7 @@ _emit_path_boxes (cairo_script_surface_t *surface,
if (! _cairo_path_fixed_iter_at_end (&iter)) {
_cairo_boxes_fini (&boxes);
- return CAIRO_STATUS_INVALID_PATH_DATA;
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
for (chunk = &boxes.chunks; chunk; chunk = chunk->next) {
@@ -2113,6 +2113,16 @@ _device_flush (void *abstract_device)
}
static void
+_device_finish (void *abstract_device)
+{
+ cairo_script_context_t *ctx = abstract_device;
+
+ cairo_status_t status = _cairo_output_stream_close (ctx->stream);
+ status = _cairo_device_set_error (&ctx->base, status);
+ (void) status;
+}
+
+static void
_device_destroy (void *abstract_device)
{
cairo_script_context_t *ctx = abstract_device;
@@ -2499,7 +2509,7 @@ _cairo_script_surface_paint (void *abstract_surface,
if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
return _cairo_surface_wrapper_paint (&surface->wrapper,
- op, source, clip);
+ op, source, 0, clip);
}
return CAIRO_STATUS_SUCCESS;
@@ -2556,7 +2566,7 @@ _cairo_script_surface_mask (void *abstract_surface,
if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
return _cairo_surface_wrapper_mask (&surface->wrapper,
- op, source, mask, clip);
+ op, source, 0, mask, 0, clip);
}
return CAIRO_STATUS_SUCCESS;
@@ -2643,7 +2653,7 @@ _cairo_script_surface_stroke (void *abstract_surface,
if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
return _cairo_surface_wrapper_stroke (&surface->wrapper,
- op, source, path,
+ op, source, 0, path,
style,
ctm, ctm_inverse,
tolerance, antialias,
@@ -2724,7 +2734,7 @@ _cairo_script_surface_fill (void *abstract_surface,
if (_cairo_surface_wrapper_is_active (&surface->wrapper)) {
return _cairo_surface_wrapper_fill (&surface->wrapper,
- op, source, path,
+ op, source, 0, path,
fill_rule,
tolerance,
antialias,
@@ -3034,6 +3044,7 @@ _emit_scaled_font (cairo_script_surface_t *surface,
if (unlikely (status))
return status;
+ _cairo_font_options_init_default (&options);
cairo_scaled_font_get_font_options (scaled_font, &options);
status = _emit_font_options (surface, &options);
if (unlikely (status))
@@ -3575,7 +3586,7 @@ _cairo_script_surface_show_text_glyphs (void *abstract_surface,
if (_cairo_surface_wrapper_is_active (&surface->wrapper)){
return _cairo_surface_wrapper_show_text_glyphs (&surface->wrapper,
- op, source,
+ op, source, 0,
utf8, utf8_len,
glyphs, num_glyphs,
clusters, num_clusters,
@@ -3731,7 +3742,7 @@ static const cairo_device_backend_t _cairo_script_device_backend = {
NULL, NULL, /* lock, unlock */
_device_flush, /* flush */
- NULL, /* finish */
+ _device_finish, /* finish */
_device_destroy
};
diff --git a/src/cairo-shape-mask-compositor.c b/src/cairo-shape-mask-compositor.c
index 3117267cc..0f4918603 100644
--- a/src/cairo-shape-mask-compositor.c
+++ b/src/cairo-shape-mask-compositor.c
@@ -116,7 +116,7 @@ _cairo_shape_mask_compositor_stroke (const cairo_compositor_t *_compositor,
&_cairo_pattern_white.base,
&pattern.base,
clip);
- if ((status == CAIRO_INT_STATUS_SUCCESS)) {
+ if (status == CAIRO_INT_STATUS_SUCCESS) {
status = _cairo_surface_mask (extents->surface,
CAIRO_OPERATOR_ADD,
&extents->source_pattern.base,
@@ -210,7 +210,7 @@ _cairo_shape_mask_compositor_fill (const cairo_compositor_t *_compositor,
&_cairo_pattern_white.base,
&pattern.base,
clip);
- if ((status == CAIRO_INT_STATUS_SUCCESS)) {
+ if (status == CAIRO_INT_STATUS_SUCCESS) {
status = _cairo_surface_mask (extents->surface,
CAIRO_OPERATOR_ADD,
&extents->source_pattern.base,
@@ -303,7 +303,7 @@ _cairo_shape_mask_compositor_glyphs (const cairo_compositor_t *_compositor,
&_cairo_pattern_white.base,
&pattern.base,
clip);
- if ((status == CAIRO_INT_STATUS_SUCCESS)) {
+ if (status == CAIRO_INT_STATUS_SUCCESS) {
status = _cairo_surface_mask (extents->surface,
CAIRO_OPERATOR_ADD,
&extents->source_pattern.base,
diff --git a/src/cairo-spans-compositor.c b/src/cairo-spans-compositor.c
index 50c92b25c..49c5999d2 100644
--- a/src/cairo-spans-compositor.c
+++ b/src/cairo-spans-compositor.c
@@ -612,7 +612,7 @@ composite_aligned_boxes (const cairo_spans_compositor_t *compositor,
recording_clip = _cairo_clip_from_boxes (boxes);
status = _cairo_recording_surface_replay_with_clip (unwrap_source (source),
- m, dst, recording_clip);
+ m, dst, recording_clip, FALSE);
_cairo_clip_destroy (recording_clip);
return status;
diff --git a/src/cairo-spans.c b/src/cairo-spans.c
index 1b46adf4d..711c0c106 100644
--- a/src/cairo-spans.c
+++ b/src/cairo-spans.c
@@ -133,6 +133,7 @@ _cairo_scan_converter_create_in_error (cairo_status_t status)
case CAIRO_STATUS_WIN32_GDI_ERROR:
case CAIRO_STATUS_TAG_ERROR:
case CAIRO_STATUS_DWRITE_ERROR:
+ case CAIRO_STATUS_SVG_FONT_ERROR:
default:
break;
}
@@ -251,6 +252,7 @@ _cairo_span_renderer_create_in_error (cairo_status_t status)
case CAIRO_STATUS_WIN32_GDI_ERROR: RETURN_NIL;
case CAIRO_STATUS_TAG_ERROR: RETURN_NIL;
case CAIRO_STATUS_DWRITE_ERROR: RETURN_NIL;
+ case CAIRO_STATUS_SVG_FONT_ERROR: RETURN_NIL;
default:
break;
}
diff --git a/src/cairo-spline.c b/src/cairo-spline.c
index 44634faec..6f50a637a 100644
--- a/src/cairo-spline.c
+++ b/src/cairo-spline.c
@@ -177,7 +177,7 @@ _cairo_spline_error_squared (const cairo_spline_knots_t *knots)
double bdx, bdy, berr;
double cdx, cdy, cerr;
- /* We are going to compute the distance (squared) between each of the the b
+ /* We are going to compute the distance (squared) between each of the b
* and c control points and the segment a-b. The maximum of these two
* distances will be our approximation error. */
diff --git a/src/cairo-surface-backend-private.h b/src/cairo-surface-backend-private.h
index d31655be8..15032de20 100644
--- a/src/cairo-surface-backend-private.h
+++ b/src/cairo-surface-backend-private.h
@@ -124,14 +124,14 @@ struct _cairo_surface_backend {
(*paint) (void *surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- const cairo_clip_t *clip);
+ const cairo_clip_t *clip);
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_clip_t *clip);
+ const cairo_clip_t *clip);
cairo_warn cairo_int_status_t
(*stroke) (void *surface,
@@ -143,7 +143,7 @@ struct _cairo_surface_backend {
const cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- const cairo_clip_t *clip);
+ const cairo_clip_t *clip);
cairo_warn cairo_int_status_t
(*fill) (void *surface,
@@ -153,7 +153,7 @@ struct _cairo_surface_backend {
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
- const cairo_clip_t *clip);
+ const cairo_clip_t *clip);
cairo_warn cairo_int_status_t
(*fill_stroke) (void *surface,
@@ -196,7 +196,7 @@ struct _cairo_surface_backend {
int num_clusters,
cairo_text_cluster_flags_t cluster_flags,
cairo_scaled_font_t *scaled_font,
- const cairo_clip_t *clip);
+ const cairo_clip_t *clip);
const char **
(*get_supported_mime_types) (void *surface);
@@ -207,6 +207,10 @@ struct _cairo_surface_backend {
const char *tag_name,
const char *attributes);
+ cairo_bool_t
+ (*supports_color_glyph) (void *surface,
+ cairo_scaled_font_t *scaled_font,
+ unsigned long glyph_index);
};
cairo_private cairo_status_t
diff --git a/src/cairo-surface-observer.c b/src/cairo-surface-observer.c
index 9c4432e24..bf29d4219 100644
--- a/src/cairo-surface-observer.c
+++ b/src/cairo-surface-observer.c
@@ -54,6 +54,15 @@
#include "cairo-script-private.h"
#endif
+/**
+ * SECTION:cairo-surface-observer
+ * @Title: Surface Observer
+ * @Short_Description: Observing other surfaces
+ * @See_Also: #cairo_surface_t
+ *
+ * A surface that exists solely to watch another is doing.
+ */
+
static const cairo_surface_backend_t _cairo_surface_observer_backend;
/* observation/stats */
diff --git a/src/cairo-surface-private.h b/src/cairo-surface-private.h
index e4ad5f3b1..35b559f9c 100644
--- a/src/cairo-surface-private.h
+++ b/src/cairo-surface-private.h
@@ -104,6 +104,9 @@ struct _cairo_surface {
* cairo_surface_create_similar().
*/
cairo_font_options_t font_options;
+
+ cairo_pattern_t *foreground_source;
+ cairo_bool_t foreground_used;
};
cairo_private cairo_surface_t *
diff --git a/src/cairo-surface-wrapper-private.h b/src/cairo-surface-wrapper-private.h
index 7c3bc56ba..016402d7e 100644
--- a/src/cairo-surface-wrapper-private.h
+++ b/src/cairo-surface-wrapper-private.h
@@ -1,3 +1,4 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
@@ -41,6 +42,7 @@
#include "cairoint.h"
#include "cairo-types-private.h"
+#include "cairo-recording-surface-private.h"
#include "cairo-surface-backend-private.h"
CAIRO_BEGIN_DECLS
@@ -53,7 +55,9 @@ struct _cairo_surface_wrapper {
cairo_bool_t has_extents;
cairo_rectangle_int_t extents;
const cairo_clip_t *clip;
- cairo_pattern_t *foreground_source;
+
+ unsigned int source_region_id;
+ unsigned int mask_region_id;
cairo_bool_t needs_transform;
};
@@ -75,10 +79,6 @@ _cairo_surface_wrapper_set_clip (cairo_surface_wrapper_t *wrapper,
const cairo_clip_t *clip);
cairo_private void
-_cairo_surface_wrapper_set_foreground_color (cairo_surface_wrapper_t *wrapper,
- const cairo_color_t *color);
-
-cairo_private void
_cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper);
static inline cairo_bool_t
@@ -100,60 +100,68 @@ _cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper,
cairo_private cairo_status_t
_cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_clip_t *clip);
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ unsigned int source_region_id,
+ const cairo_clip_t *clip);
cairo_private cairo_status_t
_cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_pattern_t *mask,
- const cairo_clip_t *clip);
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ unsigned int source_region_id,
+ const cairo_pattern_t *mask,
+ unsigned int mask_region_id,
+ const cairo_clip_t *clip);
cairo_private cairo_status_t
-_cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- const cairo_stroke_style_t *stroke_style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip);
+_cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ unsigned int source_region_id,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip);
cairo_private cairo_status_t
-_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
- cairo_operator_t fill_op,
- const cairo_pattern_t *fill_source,
- cairo_fill_rule_t fill_rule,
- double fill_tolerance,
- cairo_antialias_t fill_antialias,
- const cairo_path_fixed_t*path,
- cairo_operator_t stroke_op,
- const cairo_pattern_t *stroke_source,
- const cairo_stroke_style_t *stroke_style,
- const cairo_matrix_t *stroke_ctm,
- const cairo_matrix_t *stroke_ctm_inverse,
- double stroke_tolerance,
- cairo_antialias_t stroke_antialias,
- const cairo_clip_t *clip);
+_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
+ cairo_operator_t fill_op,
+ const cairo_pattern_t *fill_source,
+ unsigned int fill_region_id,
+ cairo_fill_rule_t fill_rule,
+ double fill_tolerance,
+ cairo_antialias_t fill_antialias,
+ const cairo_path_fixed_t *path,
+ cairo_operator_t stroke_op,
+ const cairo_pattern_t *stroke_source,
+ unsigned int stroke_region_id,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *stroke_ctm,
+ const cairo_matrix_t *stroke_ctm_inverse,
+ double stroke_tolerance,
+ cairo_antialias_t stroke_antialias,
+ const cairo_clip_t *clip);
cairo_private cairo_status_t
-_cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip);
+_cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ unsigned int source_region_id,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip);
cairo_private cairo_status_t
-_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
+_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
+ unsigned int source_region_id,
const char *utf8,
int utf8_len,
const cairo_glyph_t *glyphs,
diff --git a/src/cairo-surface-wrapper.c b/src/cairo-surface-wrapper.c
index 8ba82bd40..29c19c5a5 100644
--- a/src/cairo-surface-wrapper.c
+++ b/src/cairo-surface-wrapper.c
@@ -1,3 +1,4 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2005 Red Hat, Inc
@@ -47,12 +48,18 @@
static void
_copy_transformed_pattern (cairo_pattern_t *pattern,
const cairo_pattern_t *original,
- const cairo_matrix_t *ctm_inverse)
+ const cairo_matrix_t *ctm_inverse,
+ unsigned int region_id)
{
_cairo_pattern_init_static_copy (pattern, original);
if (! _cairo_matrix_is_identity (ctm_inverse))
_cairo_pattern_transform (pattern, ctm_inverse);
+
+ if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+ cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
+ surface_pattern->region_array_id = region_id;
+ }
}
cairo_status_t
@@ -129,9 +136,10 @@ _cairo_surface_wrapper_get_clip (cairo_surface_wrapper_t *wrapper,
cairo_status_t
_cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_clip_t *clip)
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ unsigned int source_region_id,
+ const cairo_clip_t *clip)
{
cairo_status_t status;
cairo_clip_t *dev_clip;
@@ -144,10 +152,7 @@ _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
if (_cairo_clip_is_all_clipped (dev_clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
- if (source->is_userfont_foreground && wrapper->foreground_source)
- source = wrapper->foreground_source;
-
- if (wrapper->needs_transform) {
+ if (wrapper->needs_transform || source_region_id != 0) {
cairo_matrix_t m;
_cairo_surface_wrapper_get_transform (wrapper, &m);
@@ -155,7 +160,7 @@ _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
- _copy_transformed_pattern (&source_copy.base, source, &m);
+ _copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
source = &source_copy.base;
}
@@ -165,13 +170,14 @@ _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
return status;
}
-
cairo_status_t
_cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_pattern_t *mask,
- const cairo_clip_t *clip)
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ unsigned int source_region_id,
+ const cairo_pattern_t *mask,
+ unsigned int mask_region_id,
+ const cairo_clip_t *clip)
{
cairo_status_t status;
cairo_clip_t *dev_clip;
@@ -185,10 +191,7 @@ _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
if (_cairo_clip_is_all_clipped (dev_clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
- if (source->is_userfont_foreground && wrapper->foreground_source)
- source = wrapper->foreground_source;
-
- if (wrapper->needs_transform) {
+ if (wrapper->needs_transform || source_region_id != 0 || mask_region_id != 0) {
cairo_matrix_t m;
_cairo_surface_wrapper_get_transform (wrapper, &m);
@@ -196,10 +199,10 @@ _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
- _copy_transformed_pattern (&source_copy.base, source, &m);
+ _copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
source = &source_copy.base;
- _copy_transformed_pattern (&mask_copy.base, mask, &m);
+ _copy_transformed_pattern (&mask_copy.base, mask, &m, mask_region_id);
mask = &mask_copy.base;
}
@@ -210,16 +213,17 @@ _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
}
cairo_status_t
-_cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- const cairo_stroke_style_t *stroke_style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip)
+_cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ unsigned int source_region_id,
+ const cairo_path_fixed_t *path,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip)
{
cairo_status_t status;
cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path;
@@ -235,10 +239,7 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
if (_cairo_clip_is_all_clipped (dev_clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
- if (source->is_userfont_foreground && wrapper->foreground_source)
- source = wrapper->foreground_source;
-
- if (wrapper->needs_transform) {
+ if (wrapper->needs_transform || source_region_id != 0) {
cairo_matrix_t m;
_cairo_surface_wrapper_get_transform (wrapper, &m);
@@ -257,7 +258,7 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
- _copy_transformed_pattern (&source_copy.base, source, &m);
+ _copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
source = &source_copy.base;
}
@@ -275,21 +276,23 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
}
cairo_status_t
-_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
- cairo_operator_t fill_op,
- const cairo_pattern_t *fill_source,
- cairo_fill_rule_t fill_rule,
- double fill_tolerance,
- cairo_antialias_t fill_antialias,
- const cairo_path_fixed_t*path,
- cairo_operator_t stroke_op,
- const cairo_pattern_t *stroke_source,
- const cairo_stroke_style_t *stroke_style,
- const cairo_matrix_t *stroke_ctm,
- const cairo_matrix_t *stroke_ctm_inverse,
- double stroke_tolerance,
- cairo_antialias_t stroke_antialias,
- const cairo_clip_t *clip)
+_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
+ cairo_operator_t fill_op,
+ const cairo_pattern_t *fill_source,
+ unsigned int fill_region_id,
+ cairo_fill_rule_t fill_rule,
+ double fill_tolerance,
+ cairo_antialias_t fill_antialias,
+ const cairo_path_fixed_t *path,
+ cairo_operator_t stroke_op,
+ const cairo_pattern_t *stroke_source,
+ unsigned int stroke_region_id,
+ const cairo_stroke_style_t *stroke_style,
+ const cairo_matrix_t *stroke_ctm,
+ const cairo_matrix_t *stroke_ctm_inverse,
+ double stroke_tolerance,
+ cairo_antialias_t stroke_antialias,
+ const cairo_clip_t *clip)
{
cairo_status_t status;
cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *)path;
@@ -306,13 +309,7 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
if (_cairo_clip_is_all_clipped (dev_clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
- if (fill_source->is_userfont_foreground && wrapper->foreground_source)
- fill_source = wrapper->foreground_source;
-
- if (stroke_source->is_userfont_foreground && wrapper->foreground_source)
- stroke_source = wrapper->foreground_source;
-
- if (wrapper->needs_transform) {
+ if (wrapper->needs_transform || fill_region_id != 0 || stroke_region_id != 0) {
cairo_matrix_t m;
_cairo_surface_wrapper_get_transform (wrapper, &m);
@@ -331,10 +328,10 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
- _copy_transformed_pattern (&stroke_source_copy.base, stroke_source, &m);
+ _copy_transformed_pattern (&stroke_source_copy.base, stroke_source, &m, fill_region_id);
stroke_source = &stroke_source_copy.base;
- _copy_transformed_pattern (&fill_source_copy.base, fill_source, &m);
+ _copy_transformed_pattern (&fill_source_copy.base, fill_source, &m, stroke_region_id);
fill_source = &fill_source_copy.base;
}
@@ -356,14 +353,15 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
}
cairo_status_t
-_cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip)
+_cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ unsigned int source_region_id,
+ const cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ const cairo_clip_t *clip)
{
cairo_status_t status;
cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path;
@@ -377,10 +375,7 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
if (_cairo_clip_is_all_clipped (dev_clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
- if (source->is_userfont_foreground && wrapper->foreground_source)
- source = wrapper->foreground_source;
-
- if (wrapper->needs_transform) {
+ if (wrapper->needs_transform || source_region_id != 0) {
cairo_matrix_t m;
_cairo_surface_wrapper_get_transform (wrapper, &m);
@@ -395,7 +390,7 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
- _copy_transformed_pattern (&source_copy.base, source, &m);
+ _copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
source = &source_copy.base;
}
@@ -412,9 +407,10 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
}
cairo_status_t
-_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
+_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
cairo_operator_t op,
const cairo_pattern_t *source,
+ unsigned int source_region_id,
const char *utf8,
int utf8_len,
const cairo_glyph_t *glyphs,
@@ -443,10 +439,7 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
cairo_surface_get_font_options (wrapper->target, &options);
cairo_font_options_merge (&options, &scaled_font->options);
- if (source->is_userfont_foreground && wrapper->foreground_source)
- source = wrapper->foreground_source;
-
- if (wrapper->needs_transform) {
+ if (wrapper->needs_transform || source_region_id != 0) {
cairo_matrix_t m;
int i;
@@ -481,7 +474,7 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
- _copy_transformed_pattern (&source_copy.base, source, &m);
+ _copy_transformed_pattern (&source_copy.base, source, &m, source_region_id);
source = &source_copy.base;
} else {
if (! cairo_font_options_equal (&options, &scaled_font->options)) {
@@ -613,14 +606,6 @@ _cairo_surface_wrapper_set_clip (cairo_surface_wrapper_t *wrapper,
}
void
-_cairo_surface_wrapper_set_foreground_color (cairo_surface_wrapper_t *wrapper,
- const cairo_color_t *color)
-{
- if (color)
- wrapper->foreground_source = _cairo_pattern_create_solid (color);
-}
-
-void
_cairo_surface_wrapper_get_font_options (cairo_surface_wrapper_t *wrapper,
cairo_font_options_t *options)
{
@@ -651,7 +636,8 @@ _cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
wrapper->has_extents = FALSE;
wrapper->extents.x = wrapper->extents.y = 0;
wrapper->clip = NULL;
- wrapper->foreground_source = NULL;
+ wrapper->source_region_id = 0;
+ wrapper->mask_region_id = 0;
wrapper->needs_transform = FALSE;
if (target) {
@@ -663,9 +649,6 @@ _cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
void
_cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper)
{
- if (wrapper->foreground_source)
- cairo_pattern_destroy (wrapper->foreground_source);
-
cairo_surface_destroy (wrapper->target);
}
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 105f4bff1..f1292e0bb 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -49,7 +49,6 @@
#include "cairo-recording-surface-private.h"
#include "cairo-region-private.h"
#include "cairo-surface-inline.h"
-#include "cairo-tee-surface-private.h"
/**
* SECTION:cairo-surface
@@ -134,7 +133,9 @@ const cairo_surface_t name = { \
CAIRO_HINT_STYLE_DEFAULT, /* hint_style */ \
CAIRO_HINT_METRICS_DEFAULT, /* hint_metrics */ \
CAIRO_ROUND_GLYPH_POS_DEFAULT /* round_glyph_positions */ \
- } /* font_options */ \
+ }, /* font_options */ \
+ NULL, /* foreground_source */ \
+ FALSE, /* foreground_used */ \
}
/* XXX error object! */
@@ -439,6 +440,9 @@ _cairo_surface_init (cairo_surface_t *surface,
surface->snapshot_of = NULL;
surface->has_font_options = FALSE;
+
+ surface->foreground_source = NULL;
+ surface->foreground_used = FALSE;
}
static void
@@ -976,6 +980,9 @@ cairo_surface_destroy (cairo_surface_t *surface)
_cairo_user_data_array_fini (&surface->user_data);
_cairo_user_data_array_fini (&surface->mime_data);
+ if (surface->foreground_source)
+ cairo_pattern_destroy (surface->foreground_source);
+
if (surface->owns_device)
cairo_device_destroy (surface->device);
@@ -1774,7 +1781,7 @@ slim_hidden_def (cairo_surface_mark_dirty_rectangle);
* by the CTM when drawing to @surface. One common use for this is to
* render to very high resolution display devices at a scale factor, so
* that code that assumes 1 pixel will be a certain size will still work.
- * Setting a transformation via cairo_translate() isn't
+ * Setting a transformation via cairo_scale() isn't
* sufficient to do this, since functions like
* cairo_device_to_user() will expose the hidden scale.
*
@@ -1826,7 +1833,7 @@ slim_hidden_def (cairo_surface_set_device_scale);
* @x_scale: the scale in the X direction, in device units
* @y_scale: the scale in the Y direction, in device units
*
- * This function returns the previous device offset set by
+ * This function returns the previous device scale set by
* cairo_surface_set_device_scale().
*
* Since: 1.14
@@ -2196,6 +2203,11 @@ _cairo_surface_paint (cairo_surface_t *surface,
if (unlikely (status))
return status;
+ if (source->is_foreground_marker && surface->foreground_source) {
+ source = surface->foreground_source;
+ surface->foreground_used = TRUE;
+ }
+
status = surface->backend->paint (surface, op, source, clip);
is_clear = op == CAIRO_OPERATOR_CLEAR && clip == NULL;
if (status != CAIRO_INT_STATUS_NOTHING_TO_DO || is_clear) {
@@ -2246,6 +2258,11 @@ _cairo_surface_mask (cairo_surface_t *surface,
if (unlikely (status))
return status;
+ if (source->is_foreground_marker && surface->foreground_source) {
+ source = surface->foreground_source;
+ surface->foreground_used = TRUE;
+ }
+
status = surface->backend->mask (surface, op, source, mask, clip);
if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
surface->is_clear = FALSE;
@@ -2302,6 +2319,16 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface,
if (unlikely (status))
return status;
+ if (fill_source->is_foreground_marker && surface->foreground_source) {
+ fill_source = surface->foreground_source;
+ surface->foreground_used = TRUE;
+ }
+
+ if (stroke_source->is_foreground_marker && surface->foreground_source) {
+ stroke_source = surface->foreground_source;
+ surface->foreground_used = TRUE;
+ }
+
if (surface->backend->fill_stroke) {
cairo_matrix_t dev_ctm = *stroke_ctm;
cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;
@@ -2376,6 +2403,11 @@ _cairo_surface_stroke (cairo_surface_t *surface,
if (unlikely (status))
return status;
+ if (source->is_foreground_marker && surface->foreground_source) {
+ source = surface->foreground_source;
+ surface->foreground_used = TRUE;
+ }
+
status = surface->backend->stroke (surface, op, source,
path, stroke_style,
ctm, ctm_inverse,
@@ -2421,6 +2453,11 @@ _cairo_surface_fill (cairo_surface_t *surface,
if (unlikely (status))
return status;
+ if (source->is_foreground_marker && surface->foreground_source) {
+ source = surface->foreground_source;
+ surface->foreground_used = TRUE;
+ }
+
status = surface->backend->fill (surface, op, source,
path, fill_rule,
tolerance, antialias,
@@ -2719,6 +2756,7 @@ composite_color_glyphs (cairo_surface_t *surface,
font_face = cairo_scaled_font_get_font_face (scaled_font);
cairo_scaled_font_get_font_matrix (scaled_font, &font_matrix);
cairo_scaled_font_get_ctm (scaled_font, &ctm);
+ _cairo_font_options_init_default (&font_options);
cairo_scaled_font_get_font_options (scaled_font, &font_options);
cairo_matrix_scale (&ctm, x_scale, y_scale);
scaled_font = cairo_scaled_font_create (font_face,
@@ -2756,9 +2794,21 @@ composite_color_glyphs (cairo_surface_t *surface,
goto UNLOCK;
if ((scaled_glyph->has_info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) != 0) {
- skip_cluster = FALSE;
- break;
- }
+ cairo_bool_t supports_color_glyph = FALSE;
+
+ if (surface->backend->supports_color_glyph) {
+ _cairo_scaled_font_thaw_cache (scaled_font);
+ supports_color_glyph = _cairo_surface_supports_color_glyph (surface, scaled_font, glyphs[gp].index);
+
+ memset (glyph_cache, 0, sizeof (glyph_cache));
+ _cairo_scaled_font_freeze_cache (scaled_font);
+ }
+
+ if (!supports_color_glyph) {
+ skip_cluster = FALSE;
+ break;
+ }
+ }
}
if (skip_cluster) {
@@ -2894,13 +2944,20 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
if (unlikely (status))
return status;
- if (nothing_to_do (surface, op, source))
- return CAIRO_STATUS_SUCCESS;
+ if (!(_cairo_scaled_font_has_color_glyphs (scaled_font) &&
+ scaled_font->options.color_mode != CAIRO_COLOR_MODE_NO_COLOR))
+ {
+ if (nothing_to_do (surface, op, source))
+ return CAIRO_STATUS_SUCCESS;
+ }
status = _cairo_surface_begin_modification (surface);
if (unlikely (status))
return status;
+ if (source->is_foreground_marker && surface->foreground_source)
+ source = surface->foreground_source;
+
if (_cairo_scaled_font_has_color_glyphs (scaled_font) &&
scaled_font->options.color_mode != CAIRO_COLOR_MODE_NO_COLOR)
{
@@ -2921,9 +2978,9 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
if (num_glyphs == 0)
goto DONE;
- }
- else
+ } else {
utf8_copy = NULL;
+ }
/* The logic here is duplicated in _cairo_analysis_surface show_glyphs and
* show_text_glyphs. Keep in synch. */
@@ -3011,6 +3068,16 @@ _cairo_surface_tag (cairo_surface_t *surface,
return _cairo_surface_set_error (surface, status);
}
+cairo_bool_t
+_cairo_surface_supports_color_glyph (cairo_surface_t *surface,
+ cairo_scaled_font_t *scaled_font,
+ unsigned long glyph_index)
+{
+ if (surface->backend->supports_color_glyph != NULL)
+ return surface->backend->supports_color_glyph (surface, scaled_font, glyph_index);
+
+ return FALSE;
+}
/**
* _cairo_surface_set_resolution:
@@ -3110,6 +3177,7 @@ _cairo_surface_create_in_error (cairo_status_t status)
case CAIRO_STATUS_WIN32_GDI_ERROR:
case CAIRO_INT_STATUS_DWRITE_ERROR:
case CAIRO_STATUS_TAG_ERROR:
+ case CAIRO_STATUS_SVG_FONT_ERROR:
default:
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t *) &_cairo_surface_nil;
diff --git a/src/cairo-svg-glyph-render.c b/src/cairo-svg-glyph-render.c
new file mode 100644
index 000000000..cac8a7a73
--- /dev/null
+++ b/src/cairo-svg-glyph-render.c
@@ -0,0 +1,3243 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2022 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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-array-private.h"
+#include "cairo-ft-private.h"
+#include "cairo-pattern-private.h"
+#include "cairo-scaled-font-subsets-private.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#if HAVE_FT_SVG_DOCUMENT
+
+#include <ft2build.h>
+#include FT_COLOR_H
+
+/* #define SVG_RENDER_PRINT_FUNCTIONS 1 */
+
+#define WHITE_SPACE_CHARS " \n\r\t\v\f"
+
+typedef struct {
+ const char *name;
+ int red;
+ int green;
+ int blue;
+} color_name_t;
+
+/* Must be sorted */
+static color_name_t color_names[] = {
+ { "aliceblue", 240, 248, 255 },
+ { "antiquewhite", 250, 235, 215 },
+ { "aqua", 0, 255, 255 },
+ { "aquamarine", 127, 255, 212 },
+ { "azure", 240, 255, 255 },
+ { "beige", 245, 245, 220 },
+ { "bisque", 255, 228, 196 },
+ { "black", 0, 0, 0 },
+ { "blanchedalmond", 255, 235, 205 },
+ { "blue", 0, 0, 255 },
+ { "blueviolet", 138, 43, 226 },
+ { "brown", 165, 42, 42 },
+ { "burlywood", 222, 184, 135 },
+ { "cadetblue", 95, 158, 160 },
+ { "chartreuse", 127, 255, 0 },
+ { "chocolate", 210, 105, 30 },
+ { "coral", 255, 127, 80 },
+ { "cornflowerblue", 100, 149, 237 },
+ { "cornsilk", 255, 248, 220 },
+ { "crimson", 220, 20, 60 },
+ { "cyan", 0, 255, 255 },
+ { "darkblue", 0, 0, 139 },
+ { "darkcyan", 0, 139, 139 },
+ { "darkgoldenrod", 184, 134, 11 },
+ { "darkgray", 169, 169, 169 },
+ { "darkgreen", 0, 100, 0 },
+ { "darkgrey", 169, 169, 169 },
+ { "darkkhaki", 189, 183, 107 },
+ { "darkmagenta", 139, 0, 139 },
+ { "darkolivegreen", 85, 107, 47 },
+ { "darkorange", 255, 140, 0 },
+ { "darkorchid", 153, 50, 204 },
+ { "darkred", 139, 0, 0 },
+ { "darksalmon", 233, 150, 122 },
+ { "darkseagreen", 143, 188, 143 },
+ { "darkslateblue", 72, 61, 139 },
+ { "darkslategray", 47, 79, 79 },
+ { "darkslategrey", 47, 79, 79 },
+ { "darkturquoise", 0, 206, 209 },
+ { "darkviolet", 148, 0, 211 },
+ { "deeppink", 255, 20, 147 },
+ { "deepskyblue", 0, 191, 255 },
+ { "dimgray", 105, 105, 105 },
+ { "dimgrey", 105, 105, 105 },
+ { "dodgerblue", 30, 144, 255 },
+ { "firebrick", 178, 34, 34 },
+ { "floralwhite", 255, 250, 240 },
+ { "forestgreen", 34, 139, 34 },
+ { "fuchsia", 255, 0, 255 },
+ { "gainsboro", 220, 220, 220 },
+ { "ghostwhite", 248, 248, 255 },
+ { "gold", 255, 215, 0 },
+ { "goldenrod", 218, 165, 32 },
+ { "gray", 128, 128, 128 },
+ { "green", 0, 128, 0 },
+ { "greenyellow", 173, 255, 47 },
+ { "grey", 128, 128, 128 },
+ { "honeydew", 240, 255, 240 },
+ { "hotpink", 255, 105, 180 },
+ { "indianred", 205, 92, 92 },
+ { "indigo", 75, 0, 130 },
+ { "ivory", 255, 255, 240 },
+ { "khaki", 240, 230, 140 },
+ { "lavender", 230, 230, 250 },
+ { "lavenderblush", 255, 240, 245 },
+ { "lawngreen", 124, 252, 0 },
+ { "lemonchiffon", 255, 250, 205 },
+ { "lightblue", 173, 216, 230 },
+ { "lightcoral", 240, 128, 128 },
+ { "lightcyan", 224, 255, 255 },
+ { "lightgoldenrodyellow", 250, 250, 210 },
+ { "lightgray", 211, 211, 211 },
+ { "lightgreen", 144, 238, 144 },
+ { "lightgrey", 211, 211, 211 },
+ { "lightpink", 255, 182, 193 },
+ { "lightsalmon", 255, 160, 122 },
+ { "lightseagreen", 32, 178, 170 },
+ { "lightskyblue", 135, 206, 250 },
+ { "lightslategray", 119, 136, 153 },
+ { "lightslategrey", 119, 136, 153 },
+ { "lightsteelblue", 176, 196, 222 },
+ { "lightyellow", 255, 255, 224 },
+ { "lime", 0, 255, 0 },
+ { "limegreen", 50, 205, 50 },
+ { "linen", 250, 240, 230 },
+ { "magenta", 255, 0, 255 },
+ { "maroon", 128, 0, 0 },
+ { "mediumaquamarine", 102, 205, 170 },
+ { "mediumblue", 0, 0, 205 },
+ { "mediumorchid", 186, 85, 211 },
+ { "mediumpurple", 147, 112, 219 },
+ { "mediumseagreen", 60, 179, 113 },
+ { "mediumslateblue", 123, 104, 238 },
+ { "mediumspringgreen", 0, 250, 154 },
+ { "mediumturquoise", 72, 209, 204 },
+ { "mediumvioletred", 199, 21, 133 },
+ { "midnightblue", 25, 25, 112 },
+ { "mintcream", 245, 255, 250 },
+ { "mistyrose", 255, 228, 225 },
+ { "moccasin", 255, 228, 181 },
+ { "navajowhite", 255, 222, 173 },
+ { "navy", 0, 0, 128 },
+ { "oldlace", 253, 245, 230 },
+ { "olive", 128, 128, 0 },
+ { "olivedrab", 107, 142, 35 },
+ { "orange", 255, 165, 0 },
+ { "orangered", 255, 69, 0 },
+ { "orchid", 218, 112, 214 },
+ { "palegoldenrod", 238, 232, 170 },
+ { "palegreen", 152, 251, 152 },
+ { "paleturquoise", 175, 238, 238 },
+ { "palevioletred", 219, 112, 147 },
+ { "papayawhip", 255, 239, 213 },
+ { "peachpuff", 255, 218, 185 },
+ { "peru", 205, 133, 63 },
+ { "pink", 255, 192, 203 },
+ { "plum", 221, 160, 221 },
+ { "powderblue", 176, 224, 230 },
+ { "purple", 128, 0, 128 },
+ { "red", 255, 0, 0 },
+ { "rosybrown", 188, 143, 143 },
+ { "royalblue", 65, 105, 225 },
+ { "saddlebrown", 139, 69, 19 },
+ { "salmon", 250, 128, 114 },
+ { "sandybrown", 244, 164, 96 },
+ { "seagreen", 46, 139, 87 },
+ { "seashell", 255, 245, 238 },
+ { "sienna", 160, 82, 45 },
+ { "silver", 192, 192, 192 },
+ { "skyblue", 135, 206, 235 },
+ { "slateblue", 106, 90, 205 },
+ { "slategray", 112, 128, 144 },
+ { "slategrey", 112, 128, 144 },
+ { "snow", 255, 250, 250 },
+ { "springgreen", 0, 255, 127 },
+ { "steelblue", 70, 130, 180 },
+ { "tan", 210, 180, 140 },
+ { "teal", 0, 128, 128 },
+ { "thistle", 216, 191, 216 },
+ { "tomato", 255, 99, 71 },
+ { "turquoise", 64, 224, 208 },
+ { "violet", 238, 130, 238 },
+ { "wheat", 245, 222, 179 },
+ { "white", 255, 255, 255 },
+ { "whitesmoke", 245, 245, 245 },
+ { "yellow", 255, 255, 0 },
+ { "yellowgreen", 154, 205, 50 }
+};
+
+typedef struct {
+ char *name;
+ char *value;
+} svg_attribute_t;
+
+typedef enum {
+ CONTAINER_ELEMENT,
+ EMPTY_ELEMENT,
+ PROCESSING_INSTRUCTION,
+ DOCTYPE,
+ CDATA,
+ COMMENT
+} tag_type_t;
+
+#define TOP_ELEMENT_TAG "_top"
+
+typedef struct _cairo_svg_element {
+ cairo_hash_entry_t base;
+ tag_type_t type;
+ char *tag;
+ char *id;
+ cairo_array_t attributes; /* svg_attribute_t */
+ cairo_array_t children; /* cairo_svg_element_t* */
+ cairo_array_t content; /* char */
+ cairo_pattern_t *pattern; /* defined if a paint server */
+ struct _cairo_svg_element *next; /* next on element stack */
+} cairo_svg_element_t;
+
+typedef struct _cairo_svg_color {
+ enum { RGB, FOREGROUND } type;
+ double red;
+ double green;
+ double blue;
+} cairo_svg_color_t;
+
+typedef struct _cairo_svg_paint {
+ enum { PAINT_COLOR, PAINT_SERVER, PAINT_NONE } type;
+ cairo_svg_color_t color;
+ cairo_svg_element_t *paint_server;
+} cairo_svg_paint_t;
+
+typedef enum {
+ GS_RENDER,
+ GS_NO_RENDER,
+ GS_COMPUTE_BBOX,
+ GS_CLIP
+} gs_mode_t;
+
+typedef struct _cairo_svg_graphics_state {
+ cairo_svg_paint_t fill;
+ cairo_svg_paint_t stroke;
+ cairo_svg_color_t color;
+ double fill_opacity;
+ double stroke_opacity;
+ double opacity;
+ cairo_fill_rule_t fill_rule;
+ cairo_fill_rule_t clip_rule;
+ cairo_path_t *clip_path;
+ char *dash_array;
+ double dash_offset;
+ gs_mode_t mode;
+ struct {
+ double x;
+ double y;
+ double width;
+ double height;
+ } bbox;
+ struct _cairo_svg_graphics_state *next;
+} cairo_svg_graphics_state_t;
+
+typedef enum {
+ BUILD_PATTERN_NONE,
+ BUILD_PATTERN_LINEAR,
+ BUILD_PATTERN_RADIAL
+} build_pattern_t;
+
+typedef struct _cairo_svg_glyph_render {
+ cairo_svg_element_t *tree;
+ cairo_hash_table_t *ids;
+ cairo_svg_graphics_state_t *graphics_state;
+ cairo_t *cr;
+ double units_per_em;
+ struct {
+ cairo_svg_element_t *paint_server;
+ cairo_pattern_t *pattern;
+ build_pattern_t type;
+ } build_pattern;
+ int render_element_tree_depth;
+ int num_palette_entries;
+ FT_Color* palette;
+
+ /* Viewport */
+ double width;
+ double height;
+ cairo_bool_t view_port_set;
+
+ cairo_pattern_t *foreground_marker;
+ cairo_pattern_t *foreground_source;
+ cairo_bool_t foreground_source_used;
+
+ int debug; /* 0 = quiet, 1 = errors, 2 = warnings, 3 = info */
+} cairo_svg_glyph_render_t;
+
+
+#define SVG_RENDER_ERROR 1
+#define SVG_RENDER_WARNING 2
+#define SVG_RENDER_INFO 3
+
+#define print_error(render, ...) cairo_svg_glyph_render_printf(render, SVG_RENDER_ERROR, ##__VA_ARGS__)
+#define print_warning(render, ...) cairo_svg_glyph_render_printf(render, SVG_RENDER_WARNING, ##__VA_ARGS__)
+#define print_info(render, ...) cairo_svg_glyph_render_printf(render, SVG_RENDER_INFO, ##__VA_ARGS__)
+
+static void
+cairo_svg_glyph_render_printf (cairo_svg_glyph_render_t *svg_render,
+ int level,
+ const char *fmt, ...) CAIRO_PRINTF_FORMAT (3, 4);
+
+static void
+cairo_svg_glyph_render_printf (cairo_svg_glyph_render_t *svg_render,
+ int level,
+ const char *fmt, ...)
+{
+ va_list ap;
+
+ if (svg_render->debug >= level ) {
+ switch (level) {
+ case SVG_RENDER_ERROR:
+ printf("ERROR: ");
+ break;
+ case SVG_RENDER_WARNING:
+ printf("WARNING: ");
+ break;
+ }
+ va_start (ap, fmt);
+ vprintf (fmt, ap);
+ va_end (ap);
+ printf ("\n");
+ }
+}
+
+static cairo_bool_t
+string_equal (const char *s1, const char *s2)
+{
+ if (s1 && s2)
+ return strcmp (s1, s2) == 0;
+
+ if (!s1 && !s2)
+ return TRUE;
+
+ return FALSE;
+}
+
+static cairo_bool_t
+string_match (const char **p, const char *str)
+{
+ if (*p && strncmp (*p, str, strlen (str)) == 0) {
+ *p += strlen (str);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static const char *
+skip_space (const char *p)
+{
+ while (*p && _cairo_isspace (*p))
+ p++;
+
+ return p;
+}
+
+/* Skip over character c and and whitespace before or after. Returns
+ * NULL if c not found. */
+static const char *
+skip_char (const char *p, char c)
+{
+ while (_cairo_isspace (*p))
+ p++;
+
+ if (*p != c)
+ return NULL;
+
+ p++;
+
+ while (_cairo_isspace (*p))
+ p++;
+
+ return p;
+}
+
+static int
+_color_name_compare (const void *a, const void *b)
+{
+ const color_name_t *a_color = a;
+ const color_name_t *b_color = b;
+
+ return strcmp (a_color->name, b_color->name);
+}
+
+static void
+init_element_id_key (cairo_svg_element_t *element)
+{
+ element->base.hash = _cairo_hash_string (element->id);
+}
+
+static cairo_bool_t
+_element_id_equal (const void *key_a, const void *key_b)
+{
+ const cairo_svg_element_t *a = key_a;
+ const cairo_svg_element_t *b = key_b;
+
+ return string_equal (a->id, b->id);
+}
+
+/* Find element with the "id" attribute matching id. id may have the
+ * '#' prefix. It will be stripped before searching.
+ */
+static cairo_svg_element_t *
+lookup_element (cairo_svg_glyph_render_t *svg_render, const char *id)
+{
+ cairo_svg_element_t key;
+
+ if (!id || strlen (id) < 1)
+ return NULL;
+
+ key.id = (char *)(id[0] == '#' ? id + 1 : id);
+ init_element_id_key (&key);
+ return _cairo_hash_table_lookup (svg_render->ids, &key.base);
+}
+
+/* Find element with the "id" attribute matching url where url is of
+ * the form "url(#id)".
+ */
+static cairo_svg_element_t *
+lookup_url_element (cairo_svg_glyph_render_t *svg_render, const char *url)
+{
+ const char *p = url;
+ cairo_svg_element_t *element = NULL;
+
+ if (p && string_match (&p, "url")) {
+ p = skip_char (p, '(');
+ if (!p)
+ return NULL;
+
+ const char *end = strpbrk(p, WHITE_SPACE_CHARS ")");
+ if (end) {
+ char *id = _cairo_strndup (p, end - p);
+ element = lookup_element (svg_render, id);
+ free (id);
+ }
+ }
+ return element;
+}
+
+static const char *
+get_attribute (const cairo_svg_element_t *element, const char *name)
+{
+ svg_attribute_t attr;
+ int num_elems, i;
+
+ num_elems = _cairo_array_num_elements (&element->attributes);
+ for (i = 0; i < num_elems; i++) {
+ _cairo_array_copy_element (&element->attributes, i, &attr);
+ if (string_equal (attr.name, name))
+ return attr.value;
+ }
+ return NULL;
+}
+
+static const char *
+get_href_attribute (const cairo_svg_element_t *element)
+{
+ svg_attribute_t attr;
+ int num_elems, i, len;
+
+ /* SVG2 requires the href attribute to be "href". Older versions
+ * used "xlink:href". I have seen at least one font that used an
+ * alternative name space eg "ns1:href". To keep things simple we
+ * search for an attribute named "href" or ending in ":href".
+ */
+ num_elems = _cairo_array_num_elements (&element->attributes);
+ for (i = 0; i < num_elems; i++) {
+ _cairo_array_copy_element (&element->attributes, i, &attr);
+ if (string_equal (attr.name, "href"))
+ return attr.value;
+
+ len = strlen (attr.name);
+ if (len > 4 && string_equal (attr.name + len - 5, ":href"))
+ return attr.value;
+ }
+ return NULL;
+}
+
+/* Get a float attribute or float percentage. If attribute is a
+ * percentage, the returned value is percentage * scale. Does not
+ * modify value if it returns FALSE. This allows value to be set to a
+ * default before calling get_float_attribute(), then used without
+ * checking the return value of this function.
+ */
+static cairo_bool_t
+get_float_or_percent_attribute (const cairo_svg_element_t *element,
+ const char *name,
+ double scale,
+ double *value)
+{
+ const char *p;
+ char *end;
+ double v;
+
+ p = get_attribute (element, name);
+ if (p) {
+ v = _cairo_strtod (p, &end);
+ if (end != p) {
+ *value = v;
+ if (*end == '%')
+ *value *= scale / 100.0;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/* Does not modify value if it returns FALSE. This allows value to be
+ * set to a default before calling get_float_attribute(), then used
+ * without checking the return value of this function.
+ */
+static cairo_bool_t
+get_float_attribute (const cairo_svg_element_t *element, const char *name, double *value)
+{
+ const char *p;
+ char *end;
+ double v;
+
+ p = get_attribute (element, name);
+ if (p) {
+ v = _cairo_strtod (p, &end);
+ if (end != p) {
+ *value = v;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static cairo_fill_rule_t
+get_fill_rule_attribute (const cairo_svg_element_t *element, const char *name, cairo_fill_rule_t default_value)
+{
+ const char *p;
+
+ p = get_attribute (element, name);
+ if (string_equal (p, "nonzero"))
+ return CAIRO_FILL_RULE_WINDING;
+ else if (string_equal (p, "evenodd"))
+ return CAIRO_FILL_RULE_EVEN_ODD;
+ else
+ return default_value;
+}
+
+static void
+free_elements (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element)
+{
+ int num_elems;
+
+ num_elems = _cairo_array_num_elements (&element->children);
+ for (int i = 0; i < num_elems; i++) {
+ cairo_svg_element_t *child;
+ _cairo_array_copy_element (&element->children, i, &child);
+ free_elements (svg_render, child);
+ }
+ _cairo_array_fini (&element->children);
+
+ num_elems = _cairo_array_num_elements (&element->attributes);
+ for (int i = 0; i < num_elems; i++) {
+ svg_attribute_t *attr = _cairo_array_index (&element->attributes, i);
+ free (attr->name);
+ free (attr->value);
+ }
+ _cairo_array_fini (&element->attributes);
+ _cairo_array_fini (&element->content);
+
+ free (element->tag);
+
+ if (element->id) {
+ _cairo_hash_table_remove (svg_render->ids, &element->base);
+ free (element->id);
+ }
+
+ if (element->pattern)
+ cairo_pattern_destroy (element->pattern);
+
+ free (element);
+}
+
+#if SVG_RENDER_PRINT_FUNCTIONS
+
+static void indent(int level)
+{
+ for (int i = 1; i < level; i++)
+ printf(" ");
+}
+
+static void
+print_element (cairo_svg_element_t *element, cairo_bool_t recurse, int level)
+{
+ char *content = strndup (_cairo_array_index_const (&element->content, 0),
+ _cairo_array_num_elements (&element->content));
+
+ indent(level);
+ if (element->type == COMMENT) {
+ printf("<!--%s-->\n", content);
+ } else if (element->type == CDATA) {
+ printf("<![CDATA[%s]]>\n", content);
+ } else if (element->type == DOCTYPE) {
+ printf("<!DOCTYPE%s>\n", content);
+ } else if (element->type == PROCESSING_INSTRUCTION) {
+ printf("<?%s?>\n", content);
+ } else {
+ cairo_bool_t top_element = string_equal (element->tag, TOP_ELEMENT_TAG);
+
+ if (!top_element) {
+ printf("<%s", element->tag);
+ int num_elems = _cairo_array_num_elements (&element->attributes);
+ for (int i = 0; i < num_elems; i++) {
+ svg_attribute_t *attr = _cairo_array_index (&element->attributes, i);
+ printf(" %s=\"%s\"", attr->name, attr->value);
+ }
+ if (num_elems > 0)
+ printf(" ");
+
+ if (element->type == EMPTY_ELEMENT)
+ printf("/>\n");
+ else
+ printf(">\n");
+ }
+
+ if (element->type == CONTAINER_ELEMENT) {
+ if (recurse) {
+ int num_elems = _cairo_array_num_elements (&element->children);
+ for (int i = 0; i < num_elems; i++) {
+ cairo_svg_element_t *child;
+ _cairo_array_copy_element (&element->children, i, &child);
+ print_element (child, TRUE, level + 1);
+ }
+ }
+ if (!top_element)
+ printf("</%s>\n", element->tag);
+ }
+ }
+ free (content);
+}
+#endif
+
+static const char *
+parse_list_of_floats (const char *p,
+ int num_required,
+ int num_optional,
+ cairo_bool_t *have_optional,
+ va_list ap)
+{
+ double d;
+ double *dp;
+ char *end;
+ const char *q = NULL;
+ int num_found = 0;
+
+ for (int i = 0; i < num_required + num_optional; i++) {
+ while (p && (*p == ',' || _cairo_isspace (*p)))
+ p++;
+
+ if (!p)
+ break;
+
+ d = _cairo_strtod (p, &end);
+ if (end == p) {
+ p = NULL;
+ break;
+ }
+ p = end;
+ dp = va_arg (ap, double *);
+ *dp = d;
+ num_found++;
+ if (num_found == num_required)
+ q = p;
+ }
+
+ if (num_optional > 0) {
+ if (num_found == num_required + num_optional) {
+ *have_optional = TRUE;
+ } else {
+ *have_optional = FALSE;
+ /* restore pointer to end of required floats */
+ p = q;
+ }
+ }
+
+ return p;
+}
+
+static const char *
+get_floats (const char *p,
+ int num_required,
+ int num_optional,
+ cairo_bool_t *have_optional,
+ ...)
+{
+ va_list ap;
+
+ va_start (ap, have_optional);
+ p = parse_list_of_floats (p, num_required, num_optional, have_optional, ap);
+ va_end (ap);
+ return p;
+}
+
+static const char *
+get_path_params (const char *p, int num_params, ...)
+{
+ va_list ap;
+
+ va_start (ap, num_params);
+ p = parse_list_of_floats (p, num_params, 0, NULL, ap);
+ va_end (ap);
+ return p;
+}
+
+static cairo_bool_t
+get_color (cairo_svg_glyph_render_t *svg_render,
+ const char *s,
+ cairo_svg_color_t *color)
+{
+ int len, matched;
+ unsigned r = 0, g = 0, b = 0;
+
+ if (!s)
+ return FALSE;
+
+ len = strlen(s);
+
+ if (string_equal (s, "inherit")) {
+ return FALSE;
+ } else if (string_equal (s, "currentColor") ||
+ string_equal (s, "context-fill") ||
+ string_equal (s, "context-stroke"))
+ {
+ *color = svg_render->graphics_state->color;
+ return TRUE;
+ } else if (len > 0 && s[0] == '#') {
+ if (len == 4) {
+ matched = sscanf (s + 1, "%1x%1x%1x", &r, &g, &b);
+ if (matched == 3) {
+ /* Each digit is repeated to convert to 6 digits. eg 0x123 -> 0x112233 */
+ color->type = RGB;
+ color->red = 0x11*r/255.0;
+ color->green = 0x11*g/255.0;
+ color->blue = 0x11*b/255.0;
+ return TRUE;
+ }
+ } else if (len == 7) {
+ matched = sscanf (s + 1, "%2x%2x%2x", &r, &g, &b);
+ if (matched == 3) {
+ color->type = RGB;
+ color->red = r/255.0;
+ color->green = g/255.0;
+ color->blue = b/255.0;
+ return TRUE;
+ }
+ }
+ } else if (strncmp (s, "rgb", 3) == 0) {
+ matched = sscanf (s, "rgb ( %u , %u , %u )", &r, &g, &b);
+ if (matched == 3) {
+ color->type = RGB;
+ color->red = r/255.0;
+ color->green = g/255.0;
+ color->blue = b/255.0;
+ return TRUE;
+ }
+ } else if (strncmp (s, "var", 3) == 0) {
+ /* CPAL palettes colors. eg "var(--color0, yellow)" */
+ s += 3;
+ s = skip_char (s, '(');
+ if (!string_match (&s, "--color"))
+ return FALSE;
+
+ char *end;
+ int entry = strtol (s, &end, 10);
+ if (end == s)
+ return FALSE;
+
+ if (svg_render->palette && entry >= 0 && entry < svg_render->num_palette_entries) {
+ FT_Color *palette_color = &svg_render->palette[entry];
+ color->type = RGB;
+ color->red = palette_color->red / 255.0;
+ color->green = palette_color->green/ 255.0;
+ color->blue = palette_color->blue / 255.0;
+ return TRUE;
+ } else {
+ /* Fallback color */
+ s = skip_char (end, ',');
+ if (!s)
+ return FALSE;
+
+ end = strpbrk(s, WHITE_SPACE_CHARS ")");
+ if (!end || end == s)
+ return FALSE;
+
+ char *fallback = _cairo_strndup (s, end - s);
+ cairo_bool_t success = get_color (svg_render, fallback, color);
+ free (fallback);
+ return success;
+ }
+ } else {
+ const color_name_t *color_name;
+ color_name_t color_name_key;
+
+ color_name_key.name = (char *) s;
+ color_name = bsearch (&color_name_key,
+ color_names,
+ ARRAY_LENGTH (color_names),
+ sizeof (color_name_t),
+ _color_name_compare);
+ if (color_name) {
+ color->type = RGB;
+ color->red = color_name->red/255.0;
+ color->green = color_name->green/255.0;
+ color->blue = color_name->blue/255.0;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static void
+get_paint (cairo_svg_glyph_render_t *svg_render,
+ const char *p,
+ cairo_svg_paint_t *paint)
+{
+ cairo_svg_element_t *element;
+
+ if (string_match (&p, "none")) {
+ paint->type = PAINT_NONE;
+ paint->paint_server = NULL;
+ } else if (p && strncmp (p, "url", 3) == 0) {
+ element = lookup_url_element (svg_render, p);
+ if (element) {
+ paint->type = PAINT_SERVER;
+ paint->paint_server = element;
+ }
+ } else {
+ if (get_color (svg_render, p, &paint->color)) {
+ paint->type = PAINT_COLOR;
+ paint->paint_server = NULL;
+ }
+ }
+}
+
+#ifdef SVG_RENDER_PRINT_FUNCTIONS
+
+static void
+print_color (cairo_svg_color_t *color)
+{
+ switch (color->type) {
+ case FOREGROUND_COLOR:
+ printf("foreground");
+ break;
+ case RGB:
+ printf("#%02x%02x%02x",
+ (int)(color->red*255),
+ (int)(color->red*255),
+ (int)(color->red*255));
+ break;
+ }
+}
+
+static void
+print_paint (cairo_svg_paint_t *paint)
+{
+ printf("Paint: ");
+ switch (paint->type) {
+ case PAINT_COLOR:
+ printf("color: ");
+ print_color (&paint->color);
+ break;
+ case PAINT_SERVER:
+ printf("server: %s", paint->paint_server->tag);
+ break;
+ case PAINT_NONE:
+ printf("none");
+ break;
+ }
+ printf("\n");
+}
+
+#endif
+
+static void
+parse_error (cairo_svg_glyph_render_t *svg_render,
+ const char *string,
+ const char *location,
+ const char *fmt,
+ ...) CAIRO_PRINTF_FORMAT (4, 5);
+
+static void
+parse_error (cairo_svg_glyph_render_t *svg_render,
+ const char *string,
+ const char *location,
+ const char *fmt,
+ ...)
+{
+ va_list ap;
+ const int context = 40;
+ const char *start;
+ const char *end;
+
+ if (svg_render->debug >= SVG_RENDER_ERROR) {
+ printf("ERROR: ");
+ va_start (ap, fmt);
+ vprintf (fmt, ap);
+ va_end (ap);
+ putchar ('\n');
+ start = location - context;
+ if (start < string)
+ start = string;
+
+ end = location + strlen (location);
+ if (end - location > context)
+ end = location + context;
+
+ for (const char *p = start; p < end; p++) {
+ if (_cairo_isspace (*p))
+ putchar (' ');
+ else
+ putchar (*p);
+ }
+ putchar ('\n');
+
+ for (int i = 0; i < location - start; i++)
+ putchar(' ');
+ putchar ('^');
+ putchar ('\n');
+ printf (" at position %td\n", location - string);
+ }
+}
+
+static cairo_bool_t
+append_attribute (cairo_svg_element_t *element, svg_attribute_t *attribute)
+{
+ const char *p;
+ const char *end;
+ svg_attribute_t attr;
+
+ memset (&attr, 0, sizeof (attr));
+ if (string_equal (attribute->name, "style")) {
+ /* split style into individual attributes */
+ p = attribute->value;
+ while (*p) {
+ end = strchr (p, ':');
+ if (!end || end == p)
+ break;
+ attr.name = _cairo_strndup (p, end - p);
+ p = end + 1;
+ p = skip_space(p);
+ end = strchr (p, ';');
+ if (!end)
+ end = strchr (p, 0);
+ if (end == p)
+ goto split_style_fail;
+
+ attr.value = _cairo_strndup (p, end - p);
+ if (*end)
+ p = end + 1;
+
+ if (_cairo_array_append (&element->attributes, &attr))
+ goto split_style_fail;
+
+ memset (&attr, 0, sizeof (attr));
+ p = skip_space (p);
+ }
+ }
+
+ if (_cairo_array_append (&element->attributes, attribute))
+ return FALSE;
+
+ return TRUE;
+
+ split_style_fail:
+ free (attr.name);
+ free (attr.value);
+ return FALSE;
+}
+
+static cairo_bool_t
+add_child_element (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *parent,
+ cairo_svg_element_t *child)
+{
+ cairo_status_t status;
+ const char* id;
+
+ id = get_attribute (child, "id");
+ if (id) {
+ child->id = strdup (id);
+ init_element_id_key (child);
+ status = _cairo_hash_table_insert (svg_render->ids, &child->base);
+ if (unlikely (status))
+ return FALSE;
+ }
+
+ status = _cairo_array_append (&parent->children, &child);
+ return status == CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_svg_element_t *
+create_element (tag_type_t type, char *tag)
+{
+ cairo_svg_element_t *elem;
+ cairo_status_t status;
+
+ elem = _cairo_malloc (sizeof (cairo_svg_element_t));
+ if (unlikely (elem == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ return NULL;
+ }
+
+ elem->type = type;
+ elem->tag = tag;
+ elem->id = NULL;
+ _cairo_array_init (&elem->attributes, sizeof(svg_attribute_t));
+ _cairo_array_init (&elem->children, sizeof(cairo_svg_element_t *));
+ _cairo_array_init (&elem->content, sizeof(char));
+ elem->pattern = NULL;
+ elem->next = NULL;
+
+ return elem;
+}
+
+static const char *
+parse_attributes (cairo_svg_glyph_render_t *svg_render,
+ const char *attributes,
+ cairo_svg_element_t *element)
+{
+ svg_attribute_t attr;
+ char quote_char;
+ const char *p;
+ const char *end;
+
+ p = attributes;
+ memset (&attr, 0, sizeof (svg_attribute_t));
+ p = skip_space (p);
+ while (*p && *p != '/' && *p != '>' && *p != '?') {
+ end = strpbrk(p, WHITE_SPACE_CHARS "=");
+ if (!end) {
+ parse_error (svg_render, attributes, p, "Could not find '='");
+ goto fail;
+ }
+
+ if (end == p) {
+ parse_error (svg_render, attributes, p, "Missing attribute name");
+ goto fail;
+ }
+
+ attr.name = _cairo_strndup (p, end - p);
+ p = end;
+
+ p = skip_space (p);
+ if (*p != '=') {
+ parse_error (svg_render, attributes, p, "Expected '='");
+ goto fail;
+ }
+
+ p++;
+ p = skip_space (p);
+ if (*p == '\"' || *p == '\'') {
+ quote_char = *p;
+ } else {
+ parse_error (svg_render, attributes, p, "Could not find '\"' or '''");
+ goto fail;
+ }
+
+ p++;
+ end = strchr (p, quote_char);
+ if (!end) {
+ parse_error (svg_render, attributes, p, "Could not find '%c'", quote_char);
+ goto fail;
+ }
+
+ attr.value = _cairo_strndup (p, end - p);
+ p = end + 1;
+
+ if (!append_attribute (element, &attr))
+ goto fail;
+
+ memset (&attr, 0, sizeof (svg_attribute_t));
+
+ p = skip_space (p);
+ }
+
+ return p;
+
+ fail:
+ free (attr.name);
+ free (attr.value);
+ return NULL;
+}
+
+static cairo_bool_t
+parse_svg (cairo_svg_glyph_render_t *svg_render,
+ const char *svg_document)
+{
+ const char *p = svg_document;
+ const char *end;
+ int nesting; /* when > 0 we parse content */
+ cairo_svg_element_t *open_elem; /* Stack of open elements */
+ cairo_svg_element_t *new_elem = NULL;
+ char *name;
+ cairo_status_t status;
+
+ /* Create top level element to use as a container for all top
+ * level elements in the document and push it on the stack. */
+ open_elem = create_element (CONTAINER_ELEMENT, strdup(TOP_ELEMENT_TAG));
+
+ /* We don't want to add content to the top level container. There
+ * should only be whitesapce between tags. */
+ nesting = 0;
+
+ while (*p) {
+ if (nesting > 0) {
+ /* In an open element. Anything before the next '<' is content */
+ end = strchr (p, '<');
+ if (!end) {
+ parse_error (svg_render, svg_document, p, "Could not find '<'");
+ goto fail;
+ }
+ status = _cairo_array_append_multiple (&open_elem->content, p, end - p);
+ p = end;
+
+ } else {
+ p = skip_space (p);
+ if (*p == 0)
+ break; /* end of document */
+ }
+
+ /* We should now be at the start of a tag */
+ if (*p != '<') {
+ parse_error (svg_render, svg_document, p, "Could not find '<'");
+ goto fail;
+ }
+
+ p++;
+ if (*p == '!') {
+ p++;
+ if (string_match (&p, "[CDATA[")) {
+ new_elem = create_element (CDATA, NULL);
+ end = strstr (p, "]]>");
+ if (!end) {
+ parse_error (svg_render, svg_document, p, "Could not find ']]>'");
+ goto fail;
+ }
+
+ status = _cairo_array_append_multiple (&new_elem->content, p, end - p);
+ p = end + 3;
+ } else if (string_match (&p, "--")) {
+ new_elem = create_element (COMMENT, NULL);
+ end = strstr (p, "-->");
+ if (!end) {
+ parse_error (svg_render, svg_document, p, "Could not find '-->'");
+ goto fail;
+ }
+
+ status = _cairo_array_append_multiple (&new_elem->content, p, end - p);
+ p = end + 3;
+ } else if (string_match (&p, "DOCTYPE")) {
+ new_elem = create_element (DOCTYPE, NULL);
+ end = strchr (p, '>');
+ if (!end) {
+ parse_error (svg_render, svg_document, p, "Could not find '>'");
+ goto fail;
+ }
+
+ status = _cairo_array_append_multiple (&new_elem->content, p, end - p);
+ p = end + 1;
+ } else {
+ parse_error (svg_render, svg_document, p, "Invalid");
+ goto fail;
+ }
+
+ if (!add_child_element (svg_render, open_elem, new_elem))
+ goto fail;
+
+ new_elem = NULL;
+ continue;
+ }
+
+ if (*p == '?') {
+ p++;
+ new_elem = create_element (PROCESSING_INSTRUCTION, NULL);
+ end = strstr (p, "?>");
+ if (!end) {
+ parse_error (svg_render, svg_document, p, "Could not find '?>'");
+ goto fail;
+ }
+
+ status = _cairo_array_append_multiple (&new_elem->content, p, end - p);
+ p = end + 2;
+
+ if (!add_child_element (svg_render, open_elem, new_elem))
+ goto fail;
+
+ new_elem = NULL;
+ continue;
+ }
+
+ if (*p == '/') {
+ /* Closing tag */
+ p++;
+
+ /* find end of tag name */
+ end = strpbrk(p, WHITE_SPACE_CHARS ">");
+ if (!end) {
+ parse_error (svg_render, svg_document, p, "Could not find '>'");
+ goto fail;
+ }
+
+ name = _cairo_strndup (p, end - p);
+ p = end;
+ p = skip_space (p);
+ if (*p != '>') {
+ parse_error (svg_render, svg_document, p, "Could not find '>'");
+ free (name);
+ goto fail;
+ }
+
+ p++;
+ if (nesting == 0) {
+ parse_error (svg_render, svg_document, p, "parse_elements: parsed </%s> but no matching start tag", name);
+ free (name);
+ goto fail;
+ }
+ if (!string_equal (name, open_elem->tag)) {
+ parse_error (svg_render, svg_document, p,
+ "parse_elements: found </%s> but current open tag is <%s>",
+ name, open_elem->tag);
+ free (name);
+ goto fail;
+ }
+
+ /* pop top element on open elements stack into new_elem */
+ new_elem = open_elem;
+ open_elem = open_elem->next;
+ new_elem->next = NULL;
+ nesting--;
+
+ free (name);
+ if (!add_child_element (svg_render, open_elem, new_elem))
+ goto fail;
+
+ new_elem = NULL;
+ continue;
+ }
+
+ /* We should now be in a start or empty element tag */
+
+ /* find end of tag name */
+ end = strpbrk(p, WHITE_SPACE_CHARS "/>");
+ if (!end) {
+ parse_error (svg_render, svg_document, p, "Could not find '>'");
+ goto fail;
+ }
+
+ name = _cairo_strndup (p, end - p);
+ p = end;
+
+ new_elem = create_element (CONTAINER_ELEMENT, name);
+ p = parse_attributes (svg_render, p, new_elem);
+ if (!p)
+ goto fail;
+
+ p = skip_space (p);
+ if (*p == '/') {
+ new_elem->type = EMPTY_ELEMENT;
+ p++;
+ }
+
+ if (!p || *p != '>') {
+ print_error (svg_render, "Could not find '>'");
+ goto fail;
+ }
+
+ p++;
+ if (new_elem->type == EMPTY_ELEMENT) {
+ if (!add_child_element (svg_render, open_elem, new_elem))
+ goto fail;
+
+ new_elem = NULL;
+ } else {
+ /* push new elem onto open elements stack */
+ new_elem->next = open_elem;
+ open_elem = new_elem;
+ new_elem = NULL;
+ nesting++;
+ }
+ }
+
+ if (nesting != 0) {
+ parse_error (svg_render, svg_document, p, "Missing closing tag for <%s>", open_elem->tag);
+ goto fail;
+ }
+
+ svg_render->tree = open_elem;
+ return TRUE;
+
+ fail:
+ if (new_elem)
+ free_elements (svg_render, new_elem);
+
+ while (open_elem) {
+ cairo_svg_element_t *elem = open_elem;
+ open_elem = open_elem->next;
+ free_elements (svg_render, elem);
+ }
+
+ return FALSE;
+}
+
+static cairo_bool_t
+parse_transform (const char *p, cairo_matrix_t *matrix)
+{
+ cairo_matrix_t m;
+ double x, y, a;
+ cairo_bool_t have_optional;
+
+ cairo_matrix_init_identity (matrix);
+ while (p) {
+ while (p && (*p == ',' || _cairo_isspace (*p)))
+ p++;
+
+ if (!p || *p == 0)
+ break;
+
+ if (string_match (&p, "matrix")) {
+ p = skip_char (p, '(');
+ if (!p)
+ break;
+
+ p = get_floats (p, 6, 0, NULL, &m.xx, &m.yx, &m.xy, &m.yy, &m.x0, &m.y0);
+ if (!p)
+ break;
+
+ p = skip_char (p, ')');
+ if (!p)
+ break;
+
+ cairo_matrix_multiply (matrix, &m, matrix);
+
+ } else if (string_match (&p, "translate")) {
+ p = skip_char (p, '(');
+ if (!p)
+ break;
+
+ p = get_floats (p, 1, 1, &have_optional, &x, &y);
+ if (!p)
+ break;
+
+ p = skip_char (p, ')');
+ if (!p)
+ break;
+
+ if (!have_optional)
+ y = 0;
+
+ cairo_matrix_translate (matrix, x, y);
+
+ } else if (string_match (&p, "scale")) {
+ p = skip_char (p, '(');
+ if (!p)
+ break;
+
+ p = get_floats (p, 1, 1, &have_optional, &x, &y);
+ if (!p)
+ break;
+
+ p = skip_char (p, ')');
+ if (!p)
+ break;
+
+ if (!have_optional)
+ y = x;
+
+ cairo_matrix_scale (matrix, x, y);
+
+ } else if (string_match (&p, "rotate")) {
+ p = skip_char (p, '(');
+ if (!p)
+ break;
+
+ p = get_floats (p, 1, 2, &have_optional, &a, &x, &y);
+ if (!p)
+ break;
+
+ p = skip_char (p, ')');
+ if (!p)
+ break;
+
+ if (!have_optional) {
+ x = 0;
+ y = 0;
+ }
+
+ a *= M_PI/180.0;
+ cairo_matrix_translate (matrix, x, y);
+ cairo_matrix_rotate (matrix, a);
+ cairo_matrix_translate (matrix, -x, -y);
+
+ } else if (string_match (&p, "skewX")) {
+ p = skip_char (p, '(');
+ if (!p)
+ break;
+
+ p = get_floats (p, 1, 0, NULL, &a);
+ if (!p)
+ break;
+
+ p = skip_char (p, ')');
+ if (!p)
+ break;
+
+ a *= M_PI/180.0;
+ cairo_matrix_init_identity (&m);
+ m.xy = tan (a);
+ cairo_matrix_multiply (matrix, &m, matrix);
+
+ } else if (string_match (&p, "skewY")) {
+ p = skip_char (p, '(');
+ if (!p)
+ break;
+
+ p = get_floats (p, 1, 0, NULL, &a);
+ if (!p)
+ break;
+
+ p = skip_char (p, ')');
+ if (!p)
+ break;
+
+ a *= M_PI/180.0;
+ cairo_matrix_init_identity (&m);
+ m.yx = tan (a);
+ cairo_matrix_multiply (matrix, &m, matrix);
+
+ } else {
+ break;
+ }
+ }
+ return p != NULL;
+}
+
+static void
+render_element_tree (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element,
+ cairo_svg_element_t *display_element,
+ cairo_bool_t children_only);
+
+static cairo_pattern_t *
+create_pattern (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *paint_server)
+{
+ cairo_pattern_t *pattern = NULL;
+
+ if (paint_server) {
+ svg_render->build_pattern.paint_server = paint_server;
+ render_element_tree (svg_render, paint_server, NULL, FALSE);
+ pattern = svg_render->build_pattern.pattern;
+ svg_render->build_pattern.pattern = NULL;
+ svg_render->build_pattern.paint_server = NULL;
+ svg_render->build_pattern.type = BUILD_PATTERN_NONE;
+ }
+
+ if (!pattern)
+ pattern = cairo_pattern_create_rgb (0, 0, 0);
+
+ return pattern;
+}
+
+static cairo_bool_t
+render_element_svg (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element,
+ cairo_bool_t end_tag)
+{
+ double width, height;
+ double vb_x, vb_y, vb_height, vb_width;
+ const char *p;
+ const char *end;
+
+ if (end_tag)
+ return FALSE;
+
+ /* Default viewport width, height is EM square */
+ if (!get_float_or_percent_attribute (element, "width", svg_render->units_per_em, &width))
+ width = svg_render->units_per_em;
+
+ if (!get_float_or_percent_attribute (element, "height", svg_render->units_per_em, &height))
+ height = svg_render->units_per_em;
+
+ /* Transform viewport to unit square, centering it if width != height. */
+ if (width > height) {
+ cairo_scale (svg_render->cr, 1.0/width, 1.0/width);
+ cairo_translate (svg_render->cr, 0, (width - height)/2.0);
+ } else {
+ cairo_scale (svg_render->cr, 1.0/height, 1.0/height);
+ cairo_translate (svg_render->cr, (height - width)/2.0, 0);
+ }
+
+ svg_render->width = width;
+ svg_render->height = height;
+
+ p = get_attribute (element, "viewBox");
+ if (p) {
+ /* Transform viewport to viewbox */
+ end = get_path_params (p, 4, &vb_x, &vb_y, &vb_width, &vb_height);
+ if (!end) {
+ print_warning (svg_render, "viewBox expected 4 numbers: %s", p);
+ return FALSE;
+ }
+ cairo_translate (svg_render->cr, -vb_x * width/vb_width, -vb_y * width/vb_width);
+ cairo_scale (svg_render->cr, width/vb_width, height/vb_height);
+ svg_render->width = vb_width;
+ svg_render->height = vb_height;
+ }
+
+ svg_render->view_port_set = TRUE;
+ return TRUE;
+}
+
+static cairo_bool_t
+render_element_clip_path (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element,
+ cairo_bool_t end_tag)
+{
+ cairo_svg_graphics_state_t *gs = svg_render->graphics_state;
+ const char *p;
+
+ if (end_tag || gs->mode != GS_CLIP || svg_render->build_pattern.type != BUILD_PATTERN_NONE) {
+ return FALSE;
+ }
+
+ p = get_attribute (element, "clipPathUnits");
+ if (string_equal (p, "objectBoundingBox")) {
+ cairo_translate (svg_render->cr,
+ svg_render->graphics_state->bbox.x,
+ svg_render->graphics_state->bbox.y);
+ cairo_scale (svg_render->cr,
+ svg_render->graphics_state->bbox.width,
+ svg_render->graphics_state->bbox.height);
+ }
+
+ return TRUE;
+}
+
+static void
+apply_gradient_attributes (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element)
+{
+ cairo_pattern_t *pattern = svg_render->build_pattern.pattern;
+ cairo_bool_t object_bbox = TRUE;
+ cairo_matrix_t transform;
+ cairo_matrix_t mat;
+ const char *p;
+
+ if (!pattern)
+ return;
+
+ p = get_attribute (element, "gradientUnits");
+ if (string_equal (p, "userSpaceOnUse"))
+ object_bbox = FALSE;
+
+ cairo_matrix_init_identity (&mat);
+ if (object_bbox) {
+ cairo_matrix_translate (&mat,
+ svg_render->graphics_state->bbox.x,
+ svg_render->graphics_state->bbox.y);
+ cairo_matrix_scale (&mat,
+ svg_render->graphics_state->bbox.width,
+ svg_render->graphics_state->bbox.height);
+ }
+
+ p = get_attribute (element, "gradientTransform");
+ if (parse_transform (p, &transform))
+ cairo_matrix_multiply (&mat, &transform, &mat);
+
+ if (cairo_matrix_invert (&mat) == CAIRO_STATUS_SUCCESS)
+ cairo_pattern_set_matrix (pattern, &mat);
+
+ p = get_attribute (element, "spreadMethod");
+ if (string_equal (p, "reflect"))
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REFLECT);
+ else if (string_equal (p, "repeat"))
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
+}
+
+static cairo_bool_t
+render_element_linear_gradient (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element,
+ cairo_bool_t end_tag)
+{
+ double x1, y1, x2, y2;
+
+ if (svg_render->build_pattern.paint_server != element ||
+ end_tag ||
+ svg_render->build_pattern.type != BUILD_PATTERN_NONE)
+ return FALSE;
+
+ /* FIXME default value for userSpaceOnUse? */
+ double width = 1.0;
+ double height = 1.0;
+
+ if (!get_float_or_percent_attribute (element, "x1", width, &x1))
+ x1 = 0.0;
+
+ if (!get_float_or_percent_attribute (element, "y1", height, &y1))
+ y1 = 0.0;
+
+ if (!get_float_or_percent_attribute (element, "x2", width, &x2))
+ x2 = width;
+
+ if (!get_float_or_percent_attribute (element, "y2", height, &y2))
+ y2 = 0.0;
+
+ if (svg_render->build_pattern.pattern)
+ abort();
+
+ svg_render->build_pattern.pattern = cairo_pattern_create_linear (x1, y1, x2, y2);
+ svg_render->build_pattern.type = BUILD_PATTERN_LINEAR;
+ apply_gradient_attributes (svg_render, element);
+ return TRUE;
+}
+
+static cairo_bool_t
+render_element_radial_gradient (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element,
+ cairo_bool_t end_tag)
+{
+ double cx, cy, r, fx, fy;
+
+ if (svg_render->build_pattern.paint_server != element ||
+ end_tag ||
+ svg_render->build_pattern.type != BUILD_PATTERN_NONE)
+ return FALSE;
+
+ /* FIXME default value for userSpaceOnUse? */
+ double width = 1.0;
+ double height = 1.0;
+
+ if (!get_float_or_percent_attribute (element, "cx", width, &cx))
+ cx = 0.5 * width;
+
+ if (!get_float_or_percent_attribute (element, "cy", height, &cy))
+ cy = 0.5 * height;
+
+ if (!get_float_or_percent_attribute (element, "r", width, &r))
+ r = 0.5 * width;
+
+ if (!get_float_or_percent_attribute (element, "fx", width, &fx))
+ fx = cx;
+
+ if (!get_float_or_percent_attribute (element, "fy", height, &fy))
+ fy = cy;
+
+ svg_render->build_pattern.pattern = cairo_pattern_create_radial (fx, fy, 0, cx, cy, r);
+ svg_render->build_pattern.type = BUILD_PATTERN_RADIAL;
+ apply_gradient_attributes (svg_render, element);
+ return TRUE;
+}
+
+static cairo_bool_t
+render_element_stop (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element,
+ cairo_bool_t end_tag)
+{
+ double offset, opacity;
+ cairo_pattern_t *pattern = svg_render->build_pattern.pattern;
+
+ if (!pattern)
+ return FALSE;
+
+ if (cairo_pattern_get_type (pattern) != CAIRO_PATTERN_TYPE_LINEAR &&
+ cairo_pattern_get_type (pattern) != CAIRO_PATTERN_TYPE_RADIAL)
+ return FALSE;
+
+ if (!get_float_or_percent_attribute (element, "offset", 1.0, &offset))
+ return FALSE;
+
+ if (!get_float_attribute (element, "stop-opacity", &opacity))
+ opacity = 1.0;
+
+ cairo_svg_color_t color;
+ get_color (svg_render, "black", &color);
+ get_color (svg_render, get_attribute(element, "stop-color"), &color);
+ if (color.type == RGB) {
+ cairo_pattern_add_color_stop_rgba (pattern,
+ offset,
+ color.red,
+ color.green,
+ color.blue,
+ opacity);
+ } else { /* color.type == FOREGROUND */
+ double red, green, blue, alpha;
+ if (cairo_pattern_get_rgba (svg_render->foreground_source, &red, &green, &blue, &alpha) == CAIRO_STATUS_SUCCESS) {
+ svg_render->foreground_source_used = TRUE;
+ } else {
+ red = green = blue = 0;
+ alpha = 1;
+ }
+ cairo_pattern_add_color_stop_rgba (pattern, offset, red, green, blue, alpha);
+ }
+ return TRUE;
+}
+
+static cairo_bool_t
+render_element_g (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element,
+ cairo_bool_t end_tag)
+{
+ if (svg_render->graphics_state->mode == GS_NO_RENDER ||
+ svg_render->build_pattern.type != BUILD_PATTERN_NONE)
+ return FALSE;
+
+ if (!end_tag) {
+ cairo_push_group (svg_render->cr);
+ } else {
+ cairo_pop_group_to_source (svg_render->cr);
+ cairo_paint_with_alpha (svg_render->cr, svg_render->graphics_state->opacity);
+ }
+ return TRUE;
+}
+
+typedef struct {
+ const char *data; /* current position in base64 data */
+ char buf[3]; /* decode buffer */
+ int buf_pos; /* current position in buf_pos. */
+} base64_decode_t;
+
+static cairo_status_t
+_read_png_from_base64 (void *closure, unsigned char *data, unsigned int length)
+{
+ base64_decode_t *decode = closure;
+ int n, c;
+ unsigned val;
+
+ while (length) {
+ if (decode->buf_pos >= 0) {
+ *data++ = decode->buf[decode->buf_pos++];
+ length--;
+ if (decode->buf_pos == 3)
+ decode->buf_pos = -1;
+ }
+ if (length > 0 && decode->buf_pos < 0) {
+ n = 0;
+ while (*decode->data && n < 4) {
+ c = *decode->data++;
+ if (c >='A' && c <='Z') {
+ val = (val << 6) | (c -'A');
+ n++;
+ } else if (c >='a' && c <='z') {
+ val = (val << 6) | (c -'a' + 26);
+ n++;
+ } else if (c >='0' && c <='9') {
+ val = (val << 6) | (c -'0' + 52);
+ n++;
+ } else if (c =='+') {
+ val = (val << 6) | 62;
+ n++;
+ } else if (c =='/') {
+ val = (val << 6) | 63;
+ n++;
+ } else if (c == '=') {
+ val = (val << 6);
+ n++;
+ }
+ }
+ if (n < 4)
+ return CAIRO_STATUS_READ_ERROR;
+
+ decode->buf[0] = val >> 16;
+ decode->buf[1] = val >> 8;
+ decode->buf[2] = val >> 0;
+ decode->buf_pos = 0;
+ }
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_bool_t
+render_element_image (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element,
+ cairo_bool_t end_tag)
+{
+ double x, y, width, height;
+ int w, h;
+ const char *data;
+ cairo_surface_t *surface;
+ base64_decode_t decode;
+
+ if (svg_render->graphics_state->mode == GS_NO_RENDER ||
+ svg_render->build_pattern.type != BUILD_PATTERN_NONE)
+ return FALSE;
+
+ if (!get_float_attribute (element, "x", &x))
+ x = 0;
+
+ if (!get_float_attribute (element, "y", &y))
+ y = 0;
+
+ if (!get_float_attribute (element, "width", &width))
+ return FALSE;
+
+ if (!get_float_attribute (element, "height", &height))
+ return FALSE;
+
+ data = get_href_attribute (element);
+ if (!data)
+ return FALSE;
+
+ if (!string_match (&data, "data:image/png;base64,"))
+ return FALSE;
+
+ decode.data = data;
+ decode.buf_pos = -1;
+ surface = cairo_image_surface_create_from_png_stream (_read_png_from_base64, &decode);
+ if (cairo_surface_status (surface)) {
+ print_warning (svg_render, "Unable to decode PNG");
+ cairo_surface_destroy (surface);
+ return FALSE;
+ }
+
+ w = cairo_image_surface_get_width (surface);
+ h = cairo_image_surface_get_height (surface);
+
+ if (w > 0 && h > 0) {
+ cairo_translate (svg_render->cr, x, y);
+ cairo_scale (svg_render->cr, width/w, height/h);
+ cairo_set_source_surface (svg_render->cr, surface, 0, 0);
+ cairo_paint (svg_render->cr);
+ }
+
+ cairo_surface_destroy (surface);
+
+ return FALSE;
+}
+
+static cairo_bool_t
+render_element_use (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element,
+ cairo_bool_t end_tag)
+{
+ double x = 0;
+ double y = 0;
+ const char *id;
+
+ if (end_tag || svg_render->graphics_state->mode == GS_NO_RENDER ||
+ svg_render->build_pattern.type != BUILD_PATTERN_NONE)
+ return FALSE;
+
+ get_float_attribute (element, "x", &x);
+ get_float_attribute (element, "y", &y);
+
+ id = get_href_attribute (element);
+ if (!id)
+ return FALSE;
+
+ cairo_svg_element_t *use_element = lookup_element (svg_render, id);
+ cairo_translate (svg_render->cr, x, y);
+ render_element_tree (svg_render, use_element, NULL, FALSE);
+ return TRUE;
+}
+
+static cairo_bool_t
+draw_path (cairo_svg_glyph_render_t *svg_render)
+{
+ cairo_svg_graphics_state_t *gs = svg_render->graphics_state;
+ cairo_pattern_t *pattern;
+ cairo_bool_t opacity_group = FALSE;
+
+ if (gs->mode == GS_COMPUTE_BBOX) {
+ cairo_set_source_rgb (svg_render->cr, 0, 0, 0);
+ cairo_set_fill_rule (svg_render->cr, gs->fill_rule);
+ cairo_fill (svg_render->cr);
+ return FALSE;
+ } else if (gs->mode == GS_CLIP) {
+ return FALSE;
+ }
+
+ if (gs->opacity < 1.0) {
+ cairo_push_group (svg_render->cr);
+ opacity_group = TRUE;
+ }
+
+ cairo_path_t *path = cairo_copy_path (svg_render->cr);
+ cairo_new_path (svg_render->cr);
+
+ if (gs->fill.type != PAINT_NONE) {
+ cairo_bool_t group = FALSE;
+ if (gs->fill.type == PAINT_COLOR) {
+ if (gs->fill.color.type == RGB) {
+ cairo_set_source_rgba (svg_render->cr,
+ gs->fill.color.red,
+ gs->fill.color.green,
+ gs->fill.color.blue,
+ gs->fill_opacity);
+ } else if (gs->fill.color.type == FOREGROUND) {
+ cairo_set_source (svg_render->cr, svg_render->foreground_marker);
+ if (gs->fill_opacity < 1.0)
+ group = TRUE;
+ }
+ } else if (gs->fill.type == PAINT_SERVER) {
+ pattern = create_pattern (svg_render, gs->fill.paint_server);
+ cairo_set_source (svg_render->cr, pattern);
+ cairo_pattern_destroy (pattern);
+ if (gs->fill_opacity < 1.0)
+ group = TRUE;
+ }
+
+ if (group)
+ cairo_push_group (svg_render->cr);
+
+ cairo_append_path (svg_render->cr, path);
+ cairo_set_fill_rule (svg_render->cr, gs->fill_rule);
+ cairo_fill (svg_render->cr);
+ if (group) {
+ cairo_pop_group_to_source (svg_render->cr);
+ cairo_paint_with_alpha (svg_render->cr, gs->fill_opacity);
+ }
+ }
+
+ if (gs->stroke.type != PAINT_NONE) {
+ cairo_bool_t group = FALSE;
+ if (gs->stroke.type == PAINT_COLOR) {
+ if (gs->stroke.color.type == RGB) {
+ cairo_set_source_rgba (svg_render->cr,
+ gs->stroke.color.red,
+ gs->stroke.color.green,
+ gs->stroke.color.blue,
+ gs->stroke_opacity);
+ } else if (gs->fill.color.type == FOREGROUND) {
+ cairo_set_source (svg_render->cr, svg_render->foreground_marker);
+ if (gs->fill_opacity < 1.0)
+ group = TRUE;
+ }
+ } else if (gs->stroke.type == PAINT_SERVER) {
+ pattern = create_pattern (svg_render, gs->stroke.paint_server);
+ cairo_set_source (svg_render->cr, pattern);
+ cairo_pattern_destroy (pattern);
+ if (gs->stroke_opacity < 1.0)
+ group = TRUE;
+ }
+
+ if (group)
+ cairo_push_group (svg_render->cr);
+
+ cairo_append_path (svg_render->cr, path);
+ cairo_stroke (svg_render->cr);
+
+ if (group) {
+ cairo_pop_group_to_source (svg_render->cr);
+ cairo_paint_with_alpha (svg_render->cr, gs->stroke_opacity);
+ }
+ }
+
+ cairo_path_destroy (path);
+
+ if (opacity_group) {
+ cairo_pop_group_to_source (svg_render->cr);
+ cairo_paint_with_alpha (svg_render->cr, gs->opacity);
+ }
+ return TRUE;
+}
+
+static void
+elliptical_arc (cairo_svg_glyph_render_t *svg_render,
+ double cx,
+ double cy,
+ double rx,
+ double ry,
+ double angle1,
+ double angle2)
+{
+ cairo_save (svg_render->cr);
+ cairo_translate (svg_render->cr, cx, cy);
+ cairo_scale (svg_render->cr, rx, ry);
+ cairo_arc (svg_render->cr, 0, 0, 1, angle1, angle2);
+ cairo_restore (svg_render->cr);
+}
+
+static cairo_bool_t
+render_element_rect (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element,
+ cairo_bool_t end_tag)
+{
+ double x = 0;
+ double y = 0;
+ double width = svg_render->width;
+ double height = svg_render->height;
+ double rx = 0;
+ double ry = 0;
+
+ if (end_tag ||
+ svg_render->graphics_state->mode == GS_NO_RENDER ||
+ svg_render->build_pattern.type != BUILD_PATTERN_NONE)
+ return FALSE;
+
+ get_float_or_percent_attribute (element, "x", svg_render->width, &x);
+ get_float_or_percent_attribute (element, "y", svg_render->height, &y);
+ get_float_or_percent_attribute (element, "width", svg_render->width, &width);
+ get_float_or_percent_attribute (element, "height", svg_render->height, &height);
+ get_float_or_percent_attribute (element, "rx", svg_render->width, &rx);
+ get_float_or_percent_attribute (element, "ry", svg_render->height, &ry);
+
+ if (rx == 0 && ry == 0) {
+ cairo_rectangle (svg_render->cr, x, y, width, height);
+ } else {
+ cairo_move_to (svg_render->cr, x + rx, y);
+ cairo_line_to (svg_render->cr, x + width - rx, y);
+ elliptical_arc (svg_render, x + width - rx, y + ry, rx, ry, -M_PI/2, 0);
+ cairo_line_to (svg_render->cr, x + width, y + height - ry);
+ elliptical_arc (svg_render, x + width - rx, y + height - ry, rx, ry, 0, M_PI/2);
+ cairo_line_to (svg_render->cr, x + rx, y + height);
+ elliptical_arc (svg_render, x + rx, y + height - ry, rx, ry, M_PI/2, M_PI);
+ cairo_line_to (svg_render->cr, x, y + ry);
+ elliptical_arc (svg_render, x + rx, y + ry, rx, ry, M_PI, -M_PI/2);
+ }
+
+ draw_path (svg_render);
+ return TRUE;
+}
+
+static cairo_bool_t
+render_element_circle (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element,
+ cairo_bool_t end_tag)
+{
+ double cx = 0;
+ double cy = 0;
+ double r = 0;
+
+ if (end_tag ||
+ svg_render->graphics_state->mode == GS_NO_RENDER ||
+ svg_render->build_pattern.type != BUILD_PATTERN_NONE)
+ return FALSE;
+
+ get_float_or_percent_attribute (element, "cx", svg_render->width, &cx);
+ get_float_or_percent_attribute (element, "cy", svg_render->height, &cy);
+ get_float_or_percent_attribute (element, "r", svg_render->width, &r);
+
+ cairo_arc (svg_render->cr, cx, cy, r, 0, 2*M_PI);
+
+ draw_path (svg_render);
+ return TRUE;
+}
+
+static cairo_bool_t
+render_element_ellipse (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element,
+ cairo_bool_t end_tag)
+{
+ double cx = 0;
+ double cy = 0;
+ double rx = 0;
+ double ry = 0;
+
+ if (end_tag ||
+ svg_render->graphics_state->mode == GS_NO_RENDER ||
+ svg_render->build_pattern.type != BUILD_PATTERN_NONE)
+ return FALSE;
+
+ get_float_or_percent_attribute (element, "cx", svg_render->width, &cx);
+ get_float_or_percent_attribute (element, "cy", svg_render->height, &cy);
+ get_float_or_percent_attribute (element, "rx", svg_render->width, &rx);
+ get_float_or_percent_attribute (element, "ry", svg_render->height, &ry);
+
+ elliptical_arc (svg_render, cx, cy, rx, ry, 0, 2*M_PI);
+ draw_path (svg_render);
+ return TRUE;
+}
+
+static cairo_bool_t
+render_element_line (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element,
+ cairo_bool_t end_tag)
+{
+ double x1 = 0;
+ double y1 = 0;
+ double x2 = 0;
+ double y2 = 0;
+
+ if (end_tag ||
+ svg_render->graphics_state->mode == GS_NO_RENDER ||
+ svg_render->build_pattern.type != BUILD_PATTERN_NONE)
+ return FALSE;
+
+ get_float_or_percent_attribute (element, "x1", svg_render->width, &x1);
+ get_float_or_percent_attribute (element, "y1", svg_render->height, &y1);
+ get_float_or_percent_attribute (element, "x2", svg_render->width, &x2);
+ get_float_or_percent_attribute (element, "y2", svg_render->height, &y2);
+
+ cairo_move_to (svg_render->cr, x1, y1);
+ cairo_line_to (svg_render->cr, x2, y2);
+
+ draw_path (svg_render);
+ return TRUE;
+}
+
+static cairo_bool_t
+render_element_polyline (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element,
+ cairo_bool_t end_tag)
+{
+ const char *p;
+ const char *end;
+ double x, y;
+ cairo_bool_t have_move = FALSE;
+
+ if (end_tag ||
+ svg_render->graphics_state->mode == GS_NO_RENDER ||
+ svg_render->build_pattern.type != BUILD_PATTERN_NONE)
+ return FALSE;
+
+ p = get_attribute (element, "points");
+ do {
+ end = get_path_params (p, 2, &x, &y);
+ if (!end) {
+ print_warning (svg_render, "points expected 2 numbers: %s", p);
+ break;
+ }
+ p = end;
+ if (!have_move) {
+ cairo_move_to (svg_render->cr, x, y);
+ have_move = TRUE;
+ } else {
+ cairo_line_to (svg_render->cr, x, y);
+ }
+ p = skip_space (p);
+ } while (p && *p);
+
+ if (string_equal (element->tag, "polygon"))
+ cairo_close_path (svg_render->cr);
+
+ draw_path (svg_render);
+ return TRUE;
+}
+
+static double
+angle_between_vectors (double ux,
+ double uy,
+ double vx,
+ double vy)
+{
+ double dot = ux*vx + uy*vy;
+ double umag = sqrt (ux*ux + uy*uy);
+ double vmag = sqrt (vx*vx + vy*vy);
+ double c = dot/(umag*vmag);
+ if (c > 1.0)
+ c = 1.0;
+
+ if (c < -1.0)
+ c = -1.0;
+
+ double a = acos (c);
+ if (ux * vy - uy * vx < 0.0)
+ a = -a;
+
+ return a;
+}
+
+static void
+arc_path (cairo_t *cr,
+ double x1, double y1,
+ double x2, double y2,
+ double rx, double ry,
+ double rotate,
+ cairo_bool_t large_flag,
+ cairo_bool_t sweep_flag)
+{
+ double x1_, y1_, cx_, cy_;
+ double xm, ym, cx, cy;
+ double a, b, d;
+ double ux, uy, vx, vy;
+ double theta, delta_theta;
+ double epsilon;
+ cairo_matrix_t ctm;
+
+ cairo_get_matrix (cr, &ctm);
+ epsilon = _cairo_matrix_transformed_circle_major_axis (&ctm, cairo_get_tolerance (cr));
+
+ rotate *= M_PI/180.0;
+
+ /* Convert endpoint to center parameterization.
+ * See SVG 1.1 Appendix F.6. Step numbers are the steps in the appendix.
+ */
+
+ rx = fabs (rx);
+ ry = fabs (ry);
+ if (rx < epsilon || ry < epsilon) {
+ cairo_line_to (cr, x2, y2);
+ return;
+ }
+
+ if (fabs(x1 - x2) < epsilon && fabs(y1 - y2) < epsilon) {
+ cairo_line_to (cr, x2, y2);
+ return;
+ }
+
+ /* Step 1 */
+ xm = (x1 - x2)/2;
+ ym = (y1 - y2)/2;
+ x1_ = xm * cos (rotate) + ym * sin (rotate);
+ y1_ = xm * -sin (rotate) + ym * cos (rotate);
+
+ d = (x1_*x1_)/(rx*rx) + (y1_*y1_)/(ry*ry);
+ if (d > 1.0) {
+ d = sqrt (d);
+ rx *= d;
+ ry *= d;
+ }
+
+ /* Step 2 */
+ a = (rx*rx * y1_*y1_) + (ry*ry * x1_*x1_);
+ if (a == 0.0)
+ return;
+
+ b = (rx*rx * ry*ry) / a - 1.0;
+ if (b < 0)
+ b = 0.0;
+
+ d = sqrt(b);
+ if (large_flag == sweep_flag)
+ d = -d;
+
+ cx_ = d * rx*y1_/ry;
+ cy_ = d * -ry*x1_/rx;
+
+ /* Step 3 */
+ cx = cx_ * cos (rotate) - cy_ * sin (rotate) + (x1 + x2)/2;
+ cy = cx_ * sin (rotate) + cy_ * cos (rotate) + (y1 + y2)/2;
+
+ /* Step 4 */
+ ux = (x1_ - cx_)/rx;
+ uy = (y1_ - cy_)/ry;
+ vx = (-x1_ - cx_)/rx;
+ vy = (-y1_ - cy_)/ry;
+ theta = angle_between_vectors (1.0, 0, ux, uy);
+ delta_theta = angle_between_vectors (ux, uy, vx, vy);
+
+ if (!sweep_flag && delta_theta > 0)
+ delta_theta -= 2 * M_PI;
+ else if (sweep_flag && delta_theta < 0)
+ delta_theta += 2 * M_PI;
+
+ /* Now we can call cairo_arc() */
+ cairo_save (cr);
+ cairo_translate (cr, cx, cy);
+ cairo_scale (cr, rx, ry);
+ cairo_rotate (cr, theta);
+ if (delta_theta >= 0.0)
+ cairo_arc (cr, 0, 0, 1, 0, delta_theta);
+ else
+ cairo_arc_negative (cr, 0, 0, 1, 0, delta_theta);
+ cairo_restore (cr);
+}
+
+static void
+get_current_point (cairo_svg_glyph_render_t *svg_render, double *x, double *y)
+{
+ if (cairo_has_current_point (svg_render->cr)) {
+ cairo_get_current_point (svg_render->cr, x, y);
+ } else {
+ *x = 0;
+ *y = 0;
+ }
+}
+
+static void
+reflect_point (double origin_x, double origin_y, double *x, double *y)
+{
+ *x = 2*origin_x - *x;
+ *y = 2*origin_y - *y;
+}
+
+static cairo_bool_t
+render_element_path (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element,
+ cairo_bool_t end_tag)
+{
+ double cur_x, cur_y;
+ double last_cp_x, last_cp_y;
+ double x, y, x1, y1, x2, y2;
+ double qx1, qy1, qx2, qy2;
+ double rx, ry, rotate, large_flag, sweep_flag;
+ cairo_bool_t rel, have_move;
+ enum { CUBIC, QUADRATIC, OTHER } last_op;
+
+ if (end_tag ||
+ svg_render->graphics_state->mode == GS_NO_RENDER ||
+ svg_render->build_pattern.type != BUILD_PATTERN_NONE)
+ return FALSE;
+
+ last_op = OTHER;
+ const char *p = get_attribute (element, "d");
+ const char *end;
+ int op;
+
+ while (p) {
+ while (p && _cairo_isspace (*p))
+ p++;
+
+ if (!p || *p == 0)
+ break;
+
+ op = *p;
+ switch (op) {
+ case 'M':
+ case 'm':
+ rel = op == 'm';
+ p++;
+ have_move = FALSE;
+ do {
+ end = get_path_params (p, 2, &x, &y);
+ if (!end) {
+ print_warning (svg_render, "path %c expected 2 numbers: %s", op, p);
+ break;
+ }
+ p = end;
+ if (rel) {
+ get_current_point (svg_render, &cur_x, &cur_y);
+ x += cur_x;
+ y += cur_y;
+ }
+ if (!have_move) {
+ cairo_move_to (svg_render->cr, x, y);
+ have_move = TRUE;
+ } else {
+ cairo_line_to (svg_render->cr, x, y);
+ }
+ p = skip_space (p);
+ } while (p && *p && !_cairo_isalpha(*p));
+ last_op = OTHER;
+ break;
+ case 'Z':
+ case 'z':
+ p++;
+ cairo_close_path (svg_render->cr);
+ last_op = OTHER;
+ break;
+ case 'L':
+ case 'l':
+ rel = op == 'l';
+ p++;
+ do {
+ end = get_path_params (p, 2, &x, &y);
+ if (!end) {
+ print_warning (svg_render, "path %c expected 2 numbers: %s", op, p);
+ break;
+ }
+ p = end;
+ if (rel) {
+ get_current_point (svg_render, &cur_x, &cur_y);
+ x += cur_x;
+ y += cur_y;
+ }
+ cairo_line_to (svg_render->cr, x, y);
+ p = skip_space (p);
+ } while (p && *p && !_cairo_isalpha(*p));
+ last_op = OTHER;
+ break;
+ case 'H':
+ case 'h':
+ rel = op == 'h';
+ p++;
+ do {
+ end = get_path_params (p, 1, &x1);
+ if (!end) {
+ print_warning (svg_render, "path %c expected a number: %s", op, p);
+ break;
+ }
+ p = end;
+ get_current_point (svg_render, &cur_x, &cur_y);
+ if (rel) {
+ x1 += cur_x;
+ }
+ cairo_line_to (svg_render->cr, x1, cur_y);
+ p = skip_space (p);
+ } while (p && *p && !_cairo_isalpha(*p));
+ last_op = OTHER;
+ break;
+ case 'V':
+ case 'v':
+ rel = op == 'v';
+ p++;
+ do {
+ end = get_path_params (p, 1, &y1);
+ if (!end) {
+ print_warning (svg_render, "path %c expected a number: %s", op, p);
+ break;
+ }
+ p = end;
+ get_current_point (svg_render, &cur_x, &cur_y);
+ if (rel) {
+ y1 += cur_y;
+ }
+ cairo_line_to (svg_render->cr, cur_x, y1);
+ p = skip_space (p);
+ } while (p && *p && !_cairo_isalpha(*p));
+ last_op = OTHER;
+ break;
+ case 'C':
+ case 'c':
+ rel = op == 'c';
+ p++;
+ do {
+ end = get_path_params (p, 6, &x1, &y1, &x2, &y2, &x, &y);
+ if (!end) {
+ print_warning (svg_render, "path %c expected 6 numbers: %s", op, p);
+ break;
+ }
+ p = end;
+ if (rel) {
+ get_current_point (svg_render, &cur_x, &cur_y);
+ x1 += cur_x;
+ y1 += cur_y;
+ x2 += cur_x;
+ y2 += cur_y;
+ x += cur_x;
+ y += cur_y;
+ }
+ cairo_curve_to (svg_render->cr, x1, y1, x2, y2, x, y);
+ p = skip_space (p);
+ } while (p && *p && !_cairo_isalpha(*p));
+ last_op = CUBIC;
+ last_cp_x = x2;
+ last_cp_y = y2;
+ break;
+ case 'S':
+ case 's':
+ rel = op == 's';
+ p++;
+ do {
+ end = get_path_params (p, 4, &x2, &y2, &x, &y);
+ if (!end) {
+ print_warning (svg_render, "path %c expected 4 numbers: %s", op, p);
+ break;
+ }
+ p = end;
+ get_current_point (svg_render, &cur_x, &cur_y);
+ if (rel) {
+ x2 += cur_x;
+ y2 += cur_y;
+ x += cur_x;
+ y += cur_y;
+ }
+ if (last_op == CUBIC) {
+ x1 = last_cp_x;
+ y1 = last_cp_y;
+ reflect_point (cur_x, cur_y, &x1, &y1);
+ } else {
+ x1 = cur_x;
+ y1 = cur_y;
+ }
+ cairo_curve_to (svg_render->cr, x1, y1, x2, y2, x, y);
+ last_op = CUBIC;
+ last_cp_x = x2;
+ last_cp_y = y2;
+ p = skip_space (p);
+ } while (p && *p && !_cairo_isalpha(*p));
+ break;
+ case 'Q':
+ case 'q':
+ rel = op == 'q';
+ p++;
+ do {
+ end = get_path_params (p, 4, &x1, &y1, &x, &y);
+ if (!end) {
+ print_warning (svg_render, "path %c expected 4 numbers: %s", op, p);
+ break;
+ }
+ p = end;
+ get_current_point (svg_render, &cur_x, &cur_y);
+ if (rel) {
+ x1 += cur_x;
+ y1 += cur_y;
+ x += cur_x;
+ y += cur_y;
+ }
+ qx1 = cur_x + (x1 - cur_x)*2/3;
+ qy1 = cur_y + (y1 - cur_y)*2/3;
+ qx2 = x + (x1 - x)*2/3;
+ qy2 = y + (y1 - y)*2/3;
+ cairo_curve_to (svg_render->cr, qx1, qy1, qx2, qy2, x, y);
+ p = skip_space (p);
+ } while (p && *p && !_cairo_isalpha(*p));
+ last_op = QUADRATIC;
+ last_cp_x = x1;
+ last_cp_y = y1;
+ break;
+ case 'T':
+ case 't':
+ rel = op == 't';
+ p++;
+ do {
+ end = get_path_params (p, 2, &x, &y);
+ if (!end) {
+ print_warning (svg_render, "path %c expected 2 numbers: %s", op, p);
+ break;
+ }
+ p = end;
+ get_current_point (svg_render, &cur_x, &cur_y);
+ if (rel) {
+ x += cur_x;
+ y += cur_y;
+ }
+ if (last_op == QUADRATIC) {
+ x1 = last_cp_x;
+ y1 = last_cp_y;
+ reflect_point (cur_x, cur_y, &x1, &y1);
+ } else {
+ x1 = cur_x;
+ y1 = cur_y;
+ }
+ qx1 = cur_x + (x1 - cur_x)*2/3;
+ qy1 = cur_y + (y1 - cur_y)*2/3;
+ qx2 = x + (x1 - x)*2/3;
+ qy2 = y + (y1 - y)*2/3;
+ cairo_curve_to (svg_render->cr, qx1, qy1, qx2, qy2, x, y);
+ last_op = QUADRATIC;
+ last_cp_x = x1;
+ last_cp_y = y1;
+ p = skip_space (p);
+ } while (p && *p && *p && !_cairo_isalpha(*p));
+ break;
+ case 'A':
+ case 'a':
+ rel = op == 'a';
+ p++;
+ do {
+ end = get_path_params (p, 7, &rx, &ry, &rotate, &large_flag, &sweep_flag, &x, &y);
+ if (!end) {
+ print_warning (svg_render, "path %c expected 7 numbers: %s", op, p);
+ break;
+ }
+ p = end;
+ get_current_point (svg_render, &cur_x, &cur_y);
+ if (rel) {
+ x += cur_x;
+ y += cur_y;
+ }
+ arc_path (svg_render->cr,
+ cur_x, cur_y,
+ x, y,
+ rx, ry,
+ rotate,
+ large_flag > 0.5,
+ sweep_flag > 0.5);
+ p = skip_space (p);
+ } while (p && *p && !_cairo_isalpha(*p));
+ last_op = OTHER;
+ break;
+ default:
+ p = NULL;
+ break;
+ }
+ }
+
+ draw_path (svg_render);
+ return TRUE;
+}
+
+static void
+init_graphics_state (cairo_svg_glyph_render_t *svg_render)
+{
+ cairo_svg_graphics_state_t *gs;
+
+ gs = _cairo_malloc (sizeof (cairo_svg_graphics_state_t));
+ get_paint (svg_render, "black", &gs->fill);
+ get_paint (svg_render, "none", &gs->stroke);
+ gs->color.type = FOREGROUND;
+ gs->fill_opacity = 1.0;
+ gs->stroke_opacity = 1.0;
+ gs->opacity = 1.0;
+ gs->fill_rule = CAIRO_FILL_RULE_WINDING;
+ gs->clip_rule = CAIRO_FILL_RULE_WINDING;
+ gs->clip_path = NULL;
+ gs->dash_array = NULL;
+ gs->dash_offset = 0.0;
+ gs->mode = GS_RENDER;
+ gs->bbox.x = 0;
+ gs->bbox.y = 0;
+ gs->bbox.width = 0;
+ gs->bbox.height = 0;
+ gs->next = NULL;
+
+ svg_render->graphics_state = gs;
+
+ cairo_save (svg_render->cr);
+ cairo_set_source_rgb (svg_render->cr, 0, 0, 0);
+ cairo_set_line_width (svg_render->cr, 1.0);
+ cairo_set_line_cap (svg_render->cr, CAIRO_LINE_CAP_BUTT);
+ cairo_set_line_join (svg_render->cr, CAIRO_LINE_JOIN_MITER);
+ cairo_set_miter_limit (svg_render->cr, 4.0);
+}
+
+#define MAX_DASHES 100
+static void update_dash (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element)
+{
+ cairo_svg_graphics_state_t *gs = svg_render->graphics_state;
+ const char *p;
+ char *end;
+ double value;
+ double dash_array[MAX_DASHES];
+ int num_dashes = 0;
+ cairo_bool_t not_zero = FALSE;
+
+ if (gs->dash_array == NULL || string_equal (gs->dash_array, "none")) {
+ cairo_set_dash (svg_render->cr, NULL, 0, 0);
+ return;
+ }
+
+ p = gs->dash_array;
+ while (*p && num_dashes < MAX_DASHES) {
+ while (*p && (*p == ',' || _cairo_isspace (*p)))
+ p++;
+
+ if (*p == 0)
+ break;
+
+ value = _cairo_strtod (p, &end);
+ if (end == p)
+ break;
+
+ p = end;
+ if (*p == '%') {
+ value *= svg_render->width / 100.0;
+ p++;
+ }
+
+ if (value < 0.0)
+ return;
+
+ if (value > 0.0)
+ not_zero = TRUE;
+
+ dash_array[num_dashes++] = value;
+ }
+
+ if (not_zero)
+ cairo_set_dash (svg_render->cr, dash_array, num_dashes, gs->dash_offset);
+}
+
+static cairo_bool_t
+pattern_requires_bbox (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *paint_server)
+{
+ const char *p;
+
+ if (string_equal (paint_server->tag, "linearGradient") ||
+ string_equal (paint_server->tag, "radialGradient"))
+ {
+ p = get_attribute (paint_server, "gradientUnits");
+ if (string_equal (p, "userSpaceOnUse"))
+ return FALSE;
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static cairo_bool_t
+clip_requires_bbox (cairo_svg_glyph_render_t *svg_render,
+ const char *clip_path)
+{
+ cairo_svg_element_t *element;
+ const char *p;
+
+ if (clip_path && strncmp (clip_path, "url", 3) == 0) {
+ element = lookup_url_element (svg_render, clip_path);
+ if (element) {
+ p = get_attribute (element, "clipPathUnits");
+ if (string_equal (p, "objectBoundingBox"))
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static cairo_bool_t
+need_bbox (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element)
+{
+ cairo_svg_graphics_state_t *gs = svg_render->graphics_state;
+ cairo_bool_t fill_needs_bbox = FALSE;
+ cairo_bool_t stroke_needs_bbox = FALSE;
+ cairo_bool_t clip_needs_bbox = FALSE;
+
+ if (gs->mode != GS_RENDER)
+ return FALSE;
+
+ if (gs->fill.type == PAINT_SERVER && pattern_requires_bbox (svg_render, gs->fill.paint_server))
+ fill_needs_bbox = TRUE;
+
+ if (gs->stroke.type == PAINT_SERVER && pattern_requires_bbox (svg_render, gs->stroke.paint_server))
+ stroke_needs_bbox = TRUE;
+
+ if (clip_requires_bbox (svg_render, get_attribute (element, "clip-path")))
+ clip_needs_bbox = TRUE;
+
+ if (string_equal (element->tag, "circle") ||
+ string_equal (element->tag, "ellipse") ||
+ string_equal (element->tag, "path") ||
+ string_equal (element->tag, "polygon") ||
+ string_equal (element->tag, "rect"))
+ {
+ return fill_needs_bbox || stroke_needs_bbox || clip_needs_bbox;
+ }
+
+ if (string_equal (element->tag, "line") ||
+ string_equal (element->tag, "polyline"))
+ {
+ return stroke_needs_bbox || clip_needs_bbox;
+ }
+
+ if (string_equal (element->tag, "g") ||
+ string_equal (element->tag, "image") ||
+ string_equal (element->tag, "use"))
+ {
+ return clip_needs_bbox;
+ }
+
+ return FALSE;
+}
+
+static cairo_bool_t
+call_element (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element,
+ cairo_bool_t end_tag);
+
+static void
+update_graphics_state (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element)
+{
+ double value;
+ const char *p;
+ cairo_svg_graphics_state_t *gs = svg_render->graphics_state;
+
+ p = get_attribute (element, "transform");
+ if (p) {
+ cairo_matrix_t m;
+ if (parse_transform (p, &m))
+ cairo_transform (svg_render->cr, &m);
+ }
+
+ /* The transform is all we need for bbox computation. The SVG spec
+ * excludes clipping and stroke-width from the bbox. */
+ if (gs->mode == GS_COMPUTE_BBOX)
+ return;
+
+ p = get_attribute (element, "color");
+ if (p)
+ get_color (svg_render, p, &gs->color);
+
+ if (!get_float_attribute (element, "opacity", &gs->opacity))
+ gs->opacity = 1.0;
+
+ p = get_attribute (element, "fill");
+ if (p) {
+ get_paint (svg_render, p, &gs->fill);
+ }
+
+ get_float_attribute (element, "fill-opacity", &gs->fill_opacity);
+
+ gs->fill_rule = get_fill_rule_attribute (element, "fill-rule", gs->fill_rule);
+
+ gs->clip_rule = get_fill_rule_attribute (element, "fill-rule", gs->clip_rule);
+
+ p = get_attribute (element, "stroke");
+ if (p)
+ get_paint (svg_render, p, &gs->stroke);
+
+ if (get_float_or_percent_attribute (element, "stroke-width", svg_render->width, &value))
+ cairo_set_line_width (svg_render->cr, value);
+
+ p = get_attribute (element, "stroke-linecap");
+ if (string_equal (p, "butt"))
+ cairo_set_line_cap (svg_render->cr, CAIRO_LINE_CAP_BUTT);
+ else if (string_equal (p, "round"))
+ cairo_set_line_cap (svg_render->cr, CAIRO_LINE_CAP_ROUND);
+ else if (string_equal (p, "square"))
+ cairo_set_line_cap (svg_render->cr, CAIRO_LINE_CAP_SQUARE);
+
+ p = get_attribute (element, "stroke-linejoin");
+ if (string_equal (p, "miter"))
+ cairo_set_line_join (svg_render->cr, CAIRO_LINE_JOIN_MITER);
+ else if (string_equal (p, "round"))
+ cairo_set_line_join (svg_render->cr, CAIRO_LINE_JOIN_ROUND);
+ else if (string_equal (p, "bevel"))
+ cairo_set_line_join (svg_render->cr, CAIRO_LINE_JOIN_BEVEL);
+
+ if (get_float_attribute (element, "stroke-miterlimit", &value))
+ cairo_set_miter_limit (svg_render->cr, value);
+
+ p = get_attribute (element, "stroke-dasharray");
+ if (p) {
+ free (gs->dash_array);
+ gs->dash_array = strdup (p);
+ }
+
+ get_float_or_percent_attribute (element, "stroke-dashoffset", svg_render->width, &gs->dash_offset);
+ update_dash (svg_render, element);
+
+ /* Some elements may need the bounding box of the element thay are
+ * applied to. As this recursively calls render_element on the
+ * same element while we are in render_element and setting up the
+ * graphics state, we check gs->mode to avoid re-entering the
+ * compute bbox code. The GS_COMPUTE_MODE flag is also used by
+ * render functions to ignore patterns and strokes (SVG spec
+ * ignores stroke with in bbox calculations) and just use a solid
+ * color.
+ */
+ if (gs->mode == GS_RENDER && need_bbox (svg_render, element)) {
+ cairo_surface_t *recording = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL);
+ cairo_t *old_cr = svg_render->cr;
+ svg_render->cr = cairo_create (recording);
+ gs_mode_t old_mode = gs->mode;
+ gs->mode = GS_COMPUTE_BBOX;
+ /* To avoid recursing back into this function, we call the
+ * element directory then use render_element_tree to render
+ * the children */
+ call_element (svg_render, element, FALSE);
+ render_element_tree (svg_render, element, NULL, TRUE);
+ if (element->type == CONTAINER_ELEMENT)
+ call_element (svg_render, element, TRUE);
+ gs->mode = old_mode;
+ cairo_destroy (svg_render->cr);
+ svg_render->cr = old_cr;
+ cairo_recording_surface_ink_extents (recording,
+ &gs->bbox.x,
+ &gs->bbox.y,
+ &gs->bbox.width,
+ &gs->bbox.height);
+ cairo_surface_destroy (recording);
+ }
+
+ /* clip-path may require bbox */
+ p = get_attribute (element, "clip-path");
+ if (p && strncmp (p, "url", 3) == 0) {
+ element = lookup_url_element (svg_render, p);
+ if (element) {
+ gs_mode_t old_mode = gs->mode;
+ gs->mode = GS_CLIP;
+ render_element_tree (svg_render, element, NULL, FALSE);
+ cairo_set_fill_rule (svg_render->cr, gs->clip_rule);
+ cairo_clip (svg_render->cr);
+ gs->mode = old_mode;
+ }
+ }
+}
+
+static void
+save_graphics_state (cairo_svg_glyph_render_t *svg_render)
+{
+ cairo_svg_graphics_state_t *gs;
+
+ cairo_save (svg_render->cr);
+
+ gs = _cairo_malloc (sizeof (cairo_svg_graphics_state_t));
+ gs->fill = svg_render->graphics_state->fill;
+ gs->stroke = svg_render->graphics_state->stroke;
+ gs->color = svg_render->graphics_state->color;
+ gs->fill_opacity = svg_render->graphics_state->fill_opacity;
+ gs->stroke_opacity = svg_render->graphics_state->stroke_opacity;
+ gs->opacity = svg_render->graphics_state->opacity;
+ gs->fill_rule = svg_render->graphics_state->fill_rule;
+ gs->clip_rule = svg_render->graphics_state->clip_rule;
+ gs->clip_path = NULL;
+ gs->dash_array = NULL;
+ if (svg_render->graphics_state->dash_array)
+ gs->dash_array = strdup (svg_render->graphics_state->dash_array);
+ gs->dash_offset = svg_render->graphics_state->dash_offset;
+ gs->mode = svg_render->graphics_state->mode;
+ gs->bbox = svg_render->graphics_state->bbox;
+ gs->next = svg_render->graphics_state;
+ svg_render->graphics_state = gs;
+}
+
+static void
+restore_graphics_state (cairo_svg_glyph_render_t *svg_render)
+{
+ cairo_svg_graphics_state_t *gs;
+
+ gs = svg_render->graphics_state;
+ svg_render->graphics_state = gs->next;
+ if (gs->clip_path)
+ cairo_path_destroy (gs->clip_path);
+ free (gs->dash_array);
+ free (gs);
+
+ cairo_restore (svg_render->cr);
+}
+
+/* render function returns TRUE if render_element_tree() is to render
+ * the child nodes, FALSE if render_element_tree() is to skip the
+ * child nodes.
+ */
+struct render_func {
+ const char *tag;
+ cairo_bool_t (*render) (cairo_svg_glyph_render_t *, cairo_svg_element_t *, cairo_bool_t);
+};
+
+/* Must be sorted */
+static const struct render_func render_funcs[] = {
+ { "circle", render_element_circle },
+ { "clipPath", render_element_clip_path },
+ { "defs", NULL },
+ { "desc", NULL },
+ { "ellipse", render_element_ellipse },
+ { "g", render_element_g },
+ { "image", render_element_image },
+ { "line", render_element_line },
+ { "linearGradient", render_element_linear_gradient },
+ { "metadata", NULL },
+ { "path", render_element_path },
+ { "polygon", render_element_polyline },
+ { "polyline", render_element_polyline },
+ { "radialGradient", render_element_radial_gradient },
+ { "rect", render_element_rect },
+ { "stop", render_element_stop },
+ { "svg", render_element_svg },
+ { "title", NULL },
+ { "use", render_element_use },
+};
+
+static int
+_render_func_compare (const void *a, const void *b)
+{
+ const struct render_func *render_func_a = a;
+ const struct render_func *render_func_b = b;
+
+ return strcmp (render_func_a->tag, render_func_b->tag);
+}
+
+static cairo_bool_t
+call_element (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element,
+ cairo_bool_t end_tag)
+{
+ const struct render_func *func;
+ struct render_func key;
+ cairo_bool_t recurse = FALSE;
+
+ key.tag = element->tag;
+ key.render = NULL;
+ func = bsearch (&key,
+ render_funcs,
+ ARRAY_LENGTH (render_funcs),
+ sizeof (struct render_func),
+ _render_func_compare);
+ if (func) {
+ if (func->render) {
+ recurse = func->render (svg_render, element, end_tag);
+ }
+ } else {
+ print_warning (svg_render, "Unsupported element: %s", element->tag);
+ }
+
+ return recurse;
+}
+
+static cairo_bool_t
+render_element (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element,
+ cairo_bool_t end_tag,
+ cairo_svg_element_t *display_element)
+{
+ cairo_bool_t recurse = FALSE;
+ cairo_svg_graphics_state_t *gs;
+
+ /* Ignore elements if we have not seen "<svg>". Ignore
+ * "<svg>" if we have seen it */
+ if (svg_render->view_port_set) {
+ if (string_equal (element->tag, "svg"))
+ return FALSE;
+ } else {
+ if (!string_equal (element->tag, "svg"))
+ return FALSE;
+ }
+
+ if (element->type == EMPTY_ELEMENT ||
+ (element->type == CONTAINER_ELEMENT && !end_tag))
+ {
+ save_graphics_state (svg_render);
+ update_graphics_state (svg_render, element);
+ }
+
+ gs = svg_render->graphics_state;
+ if (gs->mode == GS_NO_RENDER && element == display_element)
+ gs->mode = GS_RENDER;
+
+ recurse = call_element (svg_render, element, end_tag);
+
+ if (element->type == EMPTY_ELEMENT ||
+ (element->type == CONTAINER_ELEMENT && end_tag))
+ {
+ restore_graphics_state (svg_render);
+ }
+
+ return recurse;
+}
+
+#define MAX_DEPTH 100
+
+static void
+render_element_tree (cairo_svg_glyph_render_t *svg_render,
+ cairo_svg_element_t *element,
+ cairo_svg_element_t *display_element,
+ cairo_bool_t children_only)
+{
+ if (!element)
+ return;
+
+ /* Avoid circular references by limiting the number of recursive
+ * calls to this function. */
+ if (svg_render->render_element_tree_depth > MAX_DEPTH)
+ return;
+
+ svg_render->render_element_tree_depth++;
+ if (element->type == EMPTY_ELEMENT && !children_only) {
+ render_element (svg_render, element, FALSE, display_element);
+
+ } else if (element->type == CONTAINER_ELEMENT) {
+ int num_elems;
+ cairo_bool_t recurse = TRUE;;
+
+ if (!children_only)
+ recurse = render_element (svg_render, element, FALSE, display_element);
+
+ /* We only render the children if the parent returned
+ * success. This is how we avoid rendering non display
+ * elements like gradients, <defs>, and anything not
+ * implemented. */
+ if (recurse) {
+ num_elems = _cairo_array_num_elements (&element->children);
+ for (int i = 0; i < num_elems; i++) {
+ cairo_svg_element_t *child;
+ _cairo_array_copy_element (&element->children, i, &child);
+ render_element_tree (svg_render, child, display_element, FALSE);
+ }
+ }
+
+ if (!children_only)
+ render_element (svg_render, element, TRUE, display_element);
+ }
+ svg_render->render_element_tree_depth--;
+}
+
+static void
+render_element_tree_id (cairo_svg_glyph_render_t *svg_render,
+ const char *element_id)
+{
+ cairo_svg_element_t *glyph_element = NULL;
+
+ if (element_id)
+ glyph_element = lookup_element (svg_render, element_id);
+
+ if (glyph_element)
+ svg_render->graphics_state->mode = GS_NO_RENDER;
+ else
+ svg_render->graphics_state->mode = GS_RENDER;
+
+ render_element_tree (svg_render, svg_render->tree, glyph_element, TRUE);
+}
+
+cairo_status_t
+_cairo_render_svg_glyph (const char *svg_document,
+ unsigned long first_glyph,
+ unsigned long last_glyph,
+ unsigned long glyph,
+ double units_per_em,
+ FT_Color *palette,
+ int num_palette_entries,
+ cairo_t *cr,
+ cairo_pattern_t *foreground_source,
+ cairo_bool_t *foreground_source_used)
+{
+ cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+ cairo_svg_glyph_render_t *svg_render = _cairo_malloc (sizeof (cairo_svg_glyph_render_t));
+ if (unlikely (svg_render == NULL))
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+ svg_render->tree = NULL;
+ svg_render->ids = _cairo_hash_table_create (_element_id_equal);
+ if (unlikely (svg_render->ids == NULL)) {
+ free (svg_render);
+ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ }
+
+ svg_render->debug = 0;
+ const char *s = getenv ("CAIRO_DEBUG_SVG_RENDER");
+ if (s) {
+ if (strlen (s) > 0)
+ svg_render->debug = atoi (s);
+ else
+ svg_render->debug = SVG_RENDER_ERROR;
+ }
+
+ svg_render->cr = cr;
+ svg_render->units_per_em = units_per_em;
+ svg_render->build_pattern.paint_server = NULL;
+ svg_render->build_pattern.pattern = NULL;
+ svg_render->build_pattern.type = BUILD_PATTERN_NONE;
+ svg_render->render_element_tree_depth = 0;
+ svg_render->view_port_set = FALSE;
+ svg_render->num_palette_entries = num_palette_entries;
+ svg_render->palette = palette;
+
+ svg_render->foreground_marker = _cairo_pattern_create_foreground_marker ();
+ svg_render->foreground_source = cairo_pattern_reference (foreground_source);;
+ svg_render->foreground_source_used = FALSE;
+
+ init_graphics_state (svg_render);
+
+ print_info (svg_render, "Glyph ID: %ld", glyph);
+ print_info (svg_render, "Palette Entries: %d", num_palette_entries);
+ print_info (svg_render, "Units per EM: %f", units_per_em);
+ print_info (svg_render, "SVG Document:\n%s\n", svg_document);
+
+ /* First parse elements into a tree and populate ids hash table */
+ if (!parse_svg (svg_render, svg_document)) {
+ print_error (svg_render, "Parse SVG document failed");
+ status = CAIRO_STATUS_SVG_FONT_ERROR;
+ goto cleanup;
+ }
+
+#if SVG_RENDER_PRINT_FUNCTIONS
+ printf("\nTREE\n");
+ if (svg_render->tree) {
+ print_element (svg_render->tree, TRUE, 0);
+ printf("\n");
+ }
+#endif
+
+ /* Next, render glyph */
+ if (first_glyph == last_glyph) {
+ /* Render whole document */
+ render_element_tree_id (svg_render, NULL);
+ } else {
+ /* Render element with id "glyphID" where ID is glyph number. */
+
+ char glyph_id[30];
+ snprintf(glyph_id, sizeof(glyph_id), "#glyph%ld", glyph);
+ render_element_tree_id (svg_render, glyph_id);
+ }
+
+ cleanup:
+ if (svg_render->build_pattern.pattern)
+ cairo_pattern_destroy (svg_render->build_pattern.pattern);
+
+ if (svg_render->tree)
+ free_elements (svg_render, svg_render->tree);
+
+ while (svg_render->graphics_state)
+ restore_graphics_state (svg_render);
+
+ cairo_pattern_destroy (svg_render->foreground_marker);
+ cairo_pattern_destroy (svg_render->foreground_source);
+ *foreground_source_used = svg_render->foreground_source_used;
+
+ /* The hash entry for each element with an id is removed by
+ * free_elements() */
+ _cairo_hash_table_destroy (svg_render->ids);
+
+ free (svg_render);
+
+ return status;
+}
+
+#ifdef DEBUG_SVG_RENDER
+
+/**
+ * _cairo_debug_svg_render:
+ *
+ * Debug function for cairo-svg-glyph-render.c. Allows invoking the renderer from outside
+ * cairo to test with SVG documents, and to facilitate comparison with librsvg rendering.
+ * The viewport is .
+ *
+ * @cr: render target
+ * @svg_document: SVG Document
+ * @element: element within svg_document to render (eg "#glyph8"), or NULL to render entire document.
+ * @debug_level: 0 - quiet, 1 - print errors, 2 - print warnings, 3 - info
+ * @return TRUE on success, ie no errors, FALSE if error
+ **/
+cairo_bool_t
+_cairo_debug_svg_render (cairo_t *cr,
+ const char *svg_document,
+ const char *element,
+ double units_per_em,
+ int debug_level);
+
+cairo_bool_t
+_cairo_debug_svg_render (cairo_t *cr,
+ const char *svg_document,
+ const char *element,
+ double units_per_em,
+ int debug_level)
+{
+ cairo_status_t status;
+ cairo_bool_t foreground_source_used;
+ cairo_pattern_t *foreground = _cairo_pattern_create_foreground_marker ();
+
+ status = _cairo_render_svg_glyph (svg_document,
+ 1, 1, 1,
+ units_per_em,
+ NULL, 0,
+ cr,
+ foreground,
+ &foreground_source_used);
+ cairo_pattern_destroy (foreground);
+
+ return status == CAIRO_STATUS_SUCCESS;
+}
+
+#endif /* DEBUG_SVG_RENDER */
+
+#endif /* HAVE_FT_SVG_DOCUMENT */
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index b39a94a37..b7212a547 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -1555,14 +1555,6 @@ _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 (unlikely (status))
- goto FAIL;
-
- status = _cairo_scaled_font_subsets_foreach_user (document->font_subsets,
- _cairo_svg_document_emit_font_subset,
- document);
-
- FAIL:
_cairo_scaled_font_subsets_destroy (document->font_subsets);
document->font_subsets = NULL;
diff --git a/src/cairo-svg.h b/src/cairo-svg.h
index 5328cb583..7745eec90 100644
--- a/src/cairo-svg.h
+++ b/src/cairo-svg.h
@@ -73,9 +73,9 @@ typedef enum _cairo_svg_version {
* lengths in the SVG specification.
*
* See also:
- * https://www.w3.org/TR/SVG/coords.html#Units
- * https://www.w3.org/TR/SVG/types.html#DataTypeLength
- * https://www.w3.org/TR/css-values-3/#lengths
+ * - [SVG Units](https://www.w3.org/TR/SVG/coords.html#Units)
+ * - [SVG Types](https://www.w3.org/TR/SVG/types.html#DataTypeLength)
+ * - [CSS Length](https://www.w3.org/TR/css-values-3/#lengths)
*
* Since: 1.16
**/
diff --git a/src/cairo-tag-attributes.c b/src/cairo-tag-attributes.c
index 6d0f63f11..85467ad73 100644
--- a/src/cairo-tag-attributes.c
+++ b/src/cairo-tag-attributes.c
@@ -366,12 +366,9 @@ parse_name (const char *attributes, const char *p, const char **end, char **s)
p2++;
len = p2 - p;
- name = _cairo_malloc (len + 1);
+ name = _cairo_strndup (p, len);
if (unlikely (name == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- memcpy (name, p, len);
- name[len] = 0;
*s = name;
*end = p2;
diff --git a/src/cairo-tee-surface-private.h b/src/cairo-tee-surface-private.h
deleted file mode 100644
index a83cfc959..000000000
--- a/src/cairo-tee-surface-private.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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 University of Southern
- * California.
- *
- * Contributor(s):
- * Chris Wilson <chris@chris-wilson.co.uk>
- */
-
-#ifndef CAIRO_TEE_SURFACE_PRIVATE_H
-#define CAIRO_TEE_SURFACE_PRIVATE_H
-
-#include "cairoint.h"
-
-cairo_private cairo_surface_t *
-_cairo_tee_surface_find_match (void *abstract_surface,
- const cairo_surface_backend_t *backend,
- cairo_content_t content);
-
-#endif /* CAIRO_TEE_SURFACE_PRIVATE_H */
diff --git a/src/cairo-tee-surface.c b/src/cairo-tee-surface.c
index 7a94c9bca..1d075a29c 100644
--- a/src/cairo-tee-surface.c
+++ b/src/cairo-tee-surface.c
@@ -44,7 +44,6 @@
#include "cairo-default-context-private.h"
#include "cairo-error-private.h"
-#include "cairo-tee-surface-private.h"
#include "cairo-recording-surface-inline.h"
#include "cairo-surface-wrapper-private.h"
#include "cairo-array-private.h"
@@ -220,12 +219,12 @@ _cairo_tee_surface_paint (void *abstract_surface,
num_slaves = _cairo_array_num_elements (&surface->slaves);
slaves = _cairo_array_index (&surface->slaves, 0);
for (n = 0; n < num_slaves; n++) {
- status = _cairo_surface_wrapper_paint (&slaves[n], op, source, clip);
+ status = _cairo_surface_wrapper_paint (&slaves[n], op, source, 0, clip);
if (unlikely (status))
return status;
}
- return _cairo_surface_wrapper_paint (&surface->master, op, source, clip);
+ return _cairo_surface_wrapper_paint (&surface->master, op, source, 0, clip);
}
static cairo_int_status_t
@@ -244,13 +243,17 @@ _cairo_tee_surface_mask (void *abstract_surface,
slaves = _cairo_array_index (&surface->slaves, 0);
for (n = 0; n < num_slaves; n++) {
status = _cairo_surface_wrapper_mask (&slaves[n],
- op, source, mask, clip);
+ op, source, 0,
+ mask, 0,
+ clip);
if (unlikely (status))
return status;
}
return _cairo_surface_wrapper_mask (&surface->master,
- op, source, mask, clip);
+ op, source, 0,
+ mask, 0,
+ clip);
}
static cairo_int_status_t
@@ -274,7 +277,7 @@ _cairo_tee_surface_stroke (void *abstract_surface,
slaves = _cairo_array_index (&surface->slaves, 0);
for (n = 0; n < num_slaves; n++) {
status = _cairo_surface_wrapper_stroke (&slaves[n],
- op, source,
+ op, source, 0,
path, style,
ctm, ctm_inverse,
tolerance, antialias,
@@ -284,7 +287,7 @@ _cairo_tee_surface_stroke (void *abstract_surface,
}
return _cairo_surface_wrapper_stroke (&surface->master,
- op, source,
+ op, source, 0,
path, style,
ctm, ctm_inverse,
tolerance, antialias,
@@ -310,7 +313,7 @@ _cairo_tee_surface_fill (void *abstract_surface,
slaves = _cairo_array_index (&surface->slaves, 0);
for (n = 0; n < num_slaves; n++) {
status = _cairo_surface_wrapper_fill (&slaves[n],
- op, source,
+ op, source, 0,
path, fill_rule,
tolerance, antialias,
clip);
@@ -319,7 +322,7 @@ _cairo_tee_surface_fill (void *abstract_surface,
}
return _cairo_surface_wrapper_fill (&surface->master,
- op, source,
+ op, source, 0,
path, fill_rule,
tolerance, antialias,
clip);
@@ -361,7 +364,7 @@ _cairo_tee_surface_show_text_glyphs (void *abstract_surface,
for (n = 0; n < num_slaves; n++) {
memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
status = _cairo_surface_wrapper_show_text_glyphs (&slaves[n], op,
- source,
+ source, 0,
utf8, utf8_len,
glyphs_copy, num_glyphs,
clusters, num_clusters,
@@ -374,7 +377,7 @@ _cairo_tee_surface_show_text_glyphs (void *abstract_surface,
memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
status = _cairo_surface_wrapper_show_text_glyphs (&surface->master, op,
- source,
+ source, 0,
utf8, utf8_len,
glyphs_copy, num_glyphs,
clusters, num_clusters,
@@ -561,43 +564,3 @@ cairo_tee_surface_index (cairo_surface_t *abstract_surface,
return slave->target;
}
}
-
-cairo_surface_t *
-_cairo_tee_surface_find_match (void *abstract_surface,
- const cairo_surface_backend_t *backend,
- cairo_content_t content)
-{
- cairo_tee_surface_t *surface = abstract_surface;
- cairo_surface_wrapper_t *slaves;
- int num_slaves, n;
-
- /* exact match first */
- if (surface->master.target->backend == backend &&
- surface->master.target->content == content)
- {
- return surface->master.target;
- }
-
- num_slaves = _cairo_array_num_elements (&surface->slaves);
- slaves = _cairo_array_index (&surface->slaves, 0);
- for (n = 0; n < num_slaves; n++) {
- if (slaves[n].target->backend == backend &&
- slaves[n].target->content == content)
- {
- return slaves[n].target;
- }
- }
-
- /* matching backend? */
- if (surface->master.target->backend == backend)
- return surface->master.target;
-
- num_slaves = _cairo_array_num_elements (&surface->slaves);
- slaves = _cairo_array_index (&surface->slaves, 0);
- for (n = 0; n < num_slaves; n++) {
- if (slaves[n].target->backend == backend)
- return slaves[n].target;
- }
-
- return NULL;
-}
diff --git a/src/cairo-time.c b/src/cairo-time.c
index c93205908..05b64e157 100644
--- a/src/cairo-time.c
+++ b/src/cairo-time.c
@@ -62,7 +62,6 @@ _cairo_time_get (void)
}
#elif _WIN32
-#define WIN32_LEAN_AND_MEAN
#include <windows.h>
static cairo_always_inline double
diff --git a/src/cairo-toy-font-face.c b/src/cairo-toy-font-face.c
index ef7122609..c27eebefc 100644
--- a/src/cairo-toy-font-face.c
+++ b/src/cairo-toy-font-face.c
@@ -235,7 +235,7 @@ _cairo_toy_font_face_keys_equal (const void *key_a,
* @weight: the weight for the font
*
* Creates a font face from a triplet of family, slant, and weight.
- * These font faces are used in implementation of the the #cairo_t "toy"
+ * These font faces are used in implementation of the #cairo_t "toy"
* font API.
*
* If @family is the zero-length string "", the platform-specific default
diff --git a/src/cairo-traps-compositor.c b/src/cairo-traps-compositor.c
index 3414fc268..d1402d2a3 100644
--- a/src/cairo-traps-compositor.c
+++ b/src/cairo-traps-compositor.c
@@ -1240,7 +1240,7 @@ composite_aligned_boxes (const cairo_traps_compositor_t *compositor,
recording_clip = _cairo_clip_from_boxes (boxes);
status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (source),
- m, dst, recording_clip);
+ m, dst, recording_clip, FALSE);
_cairo_clip_destroy (recording_clip);
return status;
diff --git a/src/cairo-truetype-subset.c b/src/cairo-truetype-subset.c
index c58b96665..78c7dd5ec 100644
--- a/src/cairo-truetype-subset.c
+++ b/src/cairo-truetype-subset.c
@@ -1,3 +1,4 @@
+/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Red Hat, Inc
@@ -1531,13 +1532,7 @@ find_name (tt_name_t *name, unsigned long size, int name_id, int platform, int e
}
}
if (has_tag) {
- p = _cairo_malloc (len - 6);
- if (unlikely (p == NULL)) {
- status =_cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto fail;
- }
- memcpy (p, str + 7, len - 7);
- p[len-7] = 0;
+ p = _cairo_strndup (str + 7, len - 7);
free (str);
str = p;
}
diff --git a/src/cairo-type3-glyph-surface.c b/src/cairo-type3-glyph-surface.c
index 05ef417dc..53c029493 100644
--- a/src/cairo-type3-glyph-surface.c
+++ b/src/cairo-type3-glyph-surface.c
@@ -182,7 +182,9 @@ _cairo_type3_glyph_surface_finish (void *abstract_surface)
{
cairo_type3_glyph_surface_t *surface = abstract_surface;
- return _cairo_pdf_operators_fini (&surface->pdf_operators);
+ cairo_status_t status = _cairo_pdf_operators_fini (&surface->pdf_operators);
+ _cairo_surface_clipper_reset (&surface->clipper);
+ return status;
}
static cairo_int_status_t
@@ -205,6 +207,9 @@ _cairo_type3_glyph_surface_paint (void *abstract_surface,
return status;
pattern = (const cairo_surface_pattern_t *) source;
+ if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
+ return CAIRO_INT_STATUS_IMAGE_FALLBACK;
+
status = _cairo_surface_acquire_source_image (pattern->surface,
&image, &image_extra);
if (unlikely (status))
@@ -289,33 +294,7 @@ _cairo_type3_glyph_surface_show_glyphs (void *abstract_surface,
cairo_scaled_font_t *scaled_font,
const cairo_clip_t *clip)
{
- cairo_type3_glyph_surface_t *surface = abstract_surface;
- cairo_int_status_t status;
- cairo_scaled_font_t *font;
- cairo_matrix_t new_ctm;
-
- status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
- if (unlikely (status))
- return status;
-
- cairo_matrix_multiply (&new_ctm, &surface->cairo_to_pdf, &scaled_font->ctm);
- font = cairo_scaled_font_create (scaled_font->font_face,
- &scaled_font->font_matrix,
- &new_ctm,
- &scaled_font->options);
- if (unlikely (font->status))
- return font->status;
-
- status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators,
- NULL, 0,
- glyphs, num_glyphs,
- NULL, 0,
- FALSE,
- font);
-
- cairo_scaled_font_destroy (font);
-
- return status;
+ return CAIRO_INT_STATUS_IMAGE_FALLBACK;
}
static const cairo_surface_backend_t cairo_type3_glyph_surface_backend = {
@@ -478,12 +457,22 @@ _cairo_type3_glyph_surface_emit_glyph (void *abstract_surface,
_cairo_type3_glyph_surface_set_stream (surface, stream);
_cairo_scaled_font_freeze_cache (surface->scaled_font);
+
+ /* Check if this is a color glyph and bail out if it is */
status = _cairo_scaled_glyph_lookup (surface->scaled_font,
glyph_index,
- CAIRO_SCALED_GLYPH_INFO_METRICS |
- CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE,
+ CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE,
NULL, /* foreground color */
&scaled_glyph);
+ if (status == CAIRO_INT_STATUS_SUCCESS) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto FAIL;
+ } status = _cairo_scaled_glyph_lookup (surface->scaled_font,
+ glyph_index,
+ CAIRO_SCALED_GLYPH_INFO_METRICS |
+ CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE,
+ NULL, /* foreground color */
+ &scaled_glyph);
if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
status = _cairo_scaled_glyph_lookup (surface->scaled_font,
glyph_index,
diff --git a/src/cairo-types-private.h b/src/cairo-types-private.h
index a9980f3b9..736a1bcb3 100644
--- a/src/cairo-types-private.h
+++ b/src/cairo-types-private.h
@@ -187,6 +187,11 @@ typedef enum _cairo_round_glyph_positions {
CAIRO_ROUND_GLYPH_POS_OFF
} cairo_round_glyph_positions_t;
+typedef struct {
+ unsigned int index;
+ double red, green, blue, alpha;
+} cairo_palette_color_t;
+
struct _cairo_font_options {
cairo_antialias_t antialias;
cairo_subpixel_order_t subpixel_order;
@@ -197,6 +202,8 @@ struct _cairo_font_options {
char *variations;
cairo_color_mode_t color_mode;
unsigned int palette_index;
+ cairo_palette_color_t *custom_palette;
+ unsigned int custom_palette_size;
};
struct _cairo_glyph_text_info {
diff --git a/src/cairo-uninstalled.pc.in b/src/cairo-uninstalled.pc.in
deleted file mode 100644
index 9dc3231ae..000000000
--- a/src/cairo-uninstalled.pc.in
+++ /dev/null
@@ -1,8 +0,0 @@
-Name: cairo
-Description: Multi-platform 2D graphics library
-Version: @VERSION@
-
-@PKGCONFIG_REQUIRES@: @CAIRO_REQUIRES@
-Libs: ${pc_top_builddir}/${pcfiledir}/src/libcairo.la
-Libs.private: @CAIRO_NONPKGCONFIG_LIBS@
-Cflags: -I${pc_top_builddir}/${pcfiledir}/@srcdir@/src
diff --git a/src/cairo-user-font.c b/src/cairo-user-font.c
index fd989eaa0..ee11d864c 100644
--- a/src/cairo-user-font.c
+++ b/src/cairo-user-font.c
@@ -95,13 +95,19 @@ typedef struct _cairo_user_scaled_font {
double snap_x_scale;
double snap_y_scale;
+ cairo_pattern_t *foreground_marker;
+ cairo_pattern_t *foreground_pattern;
+ cairo_bool_t foreground_marker_used;
+ cairo_bool_t foreground_colors_used;
+
} cairo_user_scaled_font_t;
/* #cairo_user_scaled_font_t */
static cairo_surface_t *
-_cairo_user_scaled_font_create_recording_surface (const cairo_user_scaled_font_t *scaled_font,
- cairo_bool_t color)
+_cairo_user_scaled_font_create_recording_surface (cairo_user_scaled_font_t *scaled_font,
+ cairo_bool_t color,
+ const cairo_color_t *foreground_color)
{
cairo_content_t content;
@@ -113,10 +119,20 @@ _cairo_user_scaled_font_create_recording_surface (const cairo_user_scaled_font_t
CAIRO_CONTENT_ALPHA;
}
+ if (scaled_font->foreground_pattern)
+ cairo_pattern_destroy (scaled_font->foreground_pattern);
+
+ scaled_font->foreground_marker_used = FALSE;
+ scaled_font->foreground_colors_used = FALSE;
+ if (foreground_color) {
+ scaled_font->foreground_pattern = _cairo_pattern_create_solid (foreground_color);
+ } else {
+ scaled_font->foreground_pattern = cairo_pattern_create_rgb (0, 0, 0);
+ }
+
return cairo_recording_surface_create (content, NULL);
}
-
static cairo_t *
_cairo_user_scaled_font_create_recording_context (const cairo_user_scaled_font_t *scaled_font,
cairo_surface_t *recording_surface,
@@ -143,7 +159,8 @@ _cairo_user_scaled_font_create_recording_context (const cairo_user_scaled_font_t
static cairo_int_status_t
_cairo_user_scaled_glyph_init_record_glyph (cairo_user_scaled_font_t *scaled_font,
- cairo_scaled_glyph_t *scaled_glyph)
+ cairo_scaled_glyph_t *scaled_glyph,
+ const cairo_color_t *foreground_color)
{
cairo_user_font_face_t *face =
(cairo_user_font_face_t *) scaled_font->base.font_face;
@@ -151,29 +168,27 @@ _cairo_user_scaled_glyph_init_record_glyph (cairo_user_scaled_font_t *scaled_fon
cairo_surface_t *recording_surface = NULL;
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
cairo_t *cr;
+ cairo_bool_t foreground_used = FALSE;
if (!face->scaled_font_methods.render_color_glyph && !face->scaled_font_methods.render_glyph)
return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
/* special case for 0 rank matrix (as in _cairo_scaled_font_init): empty surface */
if (_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) {
- recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font, FALSE);
+ recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font, FALSE, foreground_color);
_cairo_scaled_glyph_set_recording_surface (scaled_glyph,
&scaled_font->base,
- recording_surface);
+ recording_surface,
+ NULL);
} else {
status = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
- if (face->scaled_font_methods.render_color_glyph) {
- cairo_pattern_t *pattern;
-
- recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font, TRUE);
+ if (face->scaled_font_methods.render_color_glyph &&
+ scaled_font->base.options.color_mode != CAIRO_COLOR_MODE_NO_COLOR)
+ {
+ recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font, TRUE, foreground_color);
cr = _cairo_user_scaled_font_create_recording_context (scaled_font, recording_surface, TRUE);
- pattern = cairo_pattern_create_rgb (0, 0, 0);
- pattern->is_userfont_foreground = TRUE;
- cairo_set_source (cr, pattern);
- cairo_pattern_destroy (pattern);
status = face->scaled_font_methods.render_color_glyph ((cairo_scaled_font_t *)scaled_font,
_cairo_scaled_glyph_index(scaled_glyph),
cr, &extents);
@@ -182,14 +197,16 @@ _cairo_user_scaled_glyph_init_record_glyph (cairo_user_scaled_font_t *scaled_fon
scaled_glyph->color_glyph = TRUE;
scaled_glyph->color_glyph_set = TRUE;
}
+
cairo_destroy (cr);
+ foreground_used = scaled_font->foreground_marker_used || scaled_font->foreground_colors_used;
}
if (status == (cairo_int_status_t)CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED &&
face->scaled_font_methods.render_glyph) {
if (recording_surface)
cairo_surface_destroy (recording_surface);
- recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font, FALSE);
+ recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font, FALSE, foreground_color);
recording_surface->device_transform.x0 = .25 * _cairo_scaled_glyph_xphase (scaled_glyph);
recording_surface->device_transform.y0 = .25 * _cairo_scaled_glyph_yphase (scaled_glyph);
@@ -205,6 +222,7 @@ _cairo_user_scaled_glyph_init_record_glyph (cairo_user_scaled_font_t *scaled_fon
}
cairo_destroy (cr);
+ foreground_used = FALSE;
}
if (status != CAIRO_INT_STATUS_SUCCESS) {
@@ -215,7 +233,8 @@ _cairo_user_scaled_glyph_init_record_glyph (cairo_user_scaled_font_t *scaled_fon
_cairo_scaled_glyph_set_recording_surface (scaled_glyph,
&scaled_font->base,
- recording_surface);
+ recording_surface,
+ foreground_used ? foreground_color : NULL);
}
/* set metrics */
@@ -266,6 +285,7 @@ _cairo_user_scaled_glyph_init_surface (cairo_user_scaled_font_t *scaled_font,
cairo_format_t format;
int width, height;
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
+ cairo_bool_t foreground_used;
/* TODO
* extend the glyph cache to support argb glyphs.
@@ -310,21 +330,25 @@ _cairo_user_scaled_glyph_init_surface (cairo_user_scaled_font_t *scaled_font,
if (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) {
status = _cairo_recording_surface_replay_with_foreground_color (scaled_glyph->recording_surface,
surface,
- foreground_color);
+ foreground_color,
+ &foreground_used);
+
} else {
status = _cairo_recording_surface_replay (scaled_glyph->recording_surface, surface);
+ foreground_used = FALSE;
}
-
if (unlikely (status)) {
cairo_surface_destroy(surface);
return status;
}
+ foreground_used = foreground_used || scaled_glyph->recording_uses_foreground_color;
+
if (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) {
_cairo_scaled_glyph_set_color_surface (scaled_glyph,
&scaled_font->base,
(cairo_image_surface_t *)surface,
- TRUE);
+ foreground_used ? foreground_color : NULL);
surface = NULL;
} else {
_cairo_scaled_glyph_set_surface (scaled_glyph,
@@ -339,6 +363,18 @@ _cairo_user_scaled_glyph_init_surface (cairo_user_scaled_font_t *scaled_font,
return status;
}
+static void
+_cairo_user_scaled_glyph_fini (void *abstract_font)
+{
+ cairo_user_scaled_font_t *scaled_font = abstract_font;
+
+ if (scaled_font->foreground_pattern)
+ cairo_pattern_destroy (scaled_font->foreground_pattern);
+
+ if (scaled_font->foreground_marker)
+ cairo_pattern_destroy (scaled_font->foreground_marker);
+}
+
static cairo_int_status_t
_cairo_user_scaled_glyph_init (void *abstract_font,
cairo_scaled_glyph_t *scaled_glyph,
@@ -348,8 +384,8 @@ _cairo_user_scaled_glyph_init (void *abstract_font,
cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
cairo_user_scaled_font_t *scaled_font = abstract_font;
- if (!scaled_glyph->recording_surface) {
- status = _cairo_user_scaled_glyph_init_record_glyph (scaled_font, scaled_glyph);
+ if (!scaled_glyph->recording_surface || (info & CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE)) {
+ status = _cairo_user_scaled_glyph_init_record_glyph (scaled_font, scaled_glyph, foreground_color);
if (status)
return status;
}
@@ -509,7 +545,7 @@ _cairo_user_font_face_create_for_toy (cairo_toy_font_face_t *toy_face,
static const cairo_scaled_font_backend_t _cairo_user_scaled_font_backend = {
CAIRO_FONT_TYPE_USER,
- NULL, /* scaled_font_fini */
+ _cairo_user_scaled_glyph_fini,
_cairo_user_scaled_glyph_init,
_cairo_user_text_to_glyphs,
_cairo_user_ucs4_to_index,
@@ -551,6 +587,9 @@ _cairo_user_font_face_scaled_font_create (void *abstract_
return status;
}
+ user_scaled_font->foreground_pattern = NULL;
+ user_scaled_font->foreground_marker = _cairo_pattern_create_foreground_marker ();
+
/* XXX metrics hinting? */
/* compute a normalized version of font scale matrix to compute
@@ -559,6 +598,8 @@ _cairo_user_font_face_scaled_font_create (void *abstract_
{
double fixed_scale, x_scale, y_scale;
+ user_scaled_font->snap_x_scale = 1.0;
+ user_scaled_font->snap_y_scale = 1.0;
user_scaled_font->extent_scale = user_scaled_font->base.scale_inverse;
status = _cairo_matrix_compute_basis_scale_factors (&user_scaled_font->extent_scale,
&x_scale, &y_scale,
@@ -597,7 +638,7 @@ _cairo_user_font_face_scaled_font_create (void *abstract_
cairo_surface_t *recording_surface;
cairo_t *cr;
- recording_surface = _cairo_user_scaled_font_create_recording_surface (user_scaled_font, FALSE);
+ recording_surface = _cairo_user_scaled_font_create_recording_surface (user_scaled_font, FALSE, NULL);
cr = _cairo_user_scaled_font_create_recording_context (user_scaled_font, recording_surface, FALSE);
cairo_surface_destroy (recording_surface);
@@ -1052,3 +1093,119 @@ cairo_user_font_face_get_unicode_to_glyph_func (cairo_font_face_t *font_face)
user_font_face = (cairo_user_font_face_t *) font_face;
return user_font_face->scaled_font_methods.unicode_to_glyph;
}
+
+/**
+ * cairo_user_scaled_font_get_foreground_marker:
+ * @scaled_font: A user scaled font
+ *
+ * Gets the foreground pattern of the glyph currently being
+ * rendered. A #cairo_user_scaled_font_render_glyph_func_t function
+ * that has been set with
+ * cairo_user_font_face_set_render_color_glyph_func() may call this
+ * function to retrieve the current foreground pattern for the glyph
+ * being rendered. The function should not be called outside of a
+ * cairo_user_font_face_set_render_color_glyph_func() callback.
+ *
+ * The foreground marker pattern contains an internal marker to
+ * indicate that it is to be substituted with the current source when
+ * rendered to a surface. Querying the foreground marker will reveal a
+ * solid black color, however this is not representative of the color
+ * that will actually be used. Similarly, setting a solid black color
+ * will render black, not the foreground pattern when the glyph is
+ * painted to a surface. Using the foreground marker as the source
+ * instead of cairo_user_scaled_font_get_foreground_source() in a
+ * color render callback has the following benefits:
+ *
+ * 1. Cairo only needs to call the render callback once as it can
+ * cache the recording. Cairo will substitute the actual foreground
+ * color when rendering the recording.
+ *
+ * 2. On backends that have the concept of a foreground color in fonts such as
+ * PDF, PostScript, and SVG, cairo can generate more optimal
+ * output. The glyph can be included in an embedded font.
+ *
+ * The one drawback of the using foreground marker is the render
+ * callback can not access the color components of the pattern as the
+ * actual foreground pattern is not available at the time the render
+ * callback is invoked. If the render callback needs to query the
+ * foreground pattern, use
+ * cairo_user_scaled_font_get_foreground_source().
+ *
+ * If the render callback simply wants to call cairo_set_source() with
+ * the foreground pattern,
+ * cairo_user_scaled_font_get_foreground_marker() is the preferred
+ * function to use as it results in better performance than
+ * cairo_user_scaled_font_get_foreground_source().
+ *
+ * Return value: the current foreground source marker pattern. This
+ * object is owned by cairo. This object must not be modified or used
+ * outside of a color render callback. To keep a reference to it,
+ * you must call cairo_pattern_reference().
+ *
+ * Since: 1.18
+ **/
+cairo_pattern_t *
+cairo_user_scaled_font_get_foreground_marker (cairo_scaled_font_t *scaled_font)
+{
+ cairo_user_scaled_font_t *user_scaled_font;
+
+ if (scaled_font->backend != &_cairo_user_scaled_font_backend)
+ return _cairo_pattern_create_in_error (CAIRO_STATUS_FONT_TYPE_MISMATCH);
+
+ user_scaled_font = (cairo_user_scaled_font_t *)scaled_font;
+ return user_scaled_font->foreground_marker;
+}
+
+/**
+ * cairo_user_scaled_font_get_foreground_source:
+ * @scaled_font: A user scaled font
+ *
+ * Gets the foreground pattern of the glyph currently being
+ * rendered. A #cairo_user_scaled_font_render_glyph_func_t function
+ * that has been set with
+ * cairo_user_font_face_set_render_color_glyph_func() may call this
+ * function to retrieve the current foreground pattern for the glyph
+ * being rendered. The function should not be called outside of a
+ * cairo_user_font_face_set_render_color_glyph_func() callback.
+ *
+ * This function returns the current source at the time the glyph is
+ * rendered. Compared with
+ * cairo_user_scaled_font_get_foreground_marker(), this function
+ * returns the actual source pattern that will be used to render the
+ * glyph. The render callback is free to query the pattern and
+ * extract color components or other pattern data. For example if the
+ * render callback wants to create a gradient stop based on colors in
+ * the foreground source pattern, it will need to use this function in
+ * order to be able to query the colors in the foreground pattern.
+ *
+ * While this function does not have the restrictions on using the
+ * pattern that cairo_user_scaled_font_get_foreground_marker() has, it
+ * does incur a performance penalty. If a render callback calls this
+ * function:
+ *
+ * 1. Cairo will call the render callback whenever the current pattern
+ * of the context in which the glyph is rendered changes.
+ *
+ * 2. On backends that support font embedding (PDF, PostScript, and
+ * SVG), cairo can not embed this glyph in a font. Instead the glyph
+ * will be emitted as an image or sequence of drawing operations each
+ * time it is used.
+ *
+ * Return value: the current foreground source pattern. This object is
+ * owned by cairo. To keep a reference to it, you must call
+ * cairo_pattern_reference().
+ *
+ * Since: 1.18
+ **/
+cairo_pattern_t *
+cairo_user_scaled_font_get_foreground_source (cairo_scaled_font_t *scaled_font)
+{
+ cairo_user_scaled_font_t *user_scaled_font;
+
+ if (scaled_font->backend != &_cairo_user_scaled_font_backend)
+ return _cairo_pattern_create_in_error (CAIRO_STATUS_FONT_TYPE_MISMATCH);
+
+ user_scaled_font = (cairo_user_scaled_font_t *)scaled_font;
+ user_scaled_font->foreground_colors_used = TRUE;
+ return user_scaled_font->foreground_pattern;
+}
diff --git a/src/cairo-version.h b/src/cairo-version.h
index b64b48902..3ac065f68 100644
--- a/src/cairo-version.h
+++ b/src/cairo-version.h
@@ -3,6 +3,6 @@
#define CAIRO_VERSION_MAJOR 1
#define CAIRO_VERSION_MINOR 17
-#define CAIRO_VERSION_MICRO 7
+#define CAIRO_VERSION_MICRO 9
#endif
diff --git a/src/cairo-wgl-context.c b/src/cairo-wgl-context.c
deleted file mode 100644
index 487237446..000000000
--- a/src/cairo-wgl-context.c
+++ /dev/null
@@ -1,261 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 Eric Anholt
- * Copyright © 2009 Chris Wilson
- * 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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):
- * Carl Worth <cworth@cworth.org>
- * Chris Wilson <chris@chris-wilson.co.uk>
- * Zoxc <zoxc32@gmail.com>
- */
-
-#include "cairoint.h"
-
-#include "cairo-gl-private.h"
-
-#include "cairo-error-private.h"
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-typedef struct _cairo_wgl_context {
- cairo_gl_context_t base;
-
- HDC dummy_dc;
- HWND dummy_wnd;
- HGLRC rc;
-
- HDC prev_dc;
- HGLRC prev_rc;
-} cairo_wgl_context_t;
-
-typedef struct _cairo_wgl_surface {
- cairo_gl_surface_t base;
-
- HDC dc;
-} cairo_wgl_surface_t;
-
-static void
-_wgl_acquire (void *abstract_ctx)
-{
- cairo_wgl_context_t *ctx = abstract_ctx;
-
- HDC current_dc;
-
- ctx->prev_dc = wglGetCurrentDC ();
- ctx->prev_rc = wglGetCurrentContext ();
-
- if (ctx->base.current_target == NULL ||
- _cairo_gl_surface_is_texture (ctx->base.current_target))
- {
- current_dc = ctx->dummy_dc;
- }
- else
- {
- cairo_wgl_surface_t *surface = (cairo_wgl_surface_t *) ctx->base.current_target;
- current_dc = surface->dc;
- }
-
- if (ctx->prev_dc != current_dc ||
- (ctx->prev_rc != ctx->rc &&
- current_dc != ctx->dummy_dc))
- {
- wglMakeCurrent (current_dc, ctx->rc);
- }
-}
-
-static void
-_wgl_make_current (void *abstract_ctx, cairo_gl_surface_t *abstract_surface)
-{
- cairo_wgl_context_t *ctx = abstract_ctx;
- cairo_wgl_surface_t *surface = (cairo_wgl_surface_t *) abstract_surface;
-
- /* Set the window as the target of our context. */
- wglMakeCurrent (surface->dc, ctx->rc);
-}
-
-static void
-_wgl_release (void *abstract_ctx)
-{
- cairo_wgl_context_t *ctx = abstract_ctx;
-
- if (ctx->prev_dc != wglGetCurrentDC () ||
- ctx->prev_rc != wglGetCurrentContext ())
- {
- wglMakeCurrent (ctx->prev_dc,
- ctx->prev_rc);
- }
-}
-
-static void
-_wgl_swap_buffers (void *abstract_ctx,
- cairo_gl_surface_t *abstract_surface)
-{
- cairo_wgl_surface_t *surface = (cairo_wgl_surface_t *) abstract_surface;
-
- SwapBuffers (surface->dc);
-}
-
-static void
-_wgl_destroy (void *abstract_ctx)
-{
- cairo_wgl_context_t *ctx = abstract_ctx;
-
- if (ctx->dummy_dc != 0) {
- wglMakeCurrent (ctx->dummy_dc, 0);
- ReleaseDC (ctx->dummy_wnd, ctx->dummy_dc);
- DestroyWindow (ctx->dummy_wnd);
- }
-}
-
-static cairo_status_t
-_wgl_dummy_ctx (cairo_wgl_context_t *ctx)
-{
- WNDCLASSEXA wincl;
- PIXELFORMATDESCRIPTOR pfd;
- int format;
- HDC dc;
-
- ZeroMemory (&wincl, sizeof (WNDCLASSEXA));
- wincl.cbSize = sizeof (WNDCLASSEXA);
- wincl.hInstance = GetModuleHandle (0);
- wincl.lpszClassName = "cairo_wgl_context_dummy";
- wincl.lpfnWndProc = DefWindowProcA;
- wincl.style = CS_OWNDC;
-
- RegisterClassExA (&wincl);
-
- ctx->dummy_wnd = CreateWindowA ("cairo_wgl_context_dummy", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
- ctx->dummy_dc = GetDC (ctx->dummy_wnd);
-
- ZeroMemory (&pfd, sizeof (PIXELFORMATDESCRIPTOR));
- pfd.nSize = sizeof (PIXELFORMATDESCRIPTOR);
- pfd.nVersion = 1;
- pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
- pfd.iPixelType = PFD_TYPE_RGBA;
- pfd.cColorBits = 24;
- pfd.cDepthBits = 16;
- pfd.iLayerType = PFD_MAIN_PLANE;
-
- format = ChoosePixelFormat (ctx->dummy_dc, &pfd);
- SetPixelFormat (ctx->dummy_dc, format, &pfd);
-
- wglMakeCurrent(ctx->dummy_dc, ctx->rc);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-cairo_device_t *
-cairo_wgl_device_create (HGLRC rc)
-{
- cairo_wgl_context_t *ctx;
- cairo_status_t status;
-
- ctx = calloc (1, sizeof (cairo_wgl_context_t));
- if (unlikely (ctx == NULL))
- return _cairo_gl_context_create_in_error (CAIRO_STATUS_NO_MEMORY);
-
- ctx->rc = rc;
- ctx->prev_dc = 0;
- ctx->prev_rc = 0;
-
- status = _wgl_dummy_ctx (ctx);
- if (unlikely (status)) {
- free (ctx);
- return _cairo_gl_context_create_in_error (status);
- }
-
- ctx->base.acquire = _wgl_acquire;
- ctx->base.release = _wgl_release;
- ctx->base.make_current = _wgl_make_current;
- ctx->base.swap_buffers = _wgl_swap_buffers;
- ctx->base.destroy = _wgl_destroy;
-
- status = _cairo_gl_dispatch_init (&ctx->base.dispatch,
- (cairo_gl_get_proc_addr_func_t) wglGetProcAddress);
- if (unlikely (status)) {
- free (ctx);
- return _cairo_gl_context_create_in_error (status);
- }
-
- status = _cairo_gl_context_init (&ctx->base);
- if (unlikely (status)) {
- free (ctx);
- return _cairo_gl_context_create_in_error (status);
- }
-
- ctx->base.release (ctx);
-
- return &ctx->base.base;
-}
-
-HGLRC
-cairo_wgl_device_get_context (cairo_device_t *device)
-{
- cairo_wgl_context_t *ctx;
-
- if (device->backend->type != CAIRO_DEVICE_TYPE_GL) {
- _cairo_error_throw (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
- return NULL;
- }
-
- ctx = (cairo_wgl_context_t *) device;
-
- return ctx->rc;
-}
-
-cairo_surface_t *
-cairo_gl_surface_create_for_dc (cairo_device_t *device,
- HDC dc,
- int width,
- int height)
-{
- cairo_wgl_surface_t *surface;
-
- if (unlikely (device->status))
- return _cairo_surface_create_in_error (device->status);
-
- if (device->backend->type != CAIRO_DEVICE_TYPE_GL)
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
-
- if (width <= 0 || height <= 0)
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
-
- surface = calloc (1, sizeof (cairo_wgl_surface_t));
- if (unlikely (surface == NULL))
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
-
- _cairo_gl_surface_init (device, &surface->base,
- CAIRO_CONTENT_COLOR_ALPHA, width, height);
- surface->dc = dc;
-
- return &surface->base.base;
-}
diff --git a/src/cairo-win32.h b/src/cairo-win32.h
index 078a70c7b..db4cac69f 100644
--- a/src/cairo-win32.h
+++ b/src/cairo-win32.h
@@ -107,17 +107,6 @@ cairo_win32_scaled_font_get_device_to_logical (cairo_scaled_font_t *scaled_font,
#endif /* CAIRO_HAS_WIN32_FONT */
-#if CAIRO_HAS_DWRITE_FONT
-
-/*
- * Win32 DirectWrite font support
- */
-
-cairo_public cairo_font_face_t *
-cairo_dwrite_font_face_create_for_dwrite_fontface (void *dwrite_font_face);
-
-#endif /* CAIRO_HAS_DWRITE_FONT */
-
CAIRO_END_DECLS
#else /* CAIRO_HAS_WIN32_SURFACE */
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index 5993aa378..a4441dc46 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -1112,7 +1112,8 @@ record_to_picture (cairo_surface_t *target,
status = _cairo_recording_surface_replay_with_clip (source,
&matrix, tmp,
- NULL);
+ NULL,
+ FALSE);
if (unlikely (status)) {
cairo_surface_destroy (tmp);
return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
@@ -1242,12 +1243,6 @@ _cairo_xcb_surface_picture (cairo_xcb_surface_t *target,
}
}
#endif
-#if CAIRO_HAS_GL_FUNCTIONS
- else if (source->type == CAIRO_SURFACE_TYPE_GL)
- {
- /* pixmap from texture */
- }
-#endif
else if (source->type == CAIRO_SURFACE_TYPE_RECORDING)
{
/* We have to skip the call to attach_snapshot() because we possibly
@@ -1266,7 +1261,8 @@ _cairo_xcb_surface_picture (cairo_xcb_surface_t *target,
if (unlikely (status))
return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
- if (image->format != CAIRO_FORMAT_INVALID) {
+ if (image->format != CAIRO_FORMAT_INVALID &&
+ image->format < ARRAY_LENGTH (target->screen->connection->standard_formats)) {
xcb_render_pictformat_t format;
format = target->screen->connection->standard_formats[image->format];
diff --git a/src/cairo-xlib-source.c b/src/cairo-xlib-source.c
index 4c3b99d9e..63e155e00 100644
--- a/src/cairo-xlib-source.c
+++ b/src/cairo-xlib-source.c
@@ -920,7 +920,8 @@ record_source (cairo_xlib_surface_t *dst,
recording = recording_pattern_get_surface (&pattern->base),
status = _cairo_recording_surface_replay_with_clip (recording,
&matrix, &src->base,
- NULL);
+ NULL,
+ FALSE);
cairo_surface_destroy (recording);
if (unlikely (status)) {
cairo_surface_destroy (&src->base);
diff --git a/src/cairo-xml-surface.c b/src/cairo-xml-surface.c
deleted file mode 100644
index 401a5b3c6..000000000
--- a/src/cairo-xml-surface.c
+++ /dev/null
@@ -1,1212 +0,0 @@
-/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2009 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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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>
- */
-
-/* This surface is intended to produce a verbose, hierarchical, DAG XML file
- * representing a single surface. It is intended to be used by debuggers,
- * such as cairo-sphinx, or by application test-suites that want a log of
- * operations.
- */
-
-#include "cairoint.h"
-
-#include "cairo-xml.h"
-
-#include "cairo-clip-private.h"
-#include "cairo-device-private.h"
-#include "cairo-default-context-private.h"
-#include "cairo-image-surface-private.h"
-#include "cairo-error-private.h"
-#include "cairo-output-stream-private.h"
-#include "cairo-recording-surface-inline.h"
-
-#define static cairo_warn static
-
-typedef struct _cairo_xml_surface cairo_xml_surface_t;
-
-typedef struct _cairo_xml {
- cairo_device_t base;
-
- cairo_output_stream_t *stream;
- int indent;
-} cairo_xml_t;
-
-struct _cairo_xml_surface {
- cairo_surface_t base;
-
- double width, height;
-};
-
-slim_hidden_proto (cairo_xml_for_recording_surface);
-
-static const cairo_surface_backend_t _cairo_xml_surface_backend;
-
-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 */
-
- "MULTIPLY", /* CAIRO_OPERATOR_MULTIPLY */
- "SCREEN", /* CAIRO_OPERATOR_SCREEN */
- "OVERLAY", /* CAIRO_OPERATOR_OVERLAY */
- "DARKEN", /* CAIRO_OPERATOR_DARKEN */
- "LIGHTEN", /* CAIRO_OPERATOR_LIGHTEN */
- "DODGE", /* CAIRO_OPERATOR_COLOR_DODGE */
- "BURN", /* CAIRO_OPERATOR_COLOR_BURN */
- "HARD_LIGHT", /* CAIRO_OPERATOR_HARD_LIGHT */
- "SOFT_LIGHT", /* CAIRO_OPERATOR_SOFT_LIGHT */
- "DIFFERENCE", /* CAIRO_OPERATOR_DIFFERENCE */
- "EXCLUSION", /* CAIRO_OPERATOR_EXCLUSION */
- "HSL_HUE", /* CAIRO_OPERATOR_HSL_HUE */
- "HSL_SATURATION", /* CAIRO_OPERATOR_HSL_SATURATION */
- "HSL_COLOR", /* CAIRO_OPERATOR_HSL_COLOR */
- "HSL_LUMINOSITY" /* CAIRO_OPERATOR_HSL_LUMINOSITY */
- };
- 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[] = {
- "DEFAULT", /* CAIRO_ANTIALIAS_DEFAULT */
- "NONE", /* CAIRO_ANTIALIAS_NONE */
- "GRAY", /* CAIRO_ANTIALIAS_GRAY */
- "SUBPIXEL", /* CAIRO_ANTIALIAS_SUBPIXEL */
- "FAST", /* CAIRO_ANTIALIAS_FAST */
- "GOOD", /* CAIRO_ANTIALIAS_GOOD */
- "BEST", /* CAIRO_ANTIALIAS_BEST */
- };
- 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 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 const char *
-_format_to_string (cairo_format_t format)
-{
- switch (format) {
- case CAIRO_FORMAT_ARGB32: return "ARGB32";
- case CAIRO_FORMAT_RGB30: return "RGB30";
- case CAIRO_FORMAT_RGB24: return "RGB24";
- case CAIRO_FORMAT_RGB16_565: return "RGB16_565";
- case CAIRO_FORMAT_RGB96F: return "RGB96F";
- case CAIRO_FORMAT_RGBA128F: return "RGBA128F";
- case CAIRO_FORMAT_A8: return "A8";
- case CAIRO_FORMAT_A1: return "A1";
- case CAIRO_FORMAT_INVALID: return "INVALID";
- }
- ASSERT_NOT_REACHED;
- return "INVALID";
-}
-
-static cairo_status_t
-_device_flush (void *abstract_device)
-{
- cairo_xml_t *xml = abstract_device;
- cairo_status_t status;
-
- status = _cairo_output_stream_flush (xml->stream);
-
- return status;
-}
-
-static void
-_device_destroy (void *abstract_device)
-{
- cairo_xml_t *xml = abstract_device;
- cairo_status_t status;
-
- status = _cairo_output_stream_destroy (xml->stream);
-
- free (xml);
-}
-
-static const cairo_device_backend_t _cairo_xml_device_backend = {
- CAIRO_DEVICE_TYPE_XML,
-
- NULL, NULL, /* lock, unlock */
-
- _device_flush,
- NULL, /* finish */
- _device_destroy
-};
-
-static cairo_device_t *
-_cairo_xml_create_internal (cairo_output_stream_t *stream)
-{
- cairo_xml_t *xml;
-
- xml = _cairo_malloc (sizeof (cairo_xml_t));
- if (unlikely (xml == NULL))
- return _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
-
- memset (xml, 0, sizeof (cairo_xml_t));
-
- _cairo_device_init (&xml->base, &_cairo_xml_device_backend);
-
- xml->indent = 0;
- xml->stream = stream;
-
- return &xml->base;
-}
-
-static void
-_cairo_xml_indent (cairo_xml_t *xml, int indent)
-{
- xml->indent += indent;
- assert (xml->indent >= 0);
-}
-
-static void CAIRO_PRINTF_FORMAT (2, 3)
-_cairo_xml_printf (cairo_xml_t *xml, const char *fmt, ...)
-{
- va_list ap;
- char indent[80];
- int len;
-
- len = MIN (xml->indent, ARRAY_LENGTH (indent));
- memset (indent, ' ', len);
- _cairo_output_stream_write (xml->stream, indent, len);
-
- va_start (ap, fmt);
- _cairo_output_stream_vprintf (xml->stream, fmt, ap);
- va_end (ap);
-
- _cairo_output_stream_write (xml->stream, "\n", 1);
-}
-
-static void CAIRO_PRINTF_FORMAT (2, 3)
-_cairo_xml_printf_start (cairo_xml_t *xml, const char *fmt, ...)
-{
- char indent[80];
- int len;
-
- len = MIN (xml->indent, ARRAY_LENGTH (indent));
- memset (indent, ' ', len);
- _cairo_output_stream_write (xml->stream, indent, len);
-
- if (fmt != NULL) {
- va_list ap;
-
- va_start (ap, fmt);
- _cairo_output_stream_vprintf (xml->stream, fmt, ap);
- va_end (ap);
- }
-}
-
-static void CAIRO_PRINTF_FORMAT (2, 3)
-_cairo_xml_printf_continue (cairo_xml_t *xml, const char *fmt, ...)
-{
- va_list ap;
-
- va_start (ap, fmt);
- _cairo_output_stream_vprintf (xml->stream, fmt, ap);
- va_end (ap);
-}
-
-static void CAIRO_PRINTF_FORMAT (2, 3)
-_cairo_xml_printf_end (cairo_xml_t *xml, const char *fmt, ...)
-{
- if (fmt != NULL) {
- va_list ap;
-
- va_start (ap, fmt);
- _cairo_output_stream_vprintf (xml->stream, fmt, ap);
- va_end (ap);
- }
-
- _cairo_output_stream_write (xml->stream, "\n", 1);
-}
-
-static cairo_surface_t *
-_cairo_xml_surface_create_similar (void *abstract_surface,
- cairo_content_t content,
- int width,
- int height)
-{
- cairo_rectangle_t extents;
-
- extents.x = extents.y = 0;
- extents.width = width;
- extents.height = height;
-
- return cairo_recording_surface_create (content, &extents);
-}
-
-static cairo_bool_t
-_cairo_xml_surface_get_extents (void *abstract_surface,
- cairo_rectangle_int_t *rectangle)
-{
- cairo_xml_surface_t *surface = abstract_surface;
-
- if (surface->width < 0 || surface->height < 0)
- return FALSE;
-
- rectangle->x = 0;
- rectangle->y = 0;
- rectangle->width = surface->width;
- rectangle->height = surface->height;
-
- return TRUE;
-}
-
-static cairo_status_t
-_cairo_xml_move_to (void *closure,
- const cairo_point_t *p1)
-{
- _cairo_xml_printf_continue (closure, " %f %f m",
- _cairo_fixed_to_double (p1->x),
- _cairo_fixed_to_double (p1->y));
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xml_line_to (void *closure,
- const cairo_point_t *p1)
-{
- _cairo_xml_printf_continue (closure, " %f %f l",
- _cairo_fixed_to_double (p1->x),
- _cairo_fixed_to_double (p1->y));
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xml_curve_to (void *closure,
- const cairo_point_t *p1,
- const cairo_point_t *p2,
- const cairo_point_t *p3)
-{
- _cairo_xml_printf_continue (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
-_cairo_xml_close_path (void *closure)
-{
- _cairo_xml_printf_continue (closure, " h");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_xml_emit_path (cairo_xml_t *xml,
- const cairo_path_fixed_t *path)
-{
- cairo_status_t status;
-
- _cairo_xml_printf_start (xml, "<path>");
- status = _cairo_path_fixed_interpret (path,
- _cairo_xml_move_to,
- _cairo_xml_line_to,
- _cairo_xml_curve_to,
- _cairo_xml_close_path,
- xml);
- assert (status == CAIRO_STATUS_SUCCESS);
- _cairo_xml_printf_end (xml, "</path>");
-}
-
-static void
-_cairo_xml_emit_string (cairo_xml_t *xml,
- const char *node,
- const char *data)
-{
- _cairo_xml_printf (xml, "<%s>%s</%s>", node, data, node);
-}
-
-static void
-_cairo_xml_emit_double (cairo_xml_t *xml,
- const char *node,
- double data)
-{
- _cairo_xml_printf (xml, "<%s>%f</%s>", node, data, node);
-}
-
-static cairo_xml_t *
-to_xml (cairo_xml_surface_t *surface)
-{
- return (cairo_xml_t *) surface->base.device;
-}
-
-static cairo_status_t
-_cairo_xml_surface_emit_clip_boxes (cairo_xml_surface_t *surface,
- const cairo_clip_t *clip)
-{
- cairo_box_t *box;
- cairo_xml_t *xml;
- int n;
-
- if (clip->num_boxes == 0)
- return CAIRO_STATUS_SUCCESS;
-
- /* skip the trivial clip covering the surface extents */
- if (surface->width >= 0 && surface->height >= 0 && clip->num_boxes == 1) {
- box = &clip->boxes[0];
- if (box->p1.x <= 0 && box->p1.y <= 0 &&
- box->p2.x - box->p1.x >= _cairo_fixed_from_double (surface->width) &&
- box->p2.y - box->p1.y >= _cairo_fixed_from_double (surface->height))
- {
- return CAIRO_STATUS_SUCCESS;
- }
- }
-
- xml = to_xml (surface);
-
- _cairo_xml_printf (xml, "<clip>");
- _cairo_xml_indent (xml, 2);
-
- _cairo_xml_printf (xml, "<path>");
- _cairo_xml_indent (xml, 2);
- for (n = 0; n < clip->num_boxes; n++) {
- box = &clip->boxes[n];
-
- _cairo_xml_printf_start (xml, "%f %f m",
- _cairo_fixed_to_double (box->p1.x),
- _cairo_fixed_to_double (box->p1.y));
- _cairo_xml_printf_continue (xml, " %f %f l",
- _cairo_fixed_to_double (box->p2.x),
- _cairo_fixed_to_double (box->p1.y));
- _cairo_xml_printf_continue (xml, " %f %f l",
- _cairo_fixed_to_double (box->p2.x),
- _cairo_fixed_to_double (box->p2.y));
- _cairo_xml_printf_continue (xml, " %f %f l",
- _cairo_fixed_to_double (box->p1.x),
- _cairo_fixed_to_double (box->p2.y));
- _cairo_xml_printf_end (xml, " h");
- }
- _cairo_xml_indent (xml, -2);
- _cairo_xml_printf (xml, "</path>");
- _cairo_xml_emit_double (xml, "tolerance", 1.0);
- _cairo_xml_emit_string (xml, "antialias",
- _antialias_to_string (CAIRO_ANTIALIAS_NONE));
- _cairo_xml_emit_string (xml, "fill-rule",
- _fill_rule_to_string (CAIRO_FILL_RULE_WINDING));
-
- _cairo_xml_indent (xml, -2);
- _cairo_xml_printf (xml, "</clip>");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xml_surface_emit_clip_path (cairo_xml_surface_t *surface,
- const cairo_clip_path_t *clip_path)
-{
- cairo_box_t box;
- cairo_status_t status;
- cairo_xml_t *xml;
-
- if (clip_path == NULL)
- return CAIRO_STATUS_SUCCESS;
-
- status = _cairo_xml_surface_emit_clip_path (surface, clip_path->prev);
- if (unlikely (status))
- return status;
-
- /* skip the trivial clip covering the surface extents */
- if (surface->width >= 0 && surface->height >= 0 &&
- _cairo_path_fixed_is_box (&clip_path->path, &box))
- {
- if (box.p1.x <= 0 && box.p1.y <= 0 &&
- box.p2.x - box.p1.x >= _cairo_fixed_from_double (surface->width) &&
- box.p2.y - box.p1.y >= _cairo_fixed_from_double (surface->height))
- {
- return CAIRO_STATUS_SUCCESS;
- }
- }
-
- xml = to_xml (surface);
-
- _cairo_xml_printf_start (xml, "<clip>");
- _cairo_xml_indent (xml, 2);
-
- _cairo_xml_emit_path (xml, &clip_path->path);
- _cairo_xml_emit_double (xml, "tolerance", clip_path->tolerance);
- _cairo_xml_emit_string (xml, "antialias",
- _antialias_to_string (clip_path->antialias));
- _cairo_xml_emit_string (xml, "fill-rule",
- _fill_rule_to_string (clip_path->fill_rule));
-
- _cairo_xml_indent (xml, -2);
- _cairo_xml_printf_end (xml, "</clip>");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xml_surface_emit_clip (cairo_xml_surface_t *surface,
- const cairo_clip_t *clip)
-{
- cairo_status_t status;
-
- if (clip == NULL)
- return CAIRO_STATUS_SUCCESS;
-
- status = _cairo_xml_surface_emit_clip_boxes (surface, clip);
- if (unlikely (status))
- return status;
-
- return _cairo_xml_surface_emit_clip_path (surface, clip->path);
-}
-
-static cairo_status_t
-_cairo_xml_emit_solid (cairo_xml_t *xml,
- const cairo_solid_pattern_t *solid)
-{
- _cairo_xml_printf (xml, "<solid>%f %f %f %f</solid>",
- solid->color.red,
- solid->color.green,
- solid->color.blue,
- solid->color.alpha);
- return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_xml_emit_matrix (cairo_xml_t *xml,
- const cairo_matrix_t *matrix)
-{
- if (! _cairo_matrix_is_identity (matrix)) {
- _cairo_xml_printf (xml, "<matrix>%f %f %f %f %f %f</matrix>",
- matrix->xx, matrix->yx,
- matrix->xy, matrix->yy,
- matrix->x0, matrix->y0);
- }
-}
-
-static void
-_cairo_xml_emit_gradient (cairo_xml_t *xml,
- const cairo_gradient_pattern_t *gradient)
-{
- unsigned int i;
-
- for (i = 0; i < gradient->n_stops; i++) {
- _cairo_xml_printf (xml,
- "<color-stop>%f %f %f %f %f</color-stop>",
- gradient->stops[i].offset,
- gradient->stops[i].color.red,
- gradient->stops[i].color.green,
- gradient->stops[i].color.blue,
- gradient->stops[i].color.alpha);
- }
-}
-
-static cairo_status_t
-_cairo_xml_emit_linear (cairo_xml_t *xml,
- const cairo_linear_pattern_t *linear)
-{
- _cairo_xml_printf (xml,
- "<linear x1='%f' y1='%f' x2='%f' y2='%f'>",
- linear->pd1.x, linear->pd1.y,
- linear->pd2.x, linear->pd2.y);
- _cairo_xml_indent (xml, 2);
- _cairo_xml_emit_gradient (xml, &linear->base);
- _cairo_xml_indent (xml, -2);
- _cairo_xml_printf (xml, "</linear>");
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xml_emit_radial (cairo_xml_t *xml,
- const cairo_radial_pattern_t *radial)
-{
- _cairo_xml_printf (xml,
- "<radial x1='%f' y1='%f' r1='%f' x2='%f' y2='%f' r2='%f'>",
- radial->cd1.center.x, radial->cd1.center.y, radial->cd1.radius,
- radial->cd2.center.x, radial->cd2.center.y, radial->cd2.radius);
- _cairo_xml_indent (xml, 2);
- _cairo_xml_emit_gradient (xml, &radial->base);
- _cairo_xml_indent (xml, -2);
- _cairo_xml_printf (xml, "</radial>");
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_write_func (void *closure, const unsigned char *data, unsigned len)
-{
- _cairo_output_stream_write (closure, data, len);
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xml_emit_image (cairo_xml_t *xml,
- cairo_image_surface_t *image)
-{
- cairo_output_stream_t *stream;
- cairo_status_t status;
-
- _cairo_xml_printf_start (xml,
- "<image width='%d' height='%d' format='%s'>",
- image->width, image->height,
- _format_to_string (image->format));
-
- stream = _cairo_base64_stream_create (xml->stream);
- status = cairo_surface_write_to_png_stream (&image->base,
- _write_func, stream);
- assert (status == CAIRO_STATUS_SUCCESS);
- status = _cairo_output_stream_destroy (stream);
- if (unlikely (status))
- return status;
-
- _cairo_xml_printf_end (xml, "</image>");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xml_emit_surface (cairo_xml_t *xml,
- const cairo_surface_pattern_t *pattern)
-{
- cairo_surface_t *source = pattern->surface;
- cairo_status_t status;
-
- if (_cairo_surface_is_recording (source)) {
- status = cairo_xml_for_recording_surface (&xml->base, source);
- } else {
- cairo_image_surface_t *image;
- void *image_extra;
-
- status = _cairo_surface_acquire_source_image (source,
- &image, &image_extra);
- if (unlikely (status))
- return status;
-
- status = _cairo_xml_emit_image (xml, image);
-
- _cairo_surface_release_source_image (source, image, image_extra);
- }
-
- return status;
-}
-
-static cairo_status_t
-_cairo_xml_emit_pattern (cairo_xml_t *xml,
- const char *source_or_mask,
- const cairo_pattern_t *pattern)
-{
- cairo_status_t status;
-
- _cairo_xml_printf (xml, "<%s-pattern>", source_or_mask);
- _cairo_xml_indent (xml, 2);
-
- switch (pattern->type) {
- case CAIRO_PATTERN_TYPE_SOLID:
- status = _cairo_xml_emit_solid (xml, (cairo_solid_pattern_t *) pattern);
- break;
- case CAIRO_PATTERN_TYPE_LINEAR:
- status = _cairo_xml_emit_linear (xml, (cairo_linear_pattern_t *) pattern);
- break;
- case CAIRO_PATTERN_TYPE_RADIAL:
- status = _cairo_xml_emit_radial (xml, (cairo_radial_pattern_t *) pattern);
- break;
- case CAIRO_PATTERN_TYPE_SURFACE:
- status = _cairo_xml_emit_surface (xml, (cairo_surface_pattern_t *) pattern);
- break;
- default:
- ASSERT_NOT_REACHED;
- status = CAIRO_INT_STATUS_UNSUPPORTED;
- break;
- }
-
- if (pattern->type != CAIRO_PATTERN_TYPE_SOLID) {
- _cairo_xml_emit_matrix (xml, &pattern->matrix);
- _cairo_xml_printf (xml,
- "<extend>%s</extend>",
- _extend_to_string (pattern->extend));
- _cairo_xml_printf (xml,
- "<filter>%s</filter>",
- _filter_to_string (pattern->filter));
- }
-
- _cairo_xml_indent (xml, -2);
- _cairo_xml_printf (xml, "</%s-pattern>", source_or_mask);
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_xml_surface_paint (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_clip_t *clip)
-{
- cairo_xml_surface_t *surface = abstract_surface;
- cairo_xml_t *xml = to_xml (surface);
- cairo_status_t status;
-
- _cairo_xml_printf (xml, "<paint>");
- _cairo_xml_indent (xml, 2);
-
- _cairo_xml_emit_string (xml, "operator", _operator_to_string (op));
-
- status = _cairo_xml_surface_emit_clip (surface, clip);
- if (unlikely (status))
- return status;
-
- status = _cairo_xml_emit_pattern (xml, "source", source);
- if (unlikely (status))
- return status;
-
- _cairo_xml_indent (xml, -2);
- _cairo_xml_printf (xml, "</paint>");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_xml_surface_mask (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_pattern_t *mask,
- const cairo_clip_t *clip)
-{
- cairo_xml_surface_t *surface = abstract_surface;
- cairo_xml_t *xml = to_xml (surface);
- cairo_status_t status;
-
- _cairo_xml_printf (xml, "<mask>");
- _cairo_xml_indent (xml, 2);
-
- _cairo_xml_emit_string (xml, "operator", _operator_to_string (op));
-
- status = _cairo_xml_surface_emit_clip (surface, clip);
- if (unlikely (status))
- return status;
-
- status = _cairo_xml_emit_pattern (xml, "source", source);
- if (unlikely (status))
- return status;
-
- status = _cairo_xml_emit_pattern (xml, "mask", mask);
- if (unlikely (status))
- return status;
-
- _cairo_xml_indent (xml, -2);
- _cairo_xml_printf (xml, "</mask>");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_xml_surface_stroke (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t *path,
- const cairo_stroke_style_t *style,
- const cairo_matrix_t *ctm,
- const cairo_matrix_t *ctm_inverse,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip)
-{
- cairo_xml_surface_t *surface = abstract_surface;
- cairo_xml_t *xml = to_xml (surface);
- cairo_status_t status;
-
- _cairo_xml_printf (xml, "<stroke>");
- _cairo_xml_indent (xml, 2);
-
- _cairo_xml_emit_string (xml, "operator", _operator_to_string (op));
- _cairo_xml_emit_double (xml, "line-width", style->line_width);
- _cairo_xml_emit_double (xml, "miter-limit", style->miter_limit);
- _cairo_xml_emit_string (xml, "line-cap", _line_cap_to_string (style->line_cap));
- _cairo_xml_emit_string (xml, "line-join", _line_join_to_string (style->line_join));
-
- status = _cairo_xml_surface_emit_clip (surface, clip);
- if (unlikely (status))
- return status;
-
- status = _cairo_xml_emit_pattern (xml, "source", source);
- if (unlikely (status))
- return status;
-
- if (style->num_dashes) {
- unsigned int i;
-
- _cairo_xml_printf_start (xml, "<dash offset='%f'>",
- style->dash_offset);
- for (i = 0; i < style->num_dashes; i++)
- _cairo_xml_printf_continue (xml, "%f ", style->dash[i]);
-
- _cairo_xml_printf_end (xml, "</dash>");
- }
-
- _cairo_xml_emit_path (xml, path);
- _cairo_xml_emit_double (xml, "tolerance", tolerance);
- _cairo_xml_emit_string (xml, "antialias", _antialias_to_string (antialias));
-
- _cairo_xml_emit_matrix (xml, ctm);
-
- _cairo_xml_indent (xml, -2);
- _cairo_xml_printf (xml, "</stroke>");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_xml_surface_fill (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- const cairo_path_fixed_t*path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias,
- const cairo_clip_t *clip)
-{
- cairo_xml_surface_t *surface = abstract_surface;
- cairo_xml_t *xml = to_xml (surface);
- cairo_status_t status;
-
- _cairo_xml_printf (xml, "<fill>");
- _cairo_xml_indent (xml, 2);
-
- _cairo_xml_emit_string (xml, "operator", _operator_to_string (op));
-
- status = _cairo_xml_surface_emit_clip (surface, clip);
- if (unlikely (status))
- return status;
-
- status = _cairo_xml_emit_pattern (xml, "source", source);
- if (unlikely (status))
- return status;
-
- _cairo_xml_emit_path (xml, path);
- _cairo_xml_emit_double (xml, "tolerance", tolerance);
- _cairo_xml_emit_string (xml, "antialias", _antialias_to_string (antialias));
- _cairo_xml_emit_string (xml, "fill-rule", _fill_rule_to_string (fill_rule));
-
- _cairo_xml_indent (xml, -2);
- _cairo_xml_printf (xml, "</fill>");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-#if CAIRO_HAS_FT_FONT
-#include "cairo-ft-private.h"
-static cairo_status_t
-_cairo_xml_emit_type42_font (cairo_xml_t *xml,
- cairo_scaled_font_t *scaled_font)
-{
- const cairo_scaled_font_backend_t *backend;
- cairo_output_stream_t *base64_stream;
- cairo_output_stream_t *zlib_stream;
- cairo_status_t status, status2;
- unsigned long size;
- uint32_t len;
- 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 = _cairo_malloc (size);
- if (unlikely (buf == NULL))
- return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
- status = backend->load_truetype_table (scaled_font, 0, 0, buf, &size);
- if (unlikely (status)) {
- free (buf);
- return status;
- }
-
- _cairo_xml_printf_start (xml, "<font type='42' flags='%d' index='0'>",
- _cairo_ft_scaled_font_get_load_flags (scaled_font));
-
-
- base64_stream = _cairo_base64_stream_create (xml->stream);
- len = size;
- _cairo_output_stream_write (base64_stream, &len, sizeof (len));
-
- zlib_stream = _cairo_deflate_stream_create (base64_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 (base64_stream);
- if (status == CAIRO_STATUS_SUCCESS)
- status = status2;
-
- _cairo_xml_printf_end (xml, "</font>");
-
- return status;
-}
-#else
-static cairo_status_t
-_cairo_xml_emit_type42_font (cairo_xml_t *xml,
- cairo_scaled_font_t *scaled_font)
-{
- return CAIRO_INT_STATUS_UNSUPPORTED;
-}
-#endif
-
-static cairo_status_t
-_cairo_xml_emit_type3_font (cairo_xml_t *xml,
- cairo_scaled_font_t *scaled_font,
- cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- _cairo_xml_printf_start (xml, "<font type='3'>");
- _cairo_xml_printf_end (xml, "</font>");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_xml_emit_scaled_font (cairo_xml_t *xml,
- cairo_scaled_font_t *scaled_font,
- cairo_glyph_t *glyphs,
- int num_glyphs)
-{
- cairo_int_status_t status;
-
- _cairo_xml_printf (xml, "<scaled-font>");
- _cairo_xml_indent (xml, 2);
-
- status = _cairo_xml_emit_type42_font (xml, scaled_font);
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- status = _cairo_xml_emit_type3_font (xml, scaled_font,
- glyphs, num_glyphs);
- }
-
- _cairo_xml_indent (xml, -2);
- _cairo_xml_printf (xml, "</scaled-font>");
-
- return status;
-}
-
-static cairo_int_status_t
-_cairo_xml_surface_glyphs (void *abstract_surface,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_glyph_t *glyphs,
- int num_glyphs,
- cairo_scaled_font_t *scaled_font,
- const cairo_clip_t *clip)
-{
- cairo_xml_surface_t *surface = abstract_surface;
- cairo_xml_t *xml = to_xml (surface);
- cairo_status_t status;
- int i;
-
- _cairo_xml_printf (xml, "<glyphs>");
- _cairo_xml_indent (xml, 2);
-
- _cairo_xml_emit_string (xml, "operator", _operator_to_string (op));
-
- status = _cairo_xml_surface_emit_clip (surface, clip);
- if (unlikely (status))
- return status;
-
- status = _cairo_xml_emit_pattern (xml, "source", source);
- if (unlikely (status))
- return status;
-
- status = _cairo_xml_emit_scaled_font (xml, scaled_font, glyphs, num_glyphs);
- if (unlikely (status))
- return status;
-
- for (i = 0; i < num_glyphs; i++) {
- _cairo_xml_printf (xml, "<glyph index='%lu'>%f %f</glyph>",
- glyphs[i].index,
- glyphs[i].x,
- glyphs[i].y);
- }
-
- _cairo_xml_indent (xml, -2);
- _cairo_xml_printf (xml, "</glyphs>");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static const cairo_surface_backend_t
-_cairo_xml_surface_backend = {
- CAIRO_SURFACE_TYPE_XML,
- NULL,
-
- _cairo_default_context_create,
-
- _cairo_xml_surface_create_similar,
- NULL, /* create_similar_image */
- NULL, /* map_to_image */
- NULL, /* unmap_image */
-
- _cairo_surface_default_source,
- NULL, /* acquire source image */
- NULL, /* release source image */
- NULL, /* snapshot */
-
- NULL, /* copy page */
- NULL, /* show page */
-
- _cairo_xml_surface_get_extents,
- NULL, /* get_font_options */
-
- NULL, /* flush */
- NULL, /* mark_dirty_rectangle */
-
- _cairo_xml_surface_paint,
- _cairo_xml_surface_mask,
- _cairo_xml_surface_stroke,
- _cairo_xml_surface_fill,
- NULL, /* fill_stroke */
- _cairo_xml_surface_glyphs,
-};
-
-static cairo_surface_t *
-_cairo_xml_surface_create_internal (cairo_device_t *device,
- cairo_content_t content,
- double width,
- double height)
-{
- cairo_xml_surface_t *surface;
-
- surface = _cairo_malloc (sizeof (cairo_xml_surface_t));
- if (unlikely (surface == NULL))
- return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
-
- _cairo_surface_init (&surface->base,
- &_cairo_xml_surface_backend,
- device,
- content,
- TRUE); /* is_vector */
-
- surface->width = width;
- surface->height = height;
-
- return &surface->base;
-}
-
-cairo_device_t *
-cairo_xml_create (const char *filename)
-{
- cairo_output_stream_t *stream;
- cairo_status_t status;
-
- stream = _cairo_output_stream_create_for_filename (filename);
- if ((status = _cairo_output_stream_get_status (stream)))
- return _cairo_device_create_in_error (status);
-
- return _cairo_xml_create_internal (stream);
-}
-
-cairo_device_t *
-cairo_xml_create_for_stream (cairo_write_func_t write_func,
- void *closure)
-{
- cairo_output_stream_t *stream;
- cairo_status_t status;
-
- stream = _cairo_output_stream_create (write_func, NULL, closure);
- if ((status = _cairo_output_stream_get_status (stream)))
- return _cairo_device_create_in_error (status);
-
- return _cairo_xml_create_internal (stream);
-}
-
-cairo_surface_t *
-cairo_xml_surface_create (cairo_device_t *device,
- cairo_content_t content,
- double width, double height)
-{
- if (unlikely (device->backend->type != CAIRO_DEVICE_TYPE_XML))
- return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
-
- if (unlikely (device->status))
- return _cairo_surface_create_in_error (device->status);
-
- return _cairo_xml_surface_create_internal (device, content, width, height);
-}
-
-cairo_status_t
-cairo_xml_for_recording_surface (cairo_device_t *device,
- cairo_surface_t *recording_surface)
-{
- cairo_box_t bbox;
- cairo_rectangle_int_t extents;
- cairo_surface_t *surface;
- cairo_xml_t *xml;
- cairo_status_t status;
-
- if (unlikely (device->status))
- return device->status;
-
- if (unlikely (recording_surface->status))
- return recording_surface->status;
-
- if (unlikely (device->backend->type != CAIRO_DEVICE_TYPE_XML))
- return _cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
-
- if (unlikely (! _cairo_surface_is_recording (recording_surface)))
- return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
-
- status = _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface,
- &bbox, NULL);
- if (unlikely (status))
- return status;
-
- _cairo_box_round_to_rectangle (&bbox, &extents);
- surface = _cairo_xml_surface_create_internal (device,
- recording_surface->content,
- extents.width,
- extents.height);
- if (unlikely (surface->status))
- return surface->status;
-
- xml = (cairo_xml_t *) device;
-
- _cairo_xml_printf (xml,
- "<surface content='%s' width='%d' height='%d'>",
- _content_to_string (recording_surface->content),
- extents.width, extents.height);
- _cairo_xml_indent (xml, 2);
-
- cairo_surface_set_device_offset (surface, -extents.x, -extents.y);
- status = _cairo_recording_surface_replay (recording_surface, surface);
- cairo_surface_destroy (surface);
-
- _cairo_xml_indent (xml, -2);
- _cairo_xml_printf (xml, "</surface>");
-
- return status;
-}
-slim_hidden_def (cairo_xml_for_recording_surface);
diff --git a/src/cairo.c b/src/cairo.c
index f55429405..3d4fea601 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -372,7 +372,8 @@ static const cairo_t _cairo_nil[] = {
DEFINE_NIL_CONTEXT (CAIRO_STATUS_FREETYPE_ERROR),
DEFINE_NIL_CONTEXT (CAIRO_STATUS_WIN32_GDI_ERROR),
DEFINE_NIL_CONTEXT (CAIRO_STATUS_TAG_ERROR),
- DEFINE_NIL_CONTEXT (CAIRO_STATUS_DWRITE_ERROR)
+ DEFINE_NIL_CONTEXT (CAIRO_STATUS_DWRITE_ERROR),
+ DEFINE_NIL_CONTEXT (CAIRO_STATUS_SVG_FONT_ERROR)
};
COMPILE_TIME_ASSERT (ARRAY_LENGTH (_cairo_nil) == CAIRO_STATUS_LAST_STATUS - 1);
@@ -706,6 +707,7 @@ 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:
@@ -813,6 +815,7 @@ 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:
@@ -918,6 +921,8 @@ slim_hidden_def (cairo_set_source_rgb);
* range 0 to 1. If the values passed in are outside that range, they
* will be clamped.
*
+ * Note that the color and alpha values are not premultiplied.
+ *
* The default source pattern is opaque black, (that is, it is
* equivalent to cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0)).
*
@@ -937,6 +942,7 @@ cairo_set_source_rgba (cairo_t *cr,
if (unlikely (status))
_cairo_set_error (cr, status);
}
+slim_hidden_def (cairo_set_source_rgba);
/**
* cairo_set_source_surface:
@@ -1050,6 +1056,7 @@ cairo_get_source (cairo_t *cr)
return cr->backend->get_source (cr);
}
+slim_hidden_def (cairo_get_source);
/**
* cairo_set_tolerance:
@@ -1159,9 +1166,8 @@ cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule)
* cairo_set_line_width() and ignore this note.
*
* As with the other stroke parameters, the current line width is
- * examined by cairo_stroke(), cairo_stroke_extents(), and
- * cairo_stroke_to_path(), but does not have any effect during path
- * construction.
+ * examined by cairo_stroke(), and cairo_stroke_extents(), but does not have
+ * any effect during path construction.
*
* The default line width value is 2.0.
*
@@ -1235,9 +1241,8 @@ slim_hidden_def (cairo_set_hairline);
* styles are drawn.
*
* As with the other stroke parameters, the current line cap style is
- * examined by cairo_stroke(), cairo_stroke_extents(), and
- * cairo_stroke_to_path(), but does not have any effect during path
- * construction.
+ * examined by cairo_stroke(), and cairo_stroke_extents(), but does not have
+ * any effect during path construction.
*
* The default line cap style is %CAIRO_LINE_CAP_BUTT.
*
@@ -1267,9 +1272,8 @@ slim_hidden_def (cairo_set_line_cap);
* styles are drawn.
*
* As with the other stroke parameters, the current line join style is
- * examined by cairo_stroke(), cairo_stroke_extents(), and
- * cairo_stroke_to_path(), but does not have any effect during path
- * construction.
+ * examined by cairo_stroke(), and cairo_stroke_extents(), but does not have
+ * any effect during path construction.
*
* The default line join style is %CAIRO_LINE_JOIN_MITER.
*
@@ -1338,6 +1342,7 @@ cairo_set_dash (cairo_t *cr,
if (unlikely (status))
_cairo_set_error (cr, status);
}
+slim_hidden_def (cairo_set_dash);
/**
* cairo_get_dash_count:
@@ -1403,9 +1408,8 @@ cairo_get_dash (cairo_t *cr,
* converted to a bevel.
*
* As with the other stroke parameters, the current line miter limit is
- * examined by cairo_stroke(), cairo_stroke_extents(), and
- * cairo_stroke_to_path(), but does not have any effect during path
- * construction.
+ * examined by cairo_stroke(), and cairo_stroke_extents(), but does not have
+ * any effect during path construction.
*
* The default miter limit value is 10.0, which will convert joins
* with interior angles less than 11 degrees to bevels instead of
@@ -1512,6 +1516,7 @@ cairo_rotate (cairo_t *cr, double angle)
if (unlikely (status))
_cairo_set_error (cr, status);
}
+slim_hidden_def (cairo_rotate);
/**
* cairo_transform:
@@ -1587,6 +1592,7 @@ cairo_identity_matrix (cairo_t *cr)
if (unlikely (status))
_cairo_set_error (cr, status);
}
+slim_hidden_def (cairo_identity_matrix);
/**
* cairo_user_to_device:
@@ -1901,6 +1907,7 @@ cairo_arc (cairo_t *cr,
if (unlikely (status))
_cairo_set_error (cr, status);
}
+slim_hidden_def (cairo_arc);
/**
* cairo_arc_negative:
@@ -1946,6 +1953,7 @@ cairo_arc_negative (cairo_t *cr,
if (unlikely (status))
_cairo_set_error (cr, status);
}
+slim_hidden_def (cairo_arc_negative);
/* XXX: NYI
void
@@ -2128,6 +2136,7 @@ cairo_rectangle (cairo_t *cr,
if (unlikely (status))
_cairo_set_error (cr, status);
}
+slim_hidden_def (cairo_rectangle);
#if 0
/* XXX: NYI */
@@ -2288,6 +2297,7 @@ cairo_paint_with_alpha (cairo_t *cr,
if (unlikely (status))
_cairo_set_error (cr, status);
}
+slim_hidden_def (cairo_paint_with_alpha);
/**
* cairo_mask:
@@ -2463,6 +2473,7 @@ cairo_fill (cairo_t *cr)
if (unlikely (status))
_cairo_set_error (cr, status);
}
+slim_hidden_def (cairo_fill);
/**
* cairo_fill_preserve:
@@ -2754,6 +2765,7 @@ cairo_clip (cairo_t *cr)
if (unlikely (status))
_cairo_set_error (cr, status);
}
+slim_hidden_def (cairo_clip);
/**
* cairo_clip_preserve:
@@ -2860,6 +2872,7 @@ cairo_clip_extents (cairo_t *cr,
if (unlikely (status))
_cairo_set_error (cr, status);
}
+slim_hidden_def (cairo_clip_extents);
/**
* cairo_in_clip:
@@ -2924,7 +2937,7 @@ cairo_copy_clip_rectangle_list (cairo_t *cr)
* CAIRO_TAG_DEST:
*
* Create a destination for a hyperlink. Destination tag attributes
- * are detailed at [Destinations][dests].
+ * are detailed at [Destinations][dest].
*
* Since: 1.16
**/
@@ -2933,7 +2946,7 @@ cairo_copy_clip_rectangle_list (cairo_t *cr)
* CAIRO_TAG_LINK:
*
* Create hyperlink. Link tag attributes are detailed at
- * [Links][links].
+ * [Links][link].
*
* Since: 1.16
**/
@@ -3343,7 +3356,7 @@ cairo_set_scaled_font (cairo_t *cr,
if (unlikely (cr->status))
return;
- if ((scaled_font == NULL)) {
+ if (scaled_font == NULL) {
_cairo_set_error (cr, _cairo_error (CAIRO_STATUS_NULL_POINTER));
return;
}
@@ -4004,6 +4017,7 @@ cairo_has_current_point (cairo_t *cr)
return cr->backend->has_current_point (cr);
}
+slim_hidden_def (cairo_has_current_point);
/**
* cairo_get_current_point:
@@ -4026,7 +4040,7 @@ cairo_has_current_point (cairo_t *cr)
* cairo_move_to(), cairo_line_to(), cairo_curve_to(),
* cairo_rel_move_to(), cairo_rel_line_to(), cairo_rel_curve_to(),
* cairo_arc(), cairo_arc_negative(), cairo_rectangle(),
- * cairo_text_path(), cairo_glyph_path(), cairo_stroke_to_path().
+ * cairo_text_path(), cairo_glyph_path().
*
* Some functions use and alter the current point but do not
* otherwise change current path:
@@ -4074,6 +4088,7 @@ cairo_get_fill_rule (cairo_t *cr)
return cr->backend->get_fill_rule (cr);
}
+slim_hidden_def (cairo_set_fill_rule);
/**
* cairo_get_line_width:
@@ -4174,6 +4189,7 @@ cairo_get_miter_limit (cairo_t *cr)
return cr->backend->get_miter_limit (cr);
}
+slim_hidden_def (cairo_set_miter_limit);
/**
* cairo_get_matrix:
@@ -4289,6 +4305,7 @@ cairo_copy_path (cairo_t *cr)
return cr->backend->copy_path (cr);
}
+slim_hidden_def (cairo_copy_path);
/**
* cairo_copy_path_flat:
@@ -4383,6 +4400,7 @@ cairo_append_path (cairo_t *cr,
if (unlikely (status))
_cairo_set_error (cr, status);
}
+slim_hidden_def (cairo_append_path);
/**
* cairo_status:
diff --git a/src/cairo.h b/src/cairo.h
index 82e2c69d8..eef4c442b 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -157,9 +157,7 @@ typedef struct _cairo_surface cairo_surface_t;
*
* A #cairo_device_t represents the driver interface for drawing
* operations to a #cairo_surface_t. There are different subtypes of
- * #cairo_device_t for different drawing backends; for example,
- * cairo_egl_device_create() creates a device that wraps an EGL display and
- * context.
+ * #cairo_device_t for different drawing backends.
*
* The type of a device can be queried with cairo_device_get_type().
*
@@ -297,6 +295,7 @@ typedef struct _cairo_user_data_key {
* @CAIRO_STATUS_WIN32_GDI_ERROR: error occurred in the Windows Graphics Device Interface (Since 1.16)
* @CAIRO_STATUS_TAG_ERROR: invalid tag name, attributes, or nesting (Since 1.16)
* @CAIRO_STATUS_DWRITE_ERROR: error occurred in the Windows Direct Write API (Since 1.18)
+ * @CAIRO_STATUS_SVG_FONT_ERROR: error occurred in OpenType-SVG font rendering (Since 1.18)
* @CAIRO_STATUS_LAST_STATUS: this is a special value indicating the number of
* status values defined in this enumeration. When using this value, note
* that the version of cairo at run-time may have additional status values
@@ -358,6 +357,7 @@ typedef enum _cairo_status {
CAIRO_STATUS_WIN32_GDI_ERROR,
CAIRO_STATUS_TAG_ERROR,
CAIRO_STATUS_DWRITE_ERROR,
+ CAIRO_STATUS_SVG_FONT_ERROR,
CAIRO_STATUS_LAST_STATUS
} cairo_status_t;
@@ -477,7 +477,7 @@ typedef cairo_status_t (*cairo_read_func_t) (void *closure,
/**
* cairo_rectangle_int_t:
* @x: X coordinate of the left side of the rectangle
- * @y: Y coordinate of the the top side of the rectangle
+ * @y: Y coordinate of the top side of the rectangle
* @width: width of the rectangle
* @height: height of the rectangle
*
@@ -1000,7 +1000,7 @@ cairo_clip_extents (cairo_t *cr,
/**
* cairo_rectangle_t:
* @x: X coordinate of the left side of the rectangle
- * @y: Y coordinate of the the top side of the rectangle
+ * @y: Y coordinate of the top side of the rectangle
* @width: width of the rectangle
* @height: height of the rectangle
*
@@ -1379,7 +1379,7 @@ typedef enum _cairo_hint_metrics {
* contains a color presentation for a glyph, and when supported by
* the font backend, the glyph will be rendered in color, since 1.18.
*
- * Specifies if color fonts are to be rendered using the the color
+ * Specifies if color fonts are to be rendered using the color
* glyphs or outline glyphs. Glyphs that do not have a color
* presentation, and non-color fonts are not affected by this font
* option.
@@ -1485,8 +1485,20 @@ cairo_public void
cairo_font_options_set_color_palette (cairo_font_options_t *options,
unsigned int palette_index);
+cairo_public void
+cairo_font_options_set_custom_palette_color (cairo_font_options_t *options,
+ unsigned int index,
+ double red, double green,
+ double blue, double alpha);
+
+cairo_public cairo_status_t
+cairo_font_options_get_custom_palette_color (cairo_font_options_t *options,
+ unsigned int index,
+ double *red, double *green,
+ double *blue, double *alpha);
+
/* This interface is for dealing with text as text, not caring about the
- font object inside the the cairo_t. */
+ font object inside the cairo_t. */
cairo_public void
cairo_select_font_face (cairo_t *cr,
@@ -1802,25 +1814,14 @@ typedef cairo_status_t (*cairo_user_scaled_font_init_func_t) (cairo_scaled_font_
* cairo_user_font_face_set_render_glyph_func(), the result is
* undefined if any source other than the default source on @cr is
* used. That means, glyph bitmaps should be rendered using
- * cairo_mask() instead of cairo_paint(). When this callback is set with
- * cairo_user_font_face_set_render_color_glyph_func(), setting the
- * source is a valid operation.
+ * cairo_mask() instead of cairo_paint().
*
* When this callback is set with
* cairo_user_font_face_set_render_color_glyph_func(), the default
- * source is the current source color of the context that is rendering
- * the user font. That is, the same color a non-color user font will
- * be rendered in. In most cases the callback will want to set a
- * specific color. If the callback wishes to use the current context
- * color after using another source, it should retain a reference to
- * the source or use cairo_save()/cairo_restore() prior to changing
- * the source. Note that the default source contains an internal
- * marker to indicate that it is to be substituted with the current
- * context source color when rendered to a surface. Querying the
- * default source pattern will reveal a solid black color, however
- * this is not representative of the color that will actually be
- * used. Similarly, setting a solid black color will render black, not
- * the current context source when the glyph is painted to a surface.
+ * source is black. Setting the source is a valid
+ * operation. cairo_user_scaled_font_get_foreground_marker() or
+ * cairo_user_scaled_font_get_foreground_source() may be called to
+ * obtain the current source at the time the glyph is rendered.
*
* Other non-default settings on @cr include a font size of 1.0 (given that
* it is set up to be in font space), and font options corresponding to
@@ -1843,10 +1844,13 @@ typedef cairo_status_t (*cairo_user_scaled_font_init_func_t) (cairo_scaled_font_
* Where both color and non-color callbacks has been set using
* cairo_user_font_face_set_render_color_glyph_func(), and
* cairo_user_font_face_set_render_glyph_func(), the color glyph
- * callback may return %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED if the
- * glyph is not a color glyph. This is the only case in which the
- * %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED may be returned from a
- * render callback.
+ * callback will be called first. If the color glyph callback returns
+ * %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED, any drawing operations are
+ * discarded and the non-color callback will be called. This is the
+ * only case in which the %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED may
+ * be returned from a render callback. This fallback sequence allows a
+ * user font face to contain a combination of both color and non-color
+ * glyphs.
*
* Returns: %CAIRO_STATUS_SUCCESS upon success,
* %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED if fallback options should be tried,
@@ -2014,6 +2018,11 @@ cairo_user_font_face_get_text_to_glyphs_func (cairo_font_face_t *font_face);
cairo_public cairo_user_scaled_font_unicode_to_glyph_func_t
cairo_user_font_face_get_unicode_to_glyph_func (cairo_font_face_t *font_face);
+cairo_public cairo_pattern_t *
+cairo_user_scaled_font_get_foreground_marker (cairo_scaled_font_t *scaled_font);
+
+cairo_public cairo_pattern_t *
+cairo_user_scaled_font_get_foreground_source (cairo_scaled_font_t *scaled_font);
/* Query functions */
@@ -2440,26 +2449,37 @@ cairo_surface_status (cairo_surface_t *surface);
* @CAIRO_SURFACE_TYPE_PS: The surface is of type ps, since 1.2
* @CAIRO_SURFACE_TYPE_XLIB: The surface is of type xlib, since 1.2
* @CAIRO_SURFACE_TYPE_XCB: The surface is of type xcb, since 1.2
- * @CAIRO_SURFACE_TYPE_GLITZ: The surface is of type glitz, since 1.2
+ * @CAIRO_SURFACE_TYPE_GLITZ: The surface is of type glitz, since 1.2, deprecated 1.18
+ * (glitz support have been removed, this surface type will never be set by cairo)
* @CAIRO_SURFACE_TYPE_QUARTZ: The surface is of type quartz, since 1.2
* @CAIRO_SURFACE_TYPE_WIN32: The surface is of type win32, since 1.2
- * @CAIRO_SURFACE_TYPE_BEOS: The surface is of type beos, since 1.2
- * @CAIRO_SURFACE_TYPE_DIRECTFB: The surface is of type directfb, since 1.2
+ * @CAIRO_SURFACE_TYPE_BEOS: The surface is of type beos, since 1.2, deprecated 1.18
+ * (beos support have been removed, this surface type will never be set by cairo)
+ * @CAIRO_SURFACE_TYPE_DIRECTFB: The surface is of type directfb, since 1.2, deprecated 1.18
+ * (directfb support have been removed, this surface type will never be set by cairo)
* @CAIRO_SURFACE_TYPE_SVG: The surface is of type svg, since 1.2
- * @CAIRO_SURFACE_TYPE_OS2: The surface is of type os2, since 1.4
+ * @CAIRO_SURFACE_TYPE_OS2: The surface is of type os2, since 1.4, deprecated 1.18
+ * (os2 support have been removed, this surface type will never be set by cairo)
* @CAIRO_SURFACE_TYPE_WIN32_PRINTING: The surface is a win32 printing surface, since 1.6
* @CAIRO_SURFACE_TYPE_QUARTZ_IMAGE: The surface is of type quartz_image, since 1.6
* @CAIRO_SURFACE_TYPE_SCRIPT: The surface is of type script, since 1.10
- * @CAIRO_SURFACE_TYPE_QT: The surface is of type Qt, since 1.10
+ * @CAIRO_SURFACE_TYPE_QT: The surface is of type Qt, since 1.10, deprecated 1.18
+ * (Ot support have been removed, this surface type will never be set by cairo)
* @CAIRO_SURFACE_TYPE_RECORDING: The surface is of type recording, since 1.10
- * @CAIRO_SURFACE_TYPE_VG: The surface is a OpenVG surface, since 1.10
- * @CAIRO_SURFACE_TYPE_GL: The surface is of type OpenGL, since 1.10
- * @CAIRO_SURFACE_TYPE_DRM: The surface is of type Direct Render Manager, since 1.10
+ * @CAIRO_SURFACE_TYPE_VG: The surface is a OpenVG surface, since 1.10, deprecated 1.18
+ * (OpenVG support have been removed, this surface type will never be set by cairo)
+ * @CAIRO_SURFACE_TYPE_GL: The surface is of type OpenGL, since 1.10, deprecated 1.18
+ * (OpenGL support have been removed, this surface type will never be set by cairo)
+ * @CAIRO_SURFACE_TYPE_DRM: The surface is of type Direct Render Manager, since 1.10, deprecated 1.18
+ * (DRM support have been removed, this surface type will never be set by cairo)
* @CAIRO_SURFACE_TYPE_TEE: The surface is of type 'tee' (a multiplexing surface), since 1.10
* @CAIRO_SURFACE_TYPE_XML: The surface is of type XML (for debugging), since 1.10
+ * @CAIRO_SURFACE_TYPE_SKIA: The surface is of type Skia, since 1.10, deprecated 1.18
+ * (Skia support have been removed, this surface type will never be set by cairo)
* @CAIRO_SURFACE_TYPE_SUBSURFACE: The surface is a subsurface created with
* cairo_surface_create_for_rectangle(), since 1.10
- * @CAIRO_SURFACE_TYPE_COGL: This surface is of type Cogl, since 1.12
+ * @CAIRO_SURFACE_TYPE_COGL: This surface is of type Cogl, since 1.12, deprecated 1.18
+ * (Cogl support have been removed, this surface type will never be set by cairo)
*
* #cairo_surface_type_t is used to describe the type of a given
* surface. The surface types are also known as "backends" or "surface
diff --git a/src/cairo.pc.in b/src/cairo.pc.in
deleted file mode 100644
index b361edf18..000000000
--- a/src/cairo.pc.in
+++ /dev/null
@@ -1,13 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: cairo
-Description: Multi-platform 2D graphics library
-Version: @VERSION@
-
-@PKGCONFIG_REQUIRES@: @CAIRO_REQUIRES@
-Libs: -L${libdir} -lcairo
-Libs.private: @CAIRO_NONPKGCONFIG_LIBS@
-Cflags: -I${includedir}/cairo
diff --git a/src/cairoint.h b/src/cairoint.h
index 987bf9a58..e5c281842 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -73,8 +73,7 @@
#if CAIRO_HAS_PDF_SURFACE || \
CAIRO_HAS_PS_SURFACE || \
- CAIRO_HAS_SCRIPT_SURFACE || \
- CAIRO_HAS_XML_SURFACE
+ CAIRO_HAS_SCRIPT_SURFACE
#define CAIRO_HAS_DEFLATE_STREAM 1
#endif
@@ -406,6 +405,10 @@ _cairo_hash_bytes (uintptr_t hash,
const void *bytes,
unsigned int length);
+cairo_private uintptr_t
+_cairo_hash_uintptr (uintptr_t hash,
+ uintptr_t u);
+
/* We use bits 24-27 to store phases for subpixel positions */
#define _cairo_scaled_glyph_index(g) ((unsigned long)((g)->hash_entry.hash & 0xffffff))
#define _cairo_scaled_glyph_xphase(g) (int)(((g)->hash_entry.hash >> 24) & 3)
@@ -893,6 +896,10 @@ cairo_private void
_cairo_font_options_init_copy (cairo_font_options_t *options,
const cairo_font_options_t *other);
+cairo_private cairo_bool_t
+_cairo_font_options_compare (const cairo_font_options_t *a,
+ const cairo_font_options_t *b);
+
cairo_private void
_cairo_font_options_fini (cairo_font_options_t *options);
@@ -943,6 +950,13 @@ _cairo_get_locale_decimal_point (void);
cairo_private double
_cairo_strtod (const char *nptr, char **endptr);
+#ifdef HAVE_STRNDUP
+#define _cairo_strndup strndup
+#else
+cairo_private char *
+_cairo_strndup (const char *s, size_t n);
+#endif
+
/* cairo-path-fixed.c */
cairo_private cairo_path_fixed_t *
_cairo_path_fixed_create (void);
@@ -1285,13 +1299,14 @@ _cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph,
cairo_private void
_cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
- cairo_surface_t *recording_surface);
+ cairo_surface_t *recording_surface,
+ const cairo_color_t *foreground_color);
cairo_private void
_cairo_scaled_glyph_set_color_surface (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font,
cairo_image_surface_t *surface,
- cairo_bool_t uses_foreground_color);
+ const cairo_color_t *foreground_color);
cairo_private cairo_int_status_t
_cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
@@ -1475,6 +1490,11 @@ _cairo_surface_tag (cairo_surface_t *surface,
const char *tag_name,
const char *attributes);
+cairo_private cairo_bool_t
+_cairo_surface_supports_color_glyph (cairo_surface_t *surface,
+ cairo_scaled_font_t *scaled_font,
+ unsigned long glyph_index);
+
cairo_private cairo_status_t
_cairo_surface_acquire_source_image (cairo_surface_t *surface,
cairo_image_surface_t **image_out,
@@ -1848,6 +1868,12 @@ _cairo_debug_print_matrix (FILE *file, const cairo_matrix_t *matrix);
cairo_private void
_cairo_debug_print_rect (FILE *file, const cairo_rectangle_int_t *rect);
+cairo_private const char *
+_cairo_debug_operator_to_string (cairo_operator_t op);
+
+cairo_private const char *
+_cairo_debug_status_to_string (cairo_int_status_t status);
+
cairo_private cairo_status_t
_cairo_bentley_ottmann_tessellate_rectilinear_polygon (cairo_traps_t *traps,
const cairo_polygon_t *polygon,
@@ -1939,17 +1965,26 @@ cairo_private cairo_status_t
_cairo_fopen (const char *filename, const char *mode, FILE **file_out);
/* Avoid unnecessary PLT entries. */
+slim_hidden_proto (cairo_append_path);
+slim_hidden_proto (cairo_arc);
+slim_hidden_proto (cairo_arc_negative);
+slim_hidden_proto (cairo_clip);
+slim_hidden_proto (cairo_clip_extents);
slim_hidden_proto (cairo_clip_preserve);
slim_hidden_proto (cairo_close_path);
+slim_hidden_proto (cairo_copy_path);
slim_hidden_proto (cairo_create);
slim_hidden_proto (cairo_curve_to);
slim_hidden_proto (cairo_destroy);
+slim_hidden_proto (cairo_device_to_user);
+slim_hidden_proto (cairo_fill);
slim_hidden_proto (cairo_fill_preserve);
slim_hidden_proto (cairo_font_face_destroy);
slim_hidden_proto (cairo_font_face_get_user_data);
slim_hidden_proto_no_warn (cairo_font_face_reference);
slim_hidden_proto (cairo_font_face_set_user_data);
slim_hidden_proto (cairo_font_options_equal);
+slim_hidden_proto (cairo_font_options_get_custom_palette_color);
slim_hidden_proto (cairo_font_options_hash);
slim_hidden_proto (cairo_font_options_merge);
slim_hidden_proto (cairo_font_options_set_antialias);
@@ -1959,14 +1994,17 @@ 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_hairline);
+slim_hidden_proto (cairo_get_line_width);
slim_hidden_proto (cairo_get_matrix);
slim_hidden_proto (cairo_get_scaled_font);
+slim_hidden_proto (cairo_get_source);
slim_hidden_proto (cairo_get_target);
slim_hidden_proto (cairo_get_tolerance);
slim_hidden_proto (cairo_glyph_allocate);
slim_hidden_proto (cairo_glyph_free);
+slim_hidden_proto (cairo_has_current_point);
+slim_hidden_proto (cairo_identity_matrix);
slim_hidden_proto (cairo_image_surface_create);
slim_hidden_proto (cairo_image_surface_create_for_data);
slim_hidden_proto (cairo_image_surface_get_data);
@@ -1983,35 +2021,73 @@ slim_hidden_proto (cairo_matrix_init_scale);
slim_hidden_proto (cairo_matrix_init_translate);
slim_hidden_proto (cairo_matrix_invert);
slim_hidden_proto (cairo_matrix_multiply);
+slim_hidden_proto (cairo_matrix_rotate);
slim_hidden_proto (cairo_matrix_scale);
slim_hidden_proto (cairo_matrix_transform_distance);
slim_hidden_proto (cairo_matrix_transform_point);
slim_hidden_proto (cairo_matrix_translate);
+slim_hidden_proto (cairo_mesh_pattern_begin_patch);
+slim_hidden_proto (cairo_mesh_pattern_curve_to);
+slim_hidden_proto (cairo_mesh_pattern_end_patch);
+slim_hidden_proto (cairo_mesh_pattern_get_control_point);
+slim_hidden_proto (cairo_mesh_pattern_get_corner_color_rgba);
+slim_hidden_proto (cairo_mesh_pattern_get_patch_count);
+slim_hidden_proto (cairo_mesh_pattern_get_path);
+slim_hidden_proto (cairo_mesh_pattern_line_to);
+slim_hidden_proto (cairo_mesh_pattern_move_to);
+slim_hidden_proto (cairo_mesh_pattern_set_corner_color_rgba);
slim_hidden_proto (cairo_move_to);
slim_hidden_proto (cairo_new_path);
slim_hidden_proto (cairo_paint);
+slim_hidden_proto (cairo_paint_with_alpha);
+slim_hidden_proto_no_warn (cairo_path_destroy);
slim_hidden_proto (cairo_pattern_add_color_stop_rgba);
slim_hidden_proto (cairo_pattern_create_for_surface);
+slim_hidden_proto (cairo_pattern_create_linear);
+slim_hidden_proto (cairo_pattern_create_mesh);
+slim_hidden_proto (cairo_pattern_create_radial);
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_mesh_pattern_curve_to);
-slim_hidden_proto (cairo_mesh_pattern_get_control_point);
-slim_hidden_proto (cairo_mesh_pattern_get_corner_color_rgba);
-slim_hidden_proto (cairo_mesh_pattern_get_patch_count);
-slim_hidden_proto (cairo_mesh_pattern_get_path);
-slim_hidden_proto (cairo_mesh_pattern_line_to);
-slim_hidden_proto (cairo_mesh_pattern_move_to);
-slim_hidden_proto (cairo_mesh_pattern_set_corner_color_rgba);
+slim_hidden_proto (cairo_pattern_get_rgba);
+slim_hidden_proto (cairo_pattern_get_type);
slim_hidden_proto_no_warn (cairo_pattern_reference);
+slim_hidden_proto (cairo_pattern_set_extend);
slim_hidden_proto (cairo_pattern_set_matrix);
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_no_warn (cairo_path_destroy);
slim_hidden_proto (cairo_recording_surface_create);
+slim_hidden_proto (cairo_recording_surface_ink_extents);
+slim_hidden_proto (cairo_rectangle);
+slim_hidden_proto (cairo_region_contains_point);
+slim_hidden_proto (cairo_region_contains_rectangle);
+slim_hidden_proto (cairo_region_copy);
+slim_hidden_proto (cairo_region_create);
+slim_hidden_proto (cairo_region_create_rectangle);
+slim_hidden_proto (cairo_region_create_rectangles);
+slim_hidden_proto (cairo_region_destroy);
+slim_hidden_proto (cairo_region_equal);
+slim_hidden_proto (cairo_region_get_extents);
+slim_hidden_proto (cairo_region_get_rectangle);
+slim_hidden_proto (cairo_region_intersect);
+slim_hidden_proto (cairo_region_intersect_rectangle);
+slim_hidden_proto (cairo_region_is_empty);
+slim_hidden_proto (cairo_region_num_rectangles);
+slim_hidden_proto (cairo_region_reference);
+slim_hidden_proto (cairo_region_status);
+slim_hidden_proto (cairo_region_subtract);
+slim_hidden_proto (cairo_region_subtract_rectangle);
+slim_hidden_proto (cairo_region_translate);
+slim_hidden_proto (cairo_region_union);
+slim_hidden_proto (cairo_region_union_rectangle);
+slim_hidden_proto (cairo_region_xor);
+slim_hidden_proto (cairo_region_xor_rectangle);
slim_hidden_proto (cairo_rel_line_to);
slim_hidden_proto (cairo_restore);
+slim_hidden_proto (cairo_rotate);
slim_hidden_proto (cairo_save);
slim_hidden_proto (cairo_scale);
slim_hidden_proto (cairo_scaled_font_create);
@@ -2021,23 +2097,27 @@ 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_get_user_data);
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_scaled_font_get_user_data);
slim_hidden_proto (cairo_scaled_font_set_user_data);
+slim_hidden_proto (cairo_scaled_font_status);
slim_hidden_proto (cairo_scaled_font_text_to_glyphs);
+slim_hidden_proto (cairo_set_dash);
+slim_hidden_proto (cairo_set_fill_rule);
slim_hidden_proto (cairo_set_font_matrix);
slim_hidden_proto (cairo_set_font_options);
slim_hidden_proto (cairo_set_font_size);
+slim_hidden_proto (cairo_set_hairline);
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_hairline);
slim_hidden_proto (cairo_set_matrix);
+slim_hidden_proto (cairo_set_miter_limit);
slim_hidden_proto (cairo_set_operator);
slim_hidden_proto (cairo_set_source);
slim_hidden_proto (cairo_set_source_rgb);
+slim_hidden_proto (cairo_set_source_rgba);
slim_hidden_proto (cairo_set_source_surface);
slim_hidden_proto (cairo_set_tolerance);
slim_hidden_proto (cairo_status);
@@ -2068,43 +2148,20 @@ slim_hidden_proto (cairo_text_cluster_free);
slim_hidden_proto (cairo_toy_font_face_create);
slim_hidden_proto (cairo_toy_font_face_get_slant);
slim_hidden_proto (cairo_toy_font_face_get_weight);
-slim_hidden_proto (cairo_translate);
slim_hidden_proto (cairo_transform);
+slim_hidden_proto (cairo_translate);
slim_hidden_proto (cairo_user_font_face_create);
slim_hidden_proto (cairo_user_font_face_set_init_func);
slim_hidden_proto (cairo_user_font_face_set_render_color_glyph_func);
slim_hidden_proto (cairo_user_font_face_set_render_glyph_func);
slim_hidden_proto (cairo_user_font_face_set_unicode_to_glyph_func);
-slim_hidden_proto (cairo_device_to_user);
slim_hidden_proto (cairo_user_to_device);
slim_hidden_proto (cairo_user_to_device_distance);
slim_hidden_proto (cairo_version_string);
-slim_hidden_proto (cairo_region_create);
-slim_hidden_proto (cairo_region_create_rectangle);
-slim_hidden_proto (cairo_region_create_rectangles);
-slim_hidden_proto (cairo_region_copy);
-slim_hidden_proto (cairo_region_reference);
-slim_hidden_proto (cairo_region_destroy);
-slim_hidden_proto (cairo_region_equal);
-slim_hidden_proto (cairo_region_status);
-slim_hidden_proto (cairo_region_get_extents);
-slim_hidden_proto (cairo_region_num_rectangles);
-slim_hidden_proto (cairo_region_get_rectangle);
-slim_hidden_proto (cairo_region_is_empty);
-slim_hidden_proto (cairo_region_contains_rectangle);
-slim_hidden_proto (cairo_region_contains_point);
-slim_hidden_proto (cairo_region_translate);
-slim_hidden_proto (cairo_region_subtract);
-slim_hidden_proto (cairo_region_subtract_rectangle);
-slim_hidden_proto (cairo_region_intersect);
-slim_hidden_proto (cairo_region_intersect_rectangle);
-slim_hidden_proto (cairo_region_union);
-slim_hidden_proto (cairo_region_union_rectangle);
-slim_hidden_proto (cairo_region_xor);
-slim_hidden_proto (cairo_region_xor_rectangle);
#if CAIRO_HAS_PNG_FUNCTIONS
+slim_hidden_proto (cairo_image_surface_create_from_png_stream);
slim_hidden_proto (cairo_surface_write_to_png_stream);
#endif
diff --git a/src/check-def.sh b/src/check-def.sh
deleted file mode 100755
index beefb46a3..000000000
--- a/src/check-def.sh
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/bin/sh
-
-LC_ALL=C
-export LC_ALL
-
-if which nm 2>/dev/null >/dev/null; then
- :
-else
- echo "'nm' not found; skipping test"
- exit 0
-fi
-
-test -z "$srcdir" && srcdir=.
-test -z "$MAKE" && MAKE=make
-stat=0
-
-$MAKE check-has-hidden-symbols.i > /dev/null || exit 1
-if tail -1 check-has-hidden-symbols.i | grep CAIRO_HAS_HIDDEN_SYMBOLS >/dev/null; then
- echo "Compiler doesn't support symbol visibility; skipping test"
- exit 0
-fi
-
-if [ "`uname -s`" = "Linux" ]; then
- get_cairo_syms='( objdump -t "$so" | grep "^[^ ]* [^l.*]*[.]"; objdump -t "$so" | grep "[.]hidden.*\\<cairo"; ) | sed "s/.* //"'
-else
- get_cairo_syms='nm "$so" | grep " [BCDGINRSTVW] " | cut -d" " -f3'
-fi
-
-defs="cairo.def"
-$MAKE $defs > /dev/null
-for def in $defs; do
- lib=`echo "$def" | sed 's/[.]def$//'`
- lib=`echo "$lib" | sed 's@.*/@@'`
- so=.libs/lib${lib}.so
-
- test -f "$so" || continue
-
- echo Checking that $so has the same symbol list as $def
-
- {
- echo EXPORTS
- eval $get_cairo_syms | c++filt --no-params | grep -v '^_cairo_test_\|^_fini\|^_init\|^_save[fg]pr\|^_rest[fg]pr\|^_Z\|^__gnu\|^__bss\|^_edata\|^_end' | sort -u
- # cheat: copy the last line from the def file!
- tail -n1 "$def"
- } | diff "$def" - >&2 || stat=1
-done
-
-exit $stat
diff --git a/src/make-cairo-def.sh b/src/make-cairo-def.sh
new file mode 100644
index 000000000..1a1f366e8
--- /dev/null
+++ b/src/make-cairo-def.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+LC_ALL=C
+export LC_ALL
+
+if [ $# -lt 3 ];
+then
+ echo "Generate cairo def file"
+ echo "Usage: $0 <def-filename> <cairo-features-file> <cairo-headers>..."
+ exit 1
+fi
+
+def_file="$1"
+cairo_features_h="$2"
+shift 2
+
+#echo Generating $def_file
+
+(echo EXPORTS; \
+ (cat $* || echo 'cairo_ERROR ()' ) | \
+ egrep -v '^# *include' | \
+ ( cat "$cairo_features_h" - | egrep -v '^#pragma' | cpp -D__cplusplus - || echo 'cairo_ERROR ()' ) | \
+ egrep '^cairo_.* \(' | \
+ sed -e 's/[ ].*//' | \
+ sort; \
+ ) > "$def_file"
+grep -q -v cairo_ERROR "$def_file" || (rm "$def_file"; false)
diff --git a/src/meson-check-def.sh b/src/meson-check-def.sh
new file mode 100644
index 000000000..550cf337f
--- /dev/null
+++ b/src/meson-check-def.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+LC_ALL=C
+export LC_ALL
+
+if [ $# -lt 2 ];
+then
+ echo "Check that cairo library has same exported symbols as cairo.def"
+ echo "Usage: $0 <def-filename> <cairo-library>"
+ exit 1
+fi
+
+def="$1"
+so="$2"
+
+if which nm 2>/dev/null >/dev/null; then
+ :
+else
+ echo "'nm' not found; skipping test"
+ exit 0
+fi
+
+stat=0
+
+if [ "`uname -s`" = "Linux" ]; then
+ get_cairo_syms='( objdump -t "$so" | grep "^[^ ]* [^l.*]*[.]"; objdump -t "$so" | grep "[.]hidden.*\\<cairo"; ) | sed "s/.* //"'
+else
+ get_cairo_syms='nm "$so" | grep " [BCDGINRSTVW] " | cut -d" " -f3'
+fi
+
+echo Checking that $so has the same symbol list as $def
+
+{
+ echo EXPORTS
+ eval $get_cairo_syms | c++filt --no-params | grep -v '^_cairo_test_\|^_fini\|^_init\|^_save[fg]pr\|^_rest[fg]pr\|^_Z\|^__gnu\|^__bss\|^_edata\|^_end' | sort -u
+} | diff "$def" - >&2 || stat=1
+
+exit $stat
diff --git a/src/meson.build b/src/meson.build
index 3d50edd54..f777fcd1c 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -130,6 +130,8 @@ cairo_feature_sources = {
],
'cairo-ft': [
'cairo-ft-font.c',
+ 'cairo-colr-glyph-render.c',
+ 'cairo-svg-glyph-render.c'
],
'cairo-xlib': [
@@ -177,25 +179,9 @@ cairo_feature_sources = {
'cairo-win32-font': [
'win32/cairo-win32-font.c',
],
- 'cairo-win32-dwrite-font': [
- 'win32/cairo-dwrite-font-public.c',
+ 'cairo-dwrite-font': [
'win32/cairo-dwrite-font.cpp',
],
- 'cairo-gl': [
- 'cairo-gl-composite.c',
- 'cairo-gl-device.c',
- 'cairo-gl-dispatch.c',
- 'cairo-gl-glyphs.c',
- 'cairo-gl-gradient.c',
- 'cairo-gl-info.c',
- 'cairo-gl-msaa-compositor.c',
- 'cairo-gl-operand.c',
- 'cairo-gl-shaders.c',
- 'cairo-gl-source.c',
- 'cairo-gl-spans-compositor.c',
- 'cairo-gl-surface.c',
- 'cairo-gl-traps-compositor.c',
- ],
'cairo-script': [
'cairo-script-surface.c',
],
@@ -209,18 +195,6 @@ cairo_feature_sources = {
'cairo-svg': [
'cairo-svg-surface.c',
],
- 'cairo-egl': [
- 'cairo-egl-context.c',
- ],
- 'cairo-glx': [
- 'cairo-glx-context.c',
- ],
- 'cairo-wgl': [
- 'cairo-wgl-context.c',
- ],
- 'cairo-xml': [
- 'cairo-xml-surface.c',
- ],
'cairo-tee': [
'cairo-tee-surface.c',
],
@@ -237,10 +211,10 @@ cairo_feature_headers = {
'cairo-quartz': ['cairo-quartz.h'],
'cairo-quartz-image': ['cairo-quartz-image.h'],
'cairo-win32': ['cairo-win32.h'],
+ 'cairo-dwrite-font': ['cairo-dwrite.h'],
'cairo-gl': ['cairo-gl.h'],
'cairo-script': ['cairo-script.h'],
'cairo-tee': ['cairo-tee.h'],
- 'cairo-xml': ['cairo-xml.h'],
'cairo-vg': ['cairo-vg.h'],
}
@@ -260,6 +234,12 @@ endforeach
incsrc = include_directories('.')
+cairo_static_args = []
+if get_option('default_library') == 'static' and host_machine.system() == 'windows'
+ cairo_static_args += ['-DCAIRO_WIN32_STATIC_BUILD']
+ add_project_arguments('-DCAIRO_WIN32_STATIC_BUILD', language: 'c')
+endif
+
libcairo = library('cairo', cairo_sources,
dependencies: deps,
c_args: cairo_no_warn_c_args + pthread_c_args,
@@ -271,12 +251,8 @@ libcairo = library('cairo', cairo_sources,
include_directories: incbase,
)
-cairo_headers += [configure_file(output: 'cairo-features.h', configuration: feature_conf)]
-
-cairo_static_args = []
-if get_option('default_library') == 'static' and host_machine.system() == 'windows'
- cairo_static_args += ['-DCAIRO_WIN32_STATIC_BUILD']
-endif
+cairo_features_file = configure_file(output: 'cairo-features.h', configuration: feature_conf)
+cairo_headers += [cairo_features_file]
libcairo_dep = declare_dependency(link_with: libcairo,
dependencies: deps,
@@ -296,9 +272,6 @@ install_headers(cairo_headers, subdir: 'cairo')
shell = find_program('sh', required: false)
if shell.found()
test_scripts = [
- # This script calls back into make to generate cairo.def
- # TODO: Make this work, somehow
- #'check-def.sh',
'check-doc-syntax.sh',
'check-headers.sh',
'check-preprocessor-syntax.sh',
@@ -314,6 +287,21 @@ if shell.found()
env = environment()
env.set('CAIRO_HAS_HIDDEN_SYMBOLS', '1')
+ cairo_def = custom_target('make-cairo-def',
+ input : cairo_headers,
+ output : 'cairo.def',
+ command : [ shell,
+ meson.current_source_dir()/'make-cairo-def.sh',
+ '@OUTPUT@',
+ cairo_features_file,
+ '@INPUT@'
+ ])
+
+ test('check-def', shell,
+ args: ['meson-check-def.sh', cairo_def, libcairo ],
+ env: env,
+ workdir: meson.current_source_dir())
+
test('check-plt.sh', shell,
args: ['check-plt.sh', libcairo ],
env: env,
diff --git a/src/win32/cairo-dwrite-font-public.c b/src/win32/cairo-dwrite-font-public.c
deleted file mode 100644
index 09eddd51d..000000000
--- a/src/win32/cairo-dwrite-font-public.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
-/* Cairo - a vector graphics library with display and print output
- *
- * Copyright © 2022 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>
- */
-
-
-/* gtkdoc won't scan .cpp files so we wrap the public API in cairo-dwrite-font.cpp
- * with this .c wrapper containing the gtkdocs for cairo-dwrite-font.cpp.
- */
-
-#include "cairoint.h"
-#include "cairo-win32-private.h"
-
-/**
- * SECTION:cairo-dwrite-fonts
- * @Title: DWrite Fonts
- * @Short_Description: Font support for Microsoft DirectWrite
- * @See_Also: #cairo_font_face_t
- *
- * The Microsoft DirectWrite font backend is primarily used to render text on
- * Microsoft Windows systems.
- **/
-
-/**
- * CAIRO_HAS_DWRITE_FONT:
- *
- * Defined if the Microsoft DWrite font backend is available.
- * This macro can be used to conditionally compile backend-specific code.
- *
- * Since: 1.18
- **/
-
-/**
- * cairo_dwrite_font_face_create_for_dwrite_fontface:
- * @dwrite_font_face: A pointer to an #IDWriteFontFace specifying the
- * DWrite font to use.
- *
- * Creates a new font for the DWrite font backend based on a
- * DWrite font face. This font can then be used with
- * cairo_set_font_face() or cairo_scaled_font_create().
-
- * Here is an example of how this function might be used:
- * <informalexample><programlisting><![CDATA[
- * #include <cairo-win32.h>
- * #include <dwrite.h>
- *
- * IDWriteFactory* dWriteFactory = NULL;
- * HRESULT hr = DWriteCreateFactory(
- * DWRITE_FACTORY_TYPE_SHARED,
- * __uuidof(IDWriteFactory),
- * reinterpret_cast<IUnknown**>(&dWriteFactory));
- *
- * IDWriteFontCollection *systemCollection;
- * hr = dWriteFactory->GetSystemFontCollection(&systemCollection);
- *
- * UINT32 idx;
- * BOOL found;
- * systemCollection->FindFamilyName(L"Segoe UI Emoji", &idx, &found);
- *
- * IDWriteFontFamily *family;
- * systemCollection->GetFontFamily(idx, &family);
- *
- * IDWriteFont *dwritefont;
- * DWRITE_FONT_WEIGHT weight = DWRITE_FONT_WEIGHT_NORMAL;
- * DWRITE_FONT_STYLE style = DWRITE_FONT_STYLE_NORMAL;
- * hr = family->GetFirstMatchingFont(weight, DWRITE_FONT_STRETCH_NORMAL, style, &dwritefont);
- *
- * IDWriteFontFace *dwriteface;
- * hr = dwritefont->CreateFontFace(&dwriteface);
- *
- * cairo_font_face_t *face;
- * face = cairo_dwrite_font_face_create_for_dwrite_fontface(dwriteface);
- * cairo_set_font_face(cr, face);
- * cairo_set_font_size(cr, 70);
- * cairo_move_to(cr, 100, 100);
- * cairo_show_text(cr, "😃");
- * ]]></programlisting></informalexample>
- *
- * Note: When printing a DWrite font to a
- * #CAIRO_SURFACE_TYPE_WIN32_PRINTING surface, the printing surface
- * will substitute each DWrite font with a Win32 font created from the same
- * underlying font file. If the matching font file can not be found,
- * the #CAIRO_SURFACE_TYPE_WIN32_PRINTING surface will convert each
- * glyph to a filled path. If a DWrite font was not created from a system
- * font, it is recommended that the font used to create the DWrite
- * font be made available to GDI to avoid the undesirable fallback
- * to emitting paths. This can be achieved using the GDI font loading functions
- * such as AddFontMemResourceEx().
- *
- * Return value: a newly created #cairo_font_face_t. Free with
- * cairo_font_face_destroy() when you are done using it.
- *
- * Since: 1.18
- **/
-cairo_font_face_t*
-cairo_dwrite_font_face_create_for_dwrite_fontface (void *dwrite_font_face)
-{
- return cairo_dwrite_font_face_create_for_dwrite_fontface_internal (dwrite_font_face);
-}
diff --git a/src/win32/cairo-dwrite-font.cpp b/src/win32/cairo-dwrite-font.cpp
index c58827555..cf516d41c 100644
--- a/src/win32/cairo-dwrite-font.cpp
+++ b/src/win32/cairo-dwrite-font.cpp
@@ -45,10 +45,31 @@
#include "cairo-dwrite-private.hpp"
#include "cairo-truetype-subset-private.h"
#include "cairo-scaled-font-subsets-private.h"
+#include "cairo-dwrite.h"
+
#include <float.h>
#include <wincodec.h>
+/**
+ * SECTION:cairo-dwrite-fonts
+ * @Title: DWrite Fonts
+ * @Short_Description: Font support for Microsoft DirectWrite
+ * @See_Also: #cairo_font_face_t
+ *
+ * The Microsoft DirectWrite font backend is primarily used to render text on
+ * Microsoft Windows systems.
+ **/
+
+/**
+ * CAIRO_HAS_DWRITE_FONT:
+ *
+ * Defined if the Microsoft DWrite font backend is available.
+ * This macro can be used to conditionally compile backend-specific code.
+ *
+ * Since: 1.18
+ **/
+
typedef HRESULT (WINAPI*D2D1CreateFactoryFunc)(
D2D1_FACTORY_TYPE factoryType,
REFIID iid,
@@ -191,22 +212,119 @@ private:
RefPtr<IDWriteFactory> DWriteFactory::mFactoryInstance;
+RefPtr<IDWriteFactory1> DWriteFactory::mFactoryInstance1;
+RefPtr<IDWriteFactory2> DWriteFactory::mFactoryInstance2;
+RefPtr<IDWriteFactory3> DWriteFactory::mFactoryInstance3;
RefPtr<IDWriteFactory4> DWriteFactory::mFactoryInstance4;
RefPtr<IWICImagingFactory> WICImagingFactory::mFactoryInstance;
RefPtr<IDWriteFontCollection> DWriteFactory::mSystemCollection;
RefPtr<IDWriteRenderingParams> DWriteFactory::mDefaultRenderingParams;
-RefPtr<IDWriteRenderingParams> DWriteFactory::mCustomClearTypeRenderingParams;
-RefPtr<IDWriteRenderingParams> DWriteFactory::mForceGDIClassicRenderingParams;
-FLOAT DWriteFactory::mGamma = -1.0;
-FLOAT DWriteFactory::mEnhancedContrast = -1.0;
-FLOAT DWriteFactory::mClearTypeLevel = -1.0;
-int DWriteFactory::mPixelGeometry = -1;
-int DWriteFactory::mRenderingMode = -1;
RefPtr<ID2D1Factory> D2DFactory::mFactoryInstance;
RefPtr<ID2D1DCRenderTarget> D2DFactory::mRenderTarget;
+static int
+_quality_from_antialias_mode(cairo_antialias_t antialias)
+{
+ switch (antialias) {
+ case CAIRO_ANTIALIAS_NONE:
+ return NONANTIALIASED_QUALITY;
+ case CAIRO_ANTIALIAS_FAST:
+ case CAIRO_ANTIALIAS_GRAY:
+ return ANTIALIASED_QUALITY;
+ default:
+ break;
+ }
+ return CLEARTYPE_QUALITY;
+}
+
+static RefPtr<IDWriteRenderingParams>
+_create_rendering_params(IDWriteRenderingParams *params,
+ const cairo_font_options_t *options,
+ cairo_antialias_t antialias)
+{
+ if (!params)
+ params = DWriteFactory::DefaultRenderingParams();
+ FLOAT gamma = params->GetGamma();
+ FLOAT enhanced_contrast = params->GetEnhancedContrast();
+ FLOAT clear_type_level = params->GetClearTypeLevel();
+ DWRITE_PIXEL_GEOMETRY pixel_geometry = params->GetPixelGeometry();
+ DWRITE_RENDERING_MODE rendering_mode = params->GetRenderingMode();
+
+ cairo_bool_t modified = FALSE;
+ switch (antialias) {
+ case CAIRO_ANTIALIAS_NONE:
+ if (rendering_mode != DWRITE_RENDERING_MODE_ALIASED) {
+ rendering_mode = DWRITE_RENDERING_MODE_ALIASED;
+ modified = TRUE;
+ }
+ break;
+ case CAIRO_ANTIALIAS_FAST:
+ case CAIRO_ANTIALIAS_GRAY:
+ if (clear_type_level) {
+ clear_type_level = 0;
+ modified = TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ auto subpixel_order = cairo_font_options_get_subpixel_order (options);
+ switch (subpixel_order) {
+ case CAIRO_SUBPIXEL_ORDER_RGB:
+ if (pixel_geometry != DWRITE_PIXEL_GEOMETRY_RGB) {
+ pixel_geometry = DWRITE_PIXEL_GEOMETRY_RGB;
+ modified = TRUE;
+ }
+ break;
+ case CAIRO_SUBPIXEL_ORDER_BGR:
+ if (pixel_geometry != DWRITE_PIXEL_GEOMETRY_BGR) {
+ pixel_geometry = DWRITE_PIXEL_GEOMETRY_BGR;
+ modified = TRUE;
+ }
+ break;
+ default:
+ break;
+ }
+ if (!modified)
+ return params;
+
+ HRESULT hr;
+ RefPtr<IDWriteRenderingParams1> params1;
+ hr = params->QueryInterface(&params1);
+ if (FAILED(hr)) {
+ RefPtr<IDWriteRenderingParams> ret;
+ DWriteFactory::Instance()->CreateCustomRenderingParams(gamma, enhanced_contrast, clear_type_level, pixel_geometry, rendering_mode, &ret);
+ return ret;
+ }
+
+ FLOAT grayscaleEnhancedContrast = params1->GetGrayscaleEnhancedContrast();
+ RefPtr<IDWriteRenderingParams2> params2;
+ hr = params->QueryInterface(&params2);
+ if (FAILED(hr)) {
+ RefPtr<IDWriteRenderingParams1> ret;
+ DWriteFactory::Instance1()->CreateCustomRenderingParams(gamma, enhanced_contrast, grayscaleEnhancedContrast, clear_type_level, pixel_geometry, rendering_mode, &ret);
+ return ret;
+ }
+
+ DWRITE_GRID_FIT_MODE gridFitMode = params2->GetGridFitMode();
+ RefPtr<IDWriteRenderingParams3> params3;
+ hr = params->QueryInterface(&params3);
+ if (FAILED(hr)) {
+ RefPtr<IDWriteRenderingParams2> ret;
+ DWriteFactory::Instance2()->CreateCustomRenderingParams(gamma, enhanced_contrast, grayscaleEnhancedContrast, clear_type_level, pixel_geometry, rendering_mode, gridFitMode, &ret);
+ return ret;
+ }
+
+ DWRITE_RENDERING_MODE1 rendering_mode1 = params3->GetRenderingMode1();
+ if (antialias == CAIRO_ANTIALIAS_NONE)
+ rendering_mode1 = DWRITE_RENDERING_MODE1_ALIASED;
+ RefPtr<IDWriteRenderingParams3> ret;
+ DWriteFactory::Instance3()->CreateCustomRenderingParams(gamma, enhanced_contrast, grayscaleEnhancedContrast, clear_type_level, pixel_geometry, rendering_mode1, gridFitMode, &ret);
+ return ret;
+}
+
/* Functions #cairo_font_face_backend_t */
static cairo_status_t
_cairo_dwrite_font_face_create_for_toy (cairo_toy_font_face_t *toy_face,
@@ -330,7 +448,7 @@ _cairo_dwrite_font_face_create_for_toy (cairo_toy_font_face_t *toy_face,
MultiByteToWideChar(CP_UTF8, 0, toy_face->family, -1, face_name, face_name_len);
RefPtr<IDWriteFontFamily> family = DWriteFactory::FindSystemFontFamily(face_name);
- delete face_name;
+ delete[] face_name;
if (!family) {
/* If the family is not found, use the default that should always exist. */
face_name_len = MultiByteToWideChar(CP_UTF8, 0, CAIRO_FONT_FAMILY_DEFAULT, -1, NULL, 0);
@@ -338,7 +456,7 @@ _cairo_dwrite_font_face_create_for_toy (cairo_toy_font_face_t *toy_face,
MultiByteToWideChar(CP_UTF8, 0, CAIRO_FONT_FAMILY_DEFAULT, -1, face_name, face_name_len);
family = DWriteFactory::FindSystemFontFamily(face_name);
- delete face_name;
+ delete[] face_name;
if (!family) {
*font_face = (cairo_font_face_t*)&_cairo_font_face_nil;
return (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED;
@@ -390,6 +508,8 @@ _cairo_dwrite_font_face_destroy (void *font_face)
cairo_dwrite_font_face_t *dwrite_font_face = static_cast<cairo_dwrite_font_face_t*>(font_face);
if (dwrite_font_face->dwriteface)
dwrite_font_face->dwriteface->Release();
+ if (dwrite_font_face->rendering_params)
+ dwrite_font_face->rendering_params->Release();
return TRUE;
}
@@ -536,10 +656,21 @@ _cairo_dwrite_font_face_scaled_font_create (void *abstract_face,
return status;
}
+ dwrite_font->mat = dwrite_font->base.ctm;
+ cairo_matrix_multiply(&dwrite_font->mat, &dwrite_font->mat, font_matrix);
+ dwrite_font->mat_inverse = dwrite_font->mat;
+ cairo_matrix_invert (&dwrite_font->mat_inverse);
+
cairo_font_extents_t extents;
DWRITE_FONT_METRICS metrics;
- font_face->dwriteface->GetMetrics(&metrics);
+ if (dwrite_font->measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC ||
+ dwrite_font->measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL) {
+ DWRITE_MATRIX transform = _cairo_dwrite_matrix_from_matrix (&dwrite_font->mat);
+ font_face->dwriteface->GetGdiCompatibleMetrics(1, 1, &transform, &metrics);
+ } else {
+ font_face->dwriteface->GetMetrics(&metrics);
+ }
extents.ascent = (FLOAT)metrics.ascent / metrics.designUnitsPerEm;
extents.descent = (FLOAT)metrics.descent / metrics.designUnitsPerEm;
@@ -547,15 +678,8 @@ _cairo_dwrite_font_face_scaled_font_create (void *abstract_face,
extents.max_x_advance = 14.0;
extents.max_y_advance = 0.0;
- dwrite_font->mat = dwrite_font->base.ctm;
- cairo_matrix_multiply(&dwrite_font->mat, &dwrite_font->mat, font_matrix);
- dwrite_font->mat_inverse = dwrite_font->mat;
- cairo_matrix_invert (&dwrite_font->mat_inverse);
-
cairo_antialias_t default_quality = CAIRO_ANTIALIAS_SUBPIXEL;
- dwrite_font->measuring_mode = DWRITE_MEASURING_MODE_NATURAL;
-
// The following code detects the system quality at scaled_font creation time,
// this means that if cleartype settings are changed but the scaled_fonts
// are re-used, they might not adhere to the new system setting until re-
@@ -566,12 +690,10 @@ _cairo_dwrite_font_face_scaled_font_create (void *abstract_face,
break;
case ANTIALIASED_QUALITY:
default_quality = CAIRO_ANTIALIAS_GRAY;
- dwrite_font->measuring_mode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
break;
case DEFAULT_QUALITY:
// _get_system_quality() seems to think aliased is default!
default_quality = CAIRO_ANTIALIAS_NONE;
- dwrite_font->measuring_mode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
break;
}
@@ -587,9 +709,8 @@ _cairo_dwrite_font_face_scaled_font_create (void *abstract_face,
dwrite_font->antialias_mode = options->antialias;
}
- dwrite_font->rendering_mode =
- default_quality == CAIRO_ANTIALIAS_SUBPIXEL ?
- cairo_dwrite_scaled_font_t::TEXT_RENDERING_NORMAL : cairo_dwrite_scaled_font_t::TEXT_RENDERING_NO_CLEARTYPE;
+ dwrite_font->rendering_params = _create_rendering_params(font_face->rendering_params, options, dwrite_font->antialias_mode).forget().drop();
+ dwrite_font->measuring_mode = font_face->measuring_mode;
return _cairo_scaled_font_set_metrics (*font, &extents);
}
@@ -598,6 +719,9 @@ _cairo_dwrite_font_face_scaled_font_create (void *abstract_face,
static void
_cairo_dwrite_scaled_font_fini(void *scaled_font)
{
+ cairo_dwrite_scaled_font_t *dwrite_font = static_cast<cairo_dwrite_scaled_font_t*>(scaled_font);
+ if (dwrite_font->rendering_params)
+ dwrite_font->rendering_params->Release();
}
static cairo_int_status_t
@@ -659,17 +783,30 @@ _cairo_dwrite_scaled_font_init_glyph_metrics(cairo_dwrite_scaled_font_t *scaled_
DWRITE_GLYPH_METRICS metrics;
DWRITE_FONT_METRICS fontMetrics;
- font_face->dwriteface->GetMetrics(&fontMetrics);
- HRESULT hr = font_face->dwriteface->GetDesignGlyphMetrics(&charIndex, 1, &metrics);
+ HRESULT hr;
+ if (font_face->measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC ||
+ font_face->measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL) {
+ DWRITE_MATRIX transform = _cairo_dwrite_matrix_from_matrix (&scaled_font->mat);
+ font_face->dwriteface->GetGdiCompatibleMetrics(1, 1, &transform, &fontMetrics);
+ BOOL natural = font_face->measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL;
+ hr = font_face->dwriteface->GetGdiCompatibleGlyphMetrics (1, 1, &transform, natural, &charIndex, 1, &metrics, FALSE);
+ } else {
+ font_face->dwriteface->GetMetrics(&fontMetrics);
+ hr = font_face->dwriteface->GetDesignGlyphMetrics(&charIndex, 1, &metrics);
+ }
if (FAILED(hr)) {
return CAIRO_INT_STATUS_UNSUPPORTED;
}
+ // GetGdiCompatibleMetrics may return a glyph metrics that yields a small nagative glyph height.
+ INT32 glyph_width = metrics.advanceWidth - metrics.leftSideBearing - metrics.rightSideBearing;
+ INT32 glyph_height = metrics.advanceHeight - metrics.topSideBearing - metrics.bottomSideBearing;
+ glyph_width = MAX(glyph_width, 0);
+ glyph_height = MAX(glyph_height, 0);
+
// TODO: Treat swap_xy.
- extents.width = (FLOAT)(metrics.advanceWidth - metrics.leftSideBearing - metrics.rightSideBearing) /
- fontMetrics.designUnitsPerEm;
- extents.height = (FLOAT)(metrics.advanceHeight - metrics.topSideBearing - metrics.bottomSideBearing) /
- fontMetrics.designUnitsPerEm;
+ extents.width = (FLOAT)glyph_width / fontMetrics.designUnitsPerEm;
+ extents.height = (FLOAT)glyph_height / fontMetrics.designUnitsPerEm;
extents.x_advance = (FLOAT)metrics.advanceWidth / fontMetrics.designUnitsPerEm;
extents.x_bearing = (FLOAT)metrics.leftSideBearing / fontMetrics.designUnitsPerEm;
extents.y_advance = 0.0;
@@ -679,10 +816,15 @@ _cairo_dwrite_scaled_font_init_glyph_metrics(cairo_dwrite_scaled_font_t *scaled_
// We pad the extents here because GetDesignGlyphMetrics returns "ideal" metrics
// for the glyph outline, without accounting for hinting/gridfitting/antialiasing,
// and therefore it does not always cover all pixels that will actually be touched.
- if (scaled_font->base.options.antialias != CAIRO_ANTIALIAS_NONE &&
- extents.width > 0 && extents.height > 0) {
- extents.width += scaled_font->mat_inverse.xx * 2;
- extents.x_bearing -= scaled_font->mat_inverse.xx;
+ if (extents.width > 0 && extents.height > 0) {
+ double x = 1, y = 1;
+ cairo_matrix_transform_distance (&scaled_font->mat_inverse, &x, &y);
+ x = fabs(x);
+ y = fabs(y);
+ extents.width += x * 2;
+ extents.x_bearing -= x;
+ extents.height += y * 2;
+ extents.y_bearing -= y;
}
_cairo_scaled_glyph_set_metrics (scaled_glyph,
@@ -699,8 +841,9 @@ _cairo_dwrite_scaled_font_init_glyph_metrics(cairo_dwrite_scaled_font_t *scaled_
class GeometryRecorder : public IDWriteGeometrySink
{
public:
- GeometryRecorder(cairo_path_fixed_t *aCairoPath)
- : mCairoPath(aCairoPath) {}
+ GeometryRecorder(cairo_path_fixed_t *aCairoPath, const cairo_matrix_t &matrix)
+ : mCairoPath(aCairoPath)
+ , mMatrix(matrix) {}
// IUnknown interface
IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject)
@@ -738,28 +881,18 @@ public:
return;
}
- cairo_fixed_t GetFixedX(const D2D1_POINT_2F &point)
- {
- unsigned int control_word;
- _controlfp_s(&control_word, _CW_DEFAULT, MCW_PC);
- return _cairo_fixed_from_double(point.x);
- }
-
- cairo_fixed_t GetFixedY(const D2D1_POINT_2F &point)
- {
- unsigned int control_word;
- _controlfp_s(&control_word, _CW_DEFAULT, MCW_PC);
- return _cairo_fixed_from_double(point.y);
- }
-
IFACEMETHODIMP_(void) BeginFigure(
D2D1_POINT_2F startPoint,
D2D1_FIGURE_BEGIN figureBegin)
{
- mStartPoint = startPoint;
+ double x = startPoint.x;
+ double y = startPoint.y;
+ cairo_matrix_transform_point(&mMatrix, &x, &y);
+ mStartPointX = _cairo_fixed_from_double(x);
+ mStartPointY = _cairo_fixed_from_double(y);
cairo_status_t status = _cairo_path_fixed_move_to(mCairoPath,
- GetFixedX(startPoint),
- GetFixedY(startPoint));
+ mStartPointX,
+ mStartPointY);
(void)status; /* squelch warning */
}
@@ -768,8 +901,8 @@ public:
{
if (figureEnd == D2D1_FIGURE_END_CLOSED) {
cairo_status_t status = _cairo_path_fixed_line_to(mCairoPath,
- GetFixedX(mStartPoint),
- GetFixedY(mStartPoint));
+ mStartPointX,
+ mStartPointY);
(void)status; /* squelch warning */
}
}
@@ -779,13 +912,22 @@ public:
UINT beziersCount)
{
for (unsigned int i = 0; i < beziersCount; i++) {
+ double x1 = beziers[i].point1.x;
+ double y1 = beziers[i].point1.y;
+ double x2 = beziers[i].point2.x;
+ double y2 = beziers[i].point2.y;
+ double x3 = beziers[i].point3.x;
+ double y3 = beziers[i].point3.y;
+ cairo_matrix_transform_point(&mMatrix, &x1, &y1);
+ cairo_matrix_transform_point(&mMatrix, &x2, &y2);
+ cairo_matrix_transform_point(&mMatrix, &x3, &y3);
cairo_status_t status = _cairo_path_fixed_curve_to(mCairoPath,
- GetFixedX(beziers[i].point1),
- GetFixedY(beziers[i].point1),
- GetFixedX(beziers[i].point2),
- GetFixedY(beziers[i].point2),
- GetFixedX(beziers[i].point3),
- GetFixedY(beziers[i].point3));
+ _cairo_fixed_from_double(x1),
+ _cairo_fixed_from_double(y1),
+ _cairo_fixed_from_double(x2),
+ _cairo_fixed_from_double(y2),
+ _cairo_fixed_from_double(x3),
+ _cairo_fixed_from_double(y3));
(void)status; /* squelch warning */
}
}
@@ -795,16 +937,21 @@ public:
UINT pointsCount)
{
for (unsigned int i = 0; i < pointsCount; i++) {
+ double x = points[i].x;
+ double y = points[i].y;
+ cairo_matrix_transform_point(&mMatrix, &x, &y);
cairo_status_t status = _cairo_path_fixed_line_to(mCairoPath,
- GetFixedX(points[i]),
- GetFixedY(points[i]));
+ _cairo_fixed_from_double(x),
+ _cairo_fixed_from_double(y));
(void)status; /* squelch warning */
}
}
private:
cairo_path_fixed_t *mCairoPath;
- D2D1_POINT_2F mStartPoint;
+ const cairo_matrix_t &mMatrix;
+ cairo_fixed_t mStartPointX;
+ cairo_fixed_t mStartPointY;
};
static cairo_int_status_t
@@ -814,7 +961,7 @@ _cairo_dwrite_scaled_font_init_glyph_path(cairo_dwrite_scaled_font_t *scaled_fon
cairo_int_status_t status;
cairo_path_fixed_t *path;
path = _cairo_path_fixed_create();
- GeometryRecorder recorder(path);
+ GeometryRecorder recorder(path, scaled_font->base.scale);
DWRITE_GLYPH_OFFSET offset;
offset.advanceOffset = 0;
@@ -823,12 +970,7 @@ _cairo_dwrite_scaled_font_init_glyph_path(cairo_dwrite_scaled_font_t *scaled_fon
FLOAT advance = 0.0;
cairo_dwrite_font_face_t *dwriteff = (cairo_dwrite_font_face_t*)scaled_font->base.font_face;
- /* GetGlyphRunOutline seems to ignore hinting so just use the em size to get the outline
- * to avoid rounding errors when converting to cairo_path_fixed_t.
- */
- DWRITE_FONT_METRICS metrics;
- dwriteff->dwriteface->GetMetrics(&metrics);
- HRESULT hr = dwriteff->dwriteface->GetGlyphRunOutline(metrics.designUnitsPerEm,
+ HRESULT hr = dwriteff->dwriteface->GetGlyphRunOutline(1,
&glyphId,
&advance,
&offset,
@@ -841,12 +983,6 @@ _cairo_dwrite_scaled_font_init_glyph_path(cairo_dwrite_scaled_font_t *scaled_fon
status = (cairo_int_status_t)_cairo_path_fixed_close_path(path);
- /* Now scale the em size down to 1.0 and apply the font matrix and font ctm. */
- cairo_matrix_t mat = scaled_font->base.ctm;
- cairo_matrix_multiply(&mat, &scaled_font->base.font_matrix, &mat);
- cairo_matrix_scale (&mat, 1.0/metrics.designUnitsPerEm, 1.0/metrics.designUnitsPerEm);
- _cairo_path_fixed_transform(path, &mat);
-
_cairo_scaled_glyph_set_path (scaled_glyph,
&scaled_font->base,
path);
@@ -860,7 +996,6 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s
{
int width, height;
double x1, y1, x2, y2;
- cairo_glyph_t glyph;
cairo_bool_t uses_foreground_color = FALSE;
cairo_dwrite_font_face_t *dwrite_font_face = (cairo_dwrite_font_face_t *)scaled_font->base.font_face;
@@ -877,22 +1012,18 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s
width = (int)(x2 - x1);
height = (int)(y2 - y1);
- glyph.index = _cairo_scaled_glyph_index (scaled_glyph);
- glyph.x = x1;
- glyph.y = y1;
-
DWRITE_GLYPH_RUN run;
FLOAT advance = 0;
- UINT16 index = (UINT16)glyph.index;
+ UINT16 index = (UINT16)_cairo_scaled_glyph_index (scaled_glyph);
DWRITE_GLYPH_OFFSET offset;
- double x = -glyph.x;
- double y = -glyph.y;
+ double x = -x1 + .25 * _cairo_scaled_glyph_xphase (scaled_glyph);
+ double y = -y1 + .25 * _cairo_scaled_glyph_yphase (scaled_glyph);
DWRITE_MATRIX matrix;
D2D1_POINT_2F origin = {0, 0};
RefPtr<IDWriteColorGlyphRunEnumerator1> run_enumerator;
HRESULT hr;
- /**
+ /*
* We transform by the inverse transformation here. This will put our glyph
* locations in the space in which we draw. Which is later transformed by
* the transformation matrix that we use. This will transform the
@@ -901,7 +1032,7 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s
*/
cairo_matrix_transform_point(&scaled_font->mat_inverse, &x, &y);
offset.advanceOffset = (FLOAT)x;
- /** Y-axis is inverted */
+ /* Y-axis is inverted */
offset.ascenderOffset = -(FLOAT)y;
run.fontFace = dwrite_font_face->dwriteface;
@@ -938,7 +1069,7 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s
&run,
NULL, /* glyphRunDescription */
supported_formats,
- DWRITE_MEASURING_MODE_NATURAL,
+ dwrite_font_face->measuring_mode,
&matrix,
palette_index,
&run_enumerator);
@@ -1013,8 +1144,8 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s
if (FAILED(hr) || !have_run)
break;
- DWRITE_COLOR_GLYPH_RUN1 const* color_run;
- hr = run_enumerator->GetCurrentRun(&color_run);
+ DWRITE_COLOR_GLYPH_RUN1_WORKAROUND const* color_run;
+ hr = run_enumerator->GetCurrentRun(reinterpret_cast<const DWRITE_COLOR_GLYPH_RUN1**>(&color_run));
if (FAILED(hr))
return _cairo_dwrite_error (hr, "GetCurrentRun failed");
@@ -1027,7 +1158,7 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s
dc4->DrawColorBitmapGlyphRun(color_run->glyphImageFormat,
origin,
&color_run->glyphRun,
- DWRITE_MEASURING_MODE_NATURAL,
+ dwrite_font_face->measuring_mode,
D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION_DEFAULT);
break;
@@ -1038,7 +1169,7 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s
foreground_color_brush,
nullptr,
palette_index,
- DWRITE_MEASURING_MODE_NATURAL);
+ dwrite_font_face->measuring_mode);
uses_foreground_color = TRUE;
break;
case DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE:
@@ -1050,14 +1181,23 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s
color_brush->SetColor(&color);
uses_foreground_color = TRUE;
} else {
- color_brush->SetColor(color_run->runColor);
+ double red, green, blue, alpha;
+ cairo_status_t status;
+ status = cairo_font_options_get_custom_palette_color (&scaled_font->base.options,
+ color_run->paletteIndex,
+ &red, &blue, &green, &alpha);
+ if (status == CAIRO_STATUS_SUCCESS) {
+ color_brush->SetColor(D2D1::ColorF(red, blue, green, alpha));
+ } else {
+ color_brush->SetColor(color_run->runColor);
+ }
}
dc4->DrawGlyphRun(origin,
&color_run->glyphRun,
color_run->glyphRunDescription,
color_brush,
- DWRITE_MEASURING_MODE_NATURAL);
+ dwrite_font_face->measuring_mode);
case DWRITE_GLYPH_IMAGE_FORMATS_NONE:
break;
}
@@ -1079,55 +1219,18 @@ _cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *s
_cairo_scaled_glyph_set_color_surface (scaled_glyph,
&scaled_font->base,
(cairo_image_surface_t *) image,
- uses_foreground_color);
+ uses_foreground_color ? foreground_color : NULL);
scaled_glyph->color_glyph = TRUE;
scaled_glyph->color_glyph_set = TRUE;
return CAIRO_INT_STATUS_SUCCESS;
}
-/* Helper function adapted from _compute_mask in cairo-win32-font.c */
-
-/* Compute an alpha-mask from a monochrome RGB24 image
- */
-static cairo_surface_t *
-_compute_a8_mask (cairo_surface_t *surface)
-{
- cairo_image_surface_t *glyph;
- cairo_image_surface_t *mask;
- int i, j;
-
- glyph = (cairo_image_surface_t *)cairo_surface_map_to_image (surface, NULL);
- if (unlikely (glyph->base.status))
- return &glyph->base;
-
- /* No quality param, just use the non-ClearType path */
-
- /* Compute an alpha-mask by using the green channel of a (presumed monochrome)
- * RGB24 image.
- */
- mask = (cairo_image_surface_t *)
- cairo_image_surface_create (CAIRO_FORMAT_A8, glyph->width, glyph->height);
- if (likely (mask->base.status == CAIRO_STATUS_SUCCESS)) {
- for (i = 0; i < glyph->height; i++) {
- uint32_t *p = (uint32_t *) (glyph->data + i * glyph->stride);
- uint8_t *q = (uint8_t *) (mask->data + i * mask->stride);
-
- for (j = 0; j < glyph->width; j++)
- *q++ = 255 - ((*p++ & 0x0000ff00) >> 8);
- }
- }
-
- cairo_surface_unmap_image (surface, &glyph->base);
- return &mask->base;
-}
-
static cairo_int_status_t
_cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t *scaled_font,
cairo_scaled_glyph_t *scaled_glyph)
{
cairo_int_status_t status;
- cairo_glyph_t glyph;
cairo_win32_surface_t *surface;
cairo_t *cr;
cairo_surface_t *image;
@@ -1141,16 +1244,12 @@ _cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t *scaled_
width = (int)(x2 - x1);
height = (int)(y2 - y1);
- glyph.index = _cairo_scaled_glyph_index (scaled_glyph);
- glyph.x = -x1;
- glyph.y = -y1;
-
DWRITE_GLYPH_RUN run;
FLOAT advance = 0;
- UINT16 index = (UINT16)glyph.index;
+ UINT16 index = (UINT16)_cairo_scaled_glyph_index (scaled_glyph);
DWRITE_GLYPH_OFFSET offset;
- double x = glyph.x;
- double y = glyph.y;
+ double x = -x1 + .25 * _cairo_scaled_glyph_xphase (scaled_glyph);
+ double y = -y1 + .25 * _cairo_scaled_glyph_yphase (scaled_glyph);
RECT area;
DWRITE_MATRIX matrix;
@@ -1165,7 +1264,7 @@ _cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t *scaled_
if (status)
goto FAIL;
- /**
+ /*
* We transform by the inverse transformation here. This will put our glyph
* locations in the space in which we draw. Which is later transformed by
* the transformation matrix that we use. This will transform the
@@ -1174,7 +1273,7 @@ _cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t *scaled_
*/
cairo_matrix_transform_point(&scaled_font->mat_inverse, &x, &y);
offset.advanceOffset = (FLOAT)x;
- /** Y-axis is inverted */
+ /* Y-axis is inverted */
offset.ascenderOffset = -(FLOAT)y;
area.top = 0;
@@ -1200,7 +1299,7 @@ _cairo_dwrite_scaled_font_init_glyph_surface(cairo_dwrite_scaled_font_t *scaled_
GdiFlush();
- image = _compute_a8_mask (&surface->base);
+ image = _cairo_compute_glyph_mask (&surface->base, _quality_from_antialias_mode(scaled_font->antialias_mode));
status = (cairo_int_status_t)image->status;
if (status)
goto FAIL;
@@ -1336,8 +1435,70 @@ _cairo_dwrite_has_color_glyphs(void *scaled_font)
return ((cairo_dwrite_font_face_t *)dwritesf->base.font_face)->have_color;
}
-cairo_font_face_t*
-cairo_dwrite_font_face_create_for_dwrite_fontface_internal(void* dwrite_font_face)
+/**
+ * cairo_dwrite_font_face_create_for_dwrite_fontface:
+ * @dwrite_font_face: A pointer to an #IDWriteFontFace specifying the
+ * DWrite font to use.
+ *
+ * Creates a new font for the DWrite font backend based on a
+ * DWrite font face. This font can then be used with
+ * cairo_set_font_face() or cairo_scaled_font_create().
+ *
+ * Here is an example of how this function might be used:
+ * <informalexample><programlisting><![CDATA[
+ * #include <cairo-dwrite.h>
+ * #include <dwrite.h>
+ *
+ * IDWriteFactory* dWriteFactory = NULL;
+ * HRESULT hr = DWriteCreateFactory(
+ * DWRITE_FACTORY_TYPE_SHARED,
+ * __uuidof(IDWriteFactory),
+ * reinterpret_cast<IUnknown**>(&dWriteFactory));
+ *
+ * IDWriteFontCollection *systemCollection;
+ * hr = dWriteFactory->GetSystemFontCollection(&systemCollection);
+ *
+ * UINT32 idx;
+ * BOOL found;
+ * systemCollection->FindFamilyName(L"Segoe UI Emoji", &idx, &found);
+ *
+ * IDWriteFontFamily *family;
+ * systemCollection->GetFontFamily(idx, &family);
+ *
+ * IDWriteFont *dwritefont;
+ * DWRITE_FONT_WEIGHT weight = DWRITE_FONT_WEIGHT_NORMAL;
+ * DWRITE_FONT_STYLE style = DWRITE_FONT_STYLE_NORMAL;
+ * hr = family->GetFirstMatchingFont(weight, DWRITE_FONT_STRETCH_NORMAL, style, &dwritefont);
+ *
+ * IDWriteFontFace *dwriteface;
+ * hr = dwritefont->CreateFontFace(&dwriteface);
+ *
+ * cairo_font_face_t *face;
+ * face = cairo_dwrite_font_face_create_for_dwrite_fontface(dwriteface);
+ * cairo_set_font_face(cr, face);
+ * cairo_set_font_size(cr, 70);
+ * cairo_move_to(cr, 100, 100);
+ * cairo_show_text(cr, "😃");
+ * ]]></programlisting></informalexample>
+ *
+ * Note: When printing a DWrite font to a
+ * #CAIRO_SURFACE_TYPE_WIN32_PRINTING surface, the printing surface
+ * will substitute each DWrite font with a Win32 font created from the same
+ * underlying font file. If the matching font file can not be found,
+ * the #CAIRO_SURFACE_TYPE_WIN32_PRINTING surface will convert each
+ * glyph to a filled path. If a DWrite font was not created from a system
+ * font, it is recommended that the font used to create the DWrite
+ * font be made available to GDI to avoid the undesirable fallback
+ * to emitting paths. This can be achieved using the GDI font loading functions
+ * such as AddFontMemResourceEx().
+ *
+ * Return value: a newly created #cairo_font_face_t. Free with
+ * cairo_font_face_destroy() when you are done using it.
+ *
+ * Since: 1.18
+ **/
+cairo_font_face_t *
+cairo_dwrite_font_face_create_for_dwrite_fontface (IDWriteFontFace *dwrite_font_face)
{
IDWriteFontFace *dwriteface = static_cast<IDWriteFontFace*>(dwrite_font_face);
// Must do malloc and not C++ new, since Cairo frees this.
@@ -1350,6 +1511,8 @@ cairo_dwrite_font_face_create_for_dwrite_fontface_internal(void* dwrite_font_fac
dwriteface->AddRef();
face->dwriteface = dwriteface;
face->have_color = false;
+ face->rendering_params = NULL;
+ face->measuring_mode = DWRITE_MEASURING_MODE_NATURAL;
/* Ensure IDWriteFactory4 is available before enabling color fonts */
if (DWriteFactory::Instance4()) {
@@ -1367,35 +1530,77 @@ cairo_dwrite_font_face_create_for_dwrite_fontface_internal(void* dwrite_font_fac
return font_face;
}
-void
-cairo_dwrite_scaled_font_set_force_GDI_classic(cairo_scaled_font_t *dwrite_scaled_font, cairo_bool_t force)
+/**
+ * cairo_dwrite_font_face_get_rendering_params:
+ * @font_face: The #cairo_dwrite_font_face_t object to query
+ *
+ * Gets the #IDWriteRenderingParams object of @font_face.
+ *
+ * Return value: the #IDWriteRenderingParams object or %NULL if none.
+ *
+ * Since: 1.18
+ **/
+IDWriteRenderingParams *
+cairo_dwrite_font_face_get_rendering_params (cairo_font_face_t *font_face)
{
- cairo_dwrite_scaled_font_t *font = reinterpret_cast<cairo_dwrite_scaled_font_t*>(dwrite_scaled_font);
- if (force && font->rendering_mode == cairo_dwrite_scaled_font_t::TEXT_RENDERING_NORMAL) {
- font->rendering_mode = cairo_dwrite_scaled_font_t::TEXT_RENDERING_GDI_CLASSIC;
- } else if (!force && font->rendering_mode == cairo_dwrite_scaled_font_t::TEXT_RENDERING_GDI_CLASSIC) {
- font->rendering_mode = cairo_dwrite_scaled_font_t::TEXT_RENDERING_NORMAL;
- }
+ cairo_dwrite_font_face_t *dwface = reinterpret_cast<cairo_dwrite_font_face_t *>(font_face);
+ return dwface->rendering_params;
}
-cairo_bool_t
-cairo_dwrite_scaled_font_get_force_GDI_classic(cairo_scaled_font_t *dwrite_scaled_font)
+/**
+ * cairo_dwrite_font_face_set_rendering_params:
+ * @font_face: The #cairo_dwrite_font_face_t object to modify
+ * @params: The #IDWriteRenderingParams object
+ *
+ * Sets the #IDWriteRenderingParams object to @font_face.
+ * This #IDWriteRenderingParams is used to render glyphs if default values of font options are used.
+ * If non-defalut values of font options are specified when creating a #cairo_scaled_font_t,
+ * cairo creates a new #IDWriteRenderingParams object for the #cairo_scaled_font_t object by overwriting the corresponding parameters.
+ *
+ * Since: 1.18
+ **/
+void
+cairo_dwrite_font_face_set_rendering_params (cairo_font_face_t *font_face, IDWriteRenderingParams *params)
{
- cairo_dwrite_scaled_font_t *font = reinterpret_cast<cairo_dwrite_scaled_font_t*>(dwrite_scaled_font);
- return font->rendering_mode == cairo_dwrite_scaled_font_t::TEXT_RENDERING_GDI_CLASSIC;
+ cairo_dwrite_font_face_t *dwface = reinterpret_cast<cairo_dwrite_font_face_t *>(font_face);
+ if (dwface->rendering_params)
+ dwface->rendering_params->Release();
+ dwface->rendering_params = params;
+ if (dwface->rendering_params)
+ dwface->rendering_params->AddRef();
}
-void
-cairo_dwrite_set_cleartype_params(FLOAT gamma, FLOAT contrast, FLOAT level,
- int geometry, int mode)
+/**
+ * cairo_dwrite_font_face_get_measuring_mode:
+ * @font_face: The #cairo_dwrite_font_face_t object to query
+ *
+ * Gets the #DWRITE_MEASURING_MODE enum of @font_face.
+ *
+ * Return value: The #DWRITE_MEASURING_MODE enum of @font_face.
+ *
+ * Since: 1.18
+ **/
+DWRITE_MEASURING_MODE
+cairo_dwrite_font_face_get_measuring_mode (cairo_font_face_t *font_face)
{
- DWriteFactory::SetRenderingParams(gamma, contrast, level, geometry, mode);
+ cairo_dwrite_font_face_t *dwface = reinterpret_cast<cairo_dwrite_font_face_t *>(font_face);
+ return dwface->measuring_mode;
}
-int
-cairo_dwrite_get_cleartype_rendering_mode()
+/**
+ * cairo_dwrite_font_face_set_measuring_mode:
+ * @font_face: The #cairo_dwrite_font_face_t object to modify
+ * @mode: The #DWRITE_MEASURING_MODE enum.
+ *
+ * Sets the #DWRITE_MEASURING_MODE enum to @font_face.
+ *
+ * Since: 1.18
+ **/
+void
+cairo_dwrite_font_face_set_measuring_mode (cairo_font_face_t *font_face, DWRITE_MEASURING_MODE mode)
{
- return DWriteFactory::GetClearTypeRenderingMode();
+ cairo_dwrite_font_face_t *dwface = reinterpret_cast<cairo_dwrite_font_face_t *>(font_face);
+ dwface->measuring_mode = mode;
}
static cairo_int_status_t
@@ -1411,9 +1616,6 @@ _dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface,
RefPtr<IDWriteBitmapRenderTarget> rt;
HRESULT hr;
- cairo_dwrite_scaled_font_t::TextRenderingState renderingState =
- scaled_font->rendering_mode;
-
hr = gdiInterop->CreateBitmapRenderTarget(surface->dc,
area.right - area.left,
area.bottom - area.top,
@@ -1427,22 +1629,7 @@ _dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface,
}
}
- if ((renderingState == cairo_dwrite_scaled_font_t::TEXT_RENDERING_NORMAL ||
- renderingState == cairo_dwrite_scaled_font_t::TEXT_RENDERING_GDI_CLASSIC)
- /* && !surface->base.permit_subpixel_antialiasing */ ) {
- renderingState = cairo_dwrite_scaled_font_t::TEXT_RENDERING_NO_CLEARTYPE;
- RefPtr<IDWriteBitmapRenderTarget1> rt1;
- hr = rt->QueryInterface(&rt1);
-
- if (SUCCEEDED(hr) && rt1) {
- rt1->SetTextAntialiasMode(DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE);
- }
- }
-
- RefPtr<IDWriteRenderingParams> params =
- DWriteFactory::RenderingParams(renderingState);
-
- /**
+ /*
* We set the number of pixels per DIP to 1.0. This is because we always want
* to draw in device pixels, and not device independent pixels. On high DPI
* systems this value will be higher than 1.0 and automatically upscale
@@ -1450,8 +1637,15 @@ _dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface,
*/
rt->SetPixelsPerDip(1.0);
+ float x = 0, y = 0;
if (transform) {
- rt->SetCurrentTransform(transform);
+ DWRITE_MATRIX matrix = *transform;
+ matrix.dx -= area.left;
+ matrix.dy -= area.top;
+ rt->SetCurrentTransform(&matrix);
+ } else {
+ x = (float) -area.left;
+ y = (float) -area.top;
}
BitBlt(rt->GetMemoryDC(),
0, 0,
@@ -1459,17 +1653,7 @@ _dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface,
surface->dc,
area.left, area.top,
SRCCOPY | NOMIRRORBITMAP);
- DWRITE_MEASURING_MODE measureMode;
- switch (renderingState) {
- case cairo_dwrite_scaled_font_t::TEXT_RENDERING_GDI_CLASSIC:
- case cairo_dwrite_scaled_font_t::TEXT_RENDERING_NO_CLEARTYPE:
- measureMode = DWRITE_MEASURING_MODE_GDI_CLASSIC;
- break;
- default:
- measureMode = DWRITE_MEASURING_MODE_NATURAL;
- break;
- }
- rt->DrawGlyphRun(0, 0, measureMode, run, params, color);
+ rt->DrawGlyphRun(x, y, scaled_font->measuring_mode, run, scaled_font->rendering_params, color);
BitBlt(surface->dc,
area.left, area.top,
area.right - area.left, area.bottom - area.top,
@@ -1505,6 +1689,7 @@ _dwrite_draw_glyphs_to_gdi_surface_d2d(cairo_win32_surface_t *surface,
if (FAILED(hr))
return CAIRO_INT_STATUS_UNSUPPORTED;
+ float x = 0, y = 0;
if (transform) {
rt->SetTransform(D2D1::Matrix3x2F(transform->m11,
transform->m12,
@@ -1553,15 +1738,6 @@ _cairo_dwrite_show_glyphs_on_surface(void *surface,
if (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER)
return CAIRO_INT_STATUS_UNSUPPORTED;
- /* If we have a fallback mask clip set on the dst, we have
- * to go through the fallback path */
- if (!_cairo_surface_is_win32_printing (&dst->base)) {
- if (clip != NULL)
- _cairo_win32_display_surface_set_clip (to_win32_display_surface (dst), clip);
- else
- _cairo_win32_display_surface_unset_clip (to_win32_display_surface (dst));
- }
-
/* It is vital that dx values for dxy_buf are calculated from the delta of
* _logical_ x coordinates (not user x coordinates) or else the sum of all
* previous dx values may start to diverge from the current glyph's x
@@ -1576,96 +1752,7 @@ _cairo_dwrite_show_glyphs_on_surface(void *surface,
DWRITE_GLYPH_OFFSET *offsets = const_cast<DWRITE_GLYPH_OFFSET*>(run.glyphOffsets);
BOOL transform = FALSE;
- /* Needed to calculate bounding box for efficient blitting */
- INT32 smallestX = INT_MAX;
- INT32 largestX = 0;
- INT32 smallestY = INT_MAX;
- INT32 largestY = 0;
- for (int i = 0; i < num_glyphs; i++) {
- if (glyphs[i].x < smallestX) {
- smallestX = (INT32)glyphs[i].x;
- }
- if (glyphs[i].x > largestX) {
- largestX = (INT32)glyphs[i].x;
- }
- if (glyphs[i].y < smallestY) {
- smallestY = (INT32)glyphs[i].y;
- }
- if (glyphs[i].y > largestY) {
- largestY = (INT32)glyphs[i].y;
- }
- }
- /**
- * Here we try to get a rough estimate of the area that this glyph run will
- * cover on the surface. Since we use GDI interop to draw we will be copying
- * data around the size of the area of the surface that we map. We will want
- * to map an area as small as possible to prevent large surfaces to be
- * copied around. We take the X/Y-size of the font as margin on the left/top
- * twice the X/Y-size of the font as margin on the right/bottom.
- * This should always cover the entire area where the glyphs are.
- */
- RECT fontArea;
- fontArea.left = (INT32)(smallestX - scaled_font->font_matrix.xx);
- fontArea.right = (INT32)(largestX + scaled_font->font_matrix.xx * 2);
- fontArea.top = (INT32)(smallestY - scaled_font->font_matrix.yy);
- fontArea.bottom = (INT32)(largestY + scaled_font->font_matrix.yy * 2);
- if (fontArea.left < 0)
- fontArea.left = 0;
- if (fontArea.top < 0)
- fontArea.top = 0;
- if (fontArea.bottom > dst->extents.height) {
- fontArea.bottom = dst->extents.height;
- }
- if (fontArea.right > dst->extents.width) {
- fontArea.right = dst->extents.width;
- }
- if (fontArea.right <= fontArea.left ||
- fontArea.bottom <= fontArea.top) {
- return CAIRO_INT_STATUS_SUCCESS;
- }
- if (fontArea.right > dst->extents.width) {
- fontArea.right = dst->extents.width;
- }
- if (fontArea.bottom > dst->extents.height) {
- fontArea.bottom = dst->extents.height;
- }
-
- run.bidiLevel = 0;
- run.fontFace = dwriteff->dwriteface;
- run.isSideways = FALSE;
- if (dwritesf->mat.xy == 0 && dwritesf->mat.yx == 0 &&
- dwritesf->mat.xx == scaled_font->font_matrix.xx &&
- dwritesf->mat.yy == scaled_font->font_matrix.yy) {
-
- for (int i = 0; i < num_glyphs; i++) {
- indices[i] = (WORD) glyphs[i].index;
- // Since we will multiply by our ctm matrix later for rotation effects
- // and such, adjust positions by the inverse matrix now.
- offsets[i].ascenderOffset = (FLOAT)(fontArea.top - glyphs[i].y);
- offsets[i].advanceOffset = (FLOAT)(glyphs[i].x - fontArea.left);
- advances[i] = 0.0;
- }
- run.fontEmSize = (FLOAT)scaled_font->font_matrix.yy;
- } else {
- transform = TRUE;
- // See comment about EPSILON in _cairo_dwrite_glyph_run_from_glyphs
- const double EPSILON = 0.0001;
- for (int i = 0; i < num_glyphs; i++) {
- indices[i] = (WORD) glyphs[i].index;
- double x = glyphs[i].x - fontArea.left + EPSILON;
- double y = glyphs[i].y - fontArea.top;
- cairo_matrix_transform_point(&dwritesf->mat_inverse, &x, &y);
- /**
- * Since we will multiply by our ctm matrix later for rotation effects
- * and such, adjust positions by the inverse matrix now. The Y-axis
- * is inverted so the offset becomes negative.
- */
- offsets[i].ascenderOffset = -(FLOAT)y;
- offsets[i].advanceOffset = (FLOAT)x;
- advances[i] = 0.0;
- }
- run.fontEmSize = 1.0f;
- }
+ _cairo_dwrite_glyph_run_from_glyphs(glyphs, num_glyphs, dwritesf, &run, &transform);
cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *)source;
COLORREF color = RGB(((int)solid_pattern->color.red_short) >> 8,
@@ -1681,18 +1768,31 @@ _cairo_dwrite_show_glyphs_on_surface(void *surface,
mat = NULL;
}
- RECT area;
- area.left = dst->extents.x;
- area.top = dst->extents.y;
- area.right = area.left + dst->extents.width;
- area.bottom = area.top + dst->extents.height;
+ RefPtr<IDWriteGlyphRunAnalysis> runAnalysis;
+ HRESULT hr = DWriteFactory::Instance()->
+ CreateGlyphRunAnalysis(&run, 1, mat,
+ DWRITE_RENDERING_MODE_ALIASED,
+ dwritesf->measuring_mode,
+ 0, // baselineOriginX,
+ 0, // baselineOriginY,
+ &runAnalysis);
+ if (FAILED(hr))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ RECT fontArea;
+ hr = runAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_ALIASED_1x1, &fontArea);
+ if (FAILED(hr))
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ InflateRect(&fontArea, 1, 1);
+ /* Needed to calculate bounding box for efficient blitting */
+ RECT copyArea, dstArea = { 0, 0, dst->extents.width, dst->extents.height };
+ IntersectRect(&copyArea, &fontArea, &dstArea);
#ifdef CAIRO_TRY_D2D_TO_GDI
status = _dwrite_draw_glyphs_to_gdi_surface_d2d(dst,
mat,
&run,
color,
- fontArea);
+ copyArea);
if (status == (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED) {
#endif
@@ -1701,7 +1801,7 @@ _cairo_dwrite_show_glyphs_on_surface(void *surface,
&run,
color,
dwritesf,
- fontArea);
+ copyArea);
#ifdef CAIRO_TRY_D2D_TO_GDI
}
@@ -1710,59 +1810,6 @@ _cairo_dwrite_show_glyphs_on_surface(void *surface,
return status;
}
-#define ENHANCED_CONTRAST_REGISTRY_KEY \
- HKEY_CURRENT_USER, "Software\\Microsoft\\Avalon.Graphics\\DISPLAY1\\EnhancedContrastLevel"
-
-void
-DWriteFactory::CreateRenderingParams()
-{
- if (!Instance()) {
- return;
- }
-
- Instance()->CreateRenderingParams(&mDefaultRenderingParams);
-
- // For EnhancedContrast, we override the default if the user has not set it
- // in the registry (by using the ClearType Tuner).
- FLOAT contrast;
- if (mEnhancedContrast >= 0.0 && mEnhancedContrast <= 10.0) {
- contrast = mEnhancedContrast;
- } else {
- HKEY hKey;
- if (RegOpenKeyExA(ENHANCED_CONTRAST_REGISTRY_KEY,
- 0, KEY_READ, &hKey) == ERROR_SUCCESS)
- {
- contrast = mDefaultRenderingParams->GetEnhancedContrast();
- RegCloseKey(hKey);
- } else {
- contrast = 1.0;
- }
- }
-
- // For parameters that have not been explicitly set via the SetRenderingParams API,
- // we copy values from default params (or our overridden value for contrast)
- FLOAT gamma =
- mGamma >= 1.0 && mGamma <= 2.2 ?
- mGamma : mDefaultRenderingParams->GetGamma();
- FLOAT clearTypeLevel =
- mClearTypeLevel >= 0.0 && mClearTypeLevel <= 1.0 ?
- mClearTypeLevel : mDefaultRenderingParams->GetClearTypeLevel();
- DWRITE_PIXEL_GEOMETRY pixelGeometry =
- mPixelGeometry >= DWRITE_PIXEL_GEOMETRY_FLAT && mPixelGeometry <= DWRITE_PIXEL_GEOMETRY_BGR ?
- (DWRITE_PIXEL_GEOMETRY)mPixelGeometry : mDefaultRenderingParams->GetPixelGeometry();
- DWRITE_RENDERING_MODE renderingMode =
- mRenderingMode >= DWRITE_RENDERING_MODE_DEFAULT && mRenderingMode <= DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC ?
- (DWRITE_RENDERING_MODE)mRenderingMode : mDefaultRenderingParams->GetRenderingMode();
-
- Instance()->CreateCustomRenderingParams(gamma, contrast, clearTypeLevel,
- pixelGeometry, renderingMode,
- &mCustomClearTypeRenderingParams);
-
- Instance()->CreateCustomRenderingParams(gamma, contrast, clearTypeLevel,
- pixelGeometry, DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC,
- &mForceGDIClassicRenderingParams);
-}
-
/* Check if a specific font table in a DWrite font and a scaled font is identical */
static cairo_int_status_t
compare_font_tables (cairo_dwrite_font_face_t *dwface,
@@ -1866,6 +1913,16 @@ _cairo_dwrite_scaled_font_create_win32_scaled_font (cairo_scaled_font_t *scaled_
}
cairo_font_face_t *face = cairo_scaled_font_get_font_face (scaled_font);
+ if (cairo_font_face_status (face) == CAIRO_STATUS_SUCCESS &&
+ cairo_font_face_get_type (face) == CAIRO_FONT_TYPE_TOY)
+ {
+ face = ((cairo_toy_font_face_t *)face)->impl_face;
+ }
+
+ if (face == NULL || cairo_font_face_get_type (face) != CAIRO_FONT_TYPE_DWRITE) {
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
+
cairo_dwrite_font_face_t *dwface = reinterpret_cast<cairo_dwrite_font_face_t*>(face);
RefPtr<IDWriteGdiInterop> gdiInterop;
@@ -1897,6 +1954,7 @@ _cairo_dwrite_scaled_font_create_win32_scaled_font (cairo_scaled_font_t *scaled_
cairo_scaled_font_get_ctm (scaled_font, &ctm);
cairo_font_options_t options;
+ _cairo_font_options_init_default (&options);
cairo_scaled_font_get_font_options (scaled_font, &options);
cairo_scaled_font_t *font = cairo_scaled_font_create (win32_face,
diff --git a/src/win32/cairo-dwrite-private.hpp b/src/win32/cairo-dwrite-private.hpp
index 92b096857..c7a24822a 100644
--- a/src/win32/cairo-dwrite-private.hpp
+++ b/src/win32/cairo-dwrite-private.hpp
@@ -36,27 +36,25 @@
#include "cairoint.h"
#include "cairo-win32-refptr.hpp"
-#include <dwrite.h>
-#include <dwrite_2.h>
+#include <dwrite_3.h>
#include <d2d1.h>
-/* If either of the dwrite_3.h or d2d1_3.h headers required for color fonts
- * are not available, include our own version containing just the functions we need.
- */
-
-#if HAVE_DWRITE_3_H
-#include <dwrite_3.h>
-#else
+#ifdef __MINGW32__
#include "dw-extra.h"
+#else
+typedef DWRITE_COLOR_GLYPH_RUN1 DWRITE_COLOR_GLYPH_RUN1_WORKAROUND;
#endif
+/* If d2d1_3.h header required for color fonts is not available,
+ * include our own version containing just the functions we need.
+ */
+
#if HAVE_D2D1_3_H
#include <d2d1_3.h>
#else
#include "d2d1-extra.h"
#endif
-
// DirectWrite is not available on all platforms.
typedef HRESULT (WINAPI*DWriteCreateFactoryFunc)(
DWRITE_FACTORY_TYPE factoryType,
@@ -70,14 +68,8 @@ struct _cairo_dwrite_scaled_font {
cairo_matrix_t mat;
cairo_matrix_t mat_inverse;
cairo_antialias_t antialias_mode;
+ IDWriteRenderingParams *rendering_params;
DWRITE_MEASURING_MODE measuring_mode;
- enum TextRenderingState {
- TEXT_RENDERING_UNINITIALIZED,
- TEXT_RENDERING_NO_CLEARTYPE,
- TEXT_RENDERING_NORMAL,
- TEXT_RENDERING_GDI_CLASSIC
- };
- TextRenderingState rendering_mode;
};
typedef struct _cairo_dwrite_scaled_font cairo_dwrite_scaled_font_t;
@@ -107,6 +99,36 @@ public:
return mFactoryInstance;
}
+ static RefPtr<IDWriteFactory1> Instance1()
+ {
+ if (!mFactoryInstance1) {
+ if (Instance()) {
+ Instance()->QueryInterface(&mFactoryInstance1);
+ }
+ }
+ return mFactoryInstance1;
+ }
+
+ static RefPtr<IDWriteFactory2> Instance2()
+ {
+ if (!mFactoryInstance2) {
+ if (Instance()) {
+ Instance()->QueryInterface(&mFactoryInstance2);
+ }
+ }
+ return mFactoryInstance2;
+ }
+
+ static RefPtr<IDWriteFactory3> Instance3()
+ {
+ if (!mFactoryInstance3) {
+ if (Instance()) {
+ Instance()->QueryInterface(&mFactoryInstance3);
+ }
+ }
+ return mFactoryInstance3;
+ }
+
static RefPtr<IDWriteFactory4> Instance4()
{
if (!mFactoryInstance4) {
@@ -145,69 +167,24 @@ public:
return family;
}
- static RefPtr<IDWriteRenderingParams> RenderingParams(cairo_dwrite_scaled_font_t::TextRenderingState mode)
- {
- if (!mDefaultRenderingParams ||
- !mForceGDIClassicRenderingParams ||
- !mCustomClearTypeRenderingParams)
- {
- CreateRenderingParams();
- }
- RefPtr<IDWriteRenderingParams> params;
- if (mode == cairo_dwrite_scaled_font_t::TEXT_RENDERING_NO_CLEARTYPE) {
- params = mDefaultRenderingParams;
- } else if (mode == cairo_dwrite_scaled_font_t::TEXT_RENDERING_GDI_CLASSIC && mRenderingMode < 0) {
- params = mForceGDIClassicRenderingParams;
- } else {
- params = mCustomClearTypeRenderingParams;
- }
- return params;
- }
-
- static void SetRenderingParams(FLOAT aGamma,
- FLOAT aEnhancedContrast,
- FLOAT aClearTypeLevel,
- int aPixelGeometry,
- int aRenderingMode)
+ static RefPtr<IDWriteRenderingParams> DefaultRenderingParams()
{
- mGamma = aGamma;
- mEnhancedContrast = aEnhancedContrast;
- mClearTypeLevel = aClearTypeLevel;
- mPixelGeometry = aPixelGeometry;
- mRenderingMode = aRenderingMode;
- // discard any current RenderingParams objects
- if (mCustomClearTypeRenderingParams) {
- mCustomClearTypeRenderingParams->Release();
- mCustomClearTypeRenderingParams = NULL;
- }
- if (mForceGDIClassicRenderingParams) {
- mForceGDIClassicRenderingParams->Release();
- mForceGDIClassicRenderingParams = NULL;
- }
- if (mDefaultRenderingParams) {
- mDefaultRenderingParams->Release();
- mDefaultRenderingParams = NULL;
+ if (!mDefaultRenderingParams) {
+ if (Instance()) {
+ Instance()->CreateRenderingParams(&mDefaultRenderingParams);
+ }
}
- }
-
- static int GetClearTypeRenderingMode() {
- return mRenderingMode;
+ return mDefaultRenderingParams;
}
private:
- static void CreateRenderingParams();
-
static RefPtr<IDWriteFactory> mFactoryInstance;
+ static RefPtr<IDWriteFactory1> mFactoryInstance1;
+ static RefPtr<IDWriteFactory2> mFactoryInstance2;
+ static RefPtr<IDWriteFactory3> mFactoryInstance3;
static RefPtr<IDWriteFactory4> mFactoryInstance4;
static RefPtr<IDWriteFontCollection> mSystemCollection;
static RefPtr<IDWriteRenderingParams> mDefaultRenderingParams;
- static RefPtr<IDWriteRenderingParams> mCustomClearTypeRenderingParams;
- static RefPtr<IDWriteRenderingParams> mForceGDIClassicRenderingParams;
- static FLOAT mGamma;
- static FLOAT mEnhancedContrast;
- static FLOAT mClearTypeLevel;
- static int mPixelGeometry;
- static int mRenderingMode;
};
class AutoDWriteGlyphRun : public DWRITE_GLYPH_RUN
@@ -251,5 +228,7 @@ struct _cairo_dwrite_font_face {
cairo_font_face_t base;
IDWriteFontFace *dwriteface; /* Can't use RefPtr because this struct is malloc'd. */
cairo_bool_t have_color;
+ IDWriteRenderingParams *rendering_params; /* Can't use RefPtr because this struct is malloc'd. */
+ DWRITE_MEASURING_MODE measuring_mode;
};
typedef struct _cairo_dwrite_font_face cairo_dwrite_font_face_t;
diff --git a/src/win32/cairo-win32-debug.c b/src/win32/cairo-win32-debug.c
index 5a971bd61..01410c896 100644
--- a/src/win32/cairo-win32-debug.c
+++ b/src/win32/cairo-win32-debug.c
@@ -37,15 +37,6 @@
* Vladimir Vukicevic <vladimir@pobox.com>
*/
-#define WIN32_LEAN_AND_MEAN
-/* We require Windows 2000 features such as ETO_PDY */
-#if !defined(WINVER) || (WINVER < 0x0500)
-# define WINVER 0x0500
-#endif
-#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
-# define _WIN32_WINNT 0x0500
-#endif
-
#include "cairoint.h"
#include "cairo-win32-private.h"
diff --git a/src/win32/cairo-win32-device.c b/src/win32/cairo-win32-device.c
index 6fce722ec..781ee0cde 100644
--- a/src/win32/cairo-win32-device.c
+++ b/src/win32/cairo-win32-device.c
@@ -37,15 +37,6 @@
* Vladimir Vukicevic <vladimir@pobox.com>
*/
-#define WIN32_LEAN_AND_MEAN
-/* We require Windows 2000 features such as ETO_PDY */
-#if !defined(WINVER) || (WINVER < 0x0500)
-# define WINVER 0x0500
-#endif
-#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
-# define _WIN32_WINNT 0x0500
-#endif
-
#include "cairoint.h"
#include "cairo-atomic-private.h"
diff --git a/src/win32/cairo-win32-display-surface.c b/src/win32/cairo-win32-display-surface.c
index 841725474..e3b3eec2f 100644
--- a/src/win32/cairo-win32-display-surface.c
+++ b/src/win32/cairo-win32-display-surface.c
@@ -37,15 +37,6 @@
* Vladimir Vukicevic <vladimir@pobox.com>
*/
-#define WIN32_LEAN_AND_MEAN
-/* We require Windows 2000 features such as ETO_PDY */
-#if !defined(WINVER) || (WINVER < 0x0500)
-# define WINVER 0x0500
-#endif
-#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
-# define _WIN32_WINNT 0x0500
-#endif
-
#include "cairoint.h"
#include "cairo-clip-private.h"
diff --git a/src/win32/cairo-win32-font.c b/src/win32/cairo-win32-font.c
index 2003a2782..a561e74a4 100644
--- a/src/win32/cairo-win32-font.c
+++ b/src/win32/cairo-win32-font.c
@@ -33,15 +33,6 @@
* Contributor(s):
*/
-#define WIN32_LEAN_AND_MEAN
-/* We require Windows 2000 features such as GetGlyphIndices */
-#if !defined(WINVER) || (WINVER < 0x0500)
-# define WINVER 0x0500
-#endif
-#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
-# define _WIN32_WINNT 0x0500
-#endif
-
#include "cairoint.h"
#include "cairo-win32-private.h"
@@ -80,7 +71,6 @@
*
* Note: Win32 GDI fonts do not support color fonts. Use DWrite fonts
* if color font support is required.
-
**/
/**
@@ -1345,9 +1335,9 @@ _cairo_win32_scaled_font_load_type1_data (void *abstract_font,
length);
}
-static cairo_surface_t *
-_compute_mask (cairo_surface_t *surface,
- int quality)
+cairo_surface_t *
+_cairo_compute_glyph_mask (cairo_surface_t *surface,
+ int quality)
{
cairo_image_surface_t *glyph;
cairo_image_surface_t *mask;
@@ -1431,7 +1421,7 @@ _cairo_win32_scaled_font_init_glyph_surface (cairo_win32_scaled_font_t *scaled_f
if (status)
goto FAIL;
- image = _compute_mask (surface, scaled_font->quality);
+ image = _cairo_compute_glyph_mask (surface, scaled_font->quality);
status = image->status;
if (status)
goto FAIL;
@@ -1808,7 +1798,7 @@ _cairo_win32_font_face_scaled_font_create (void *abstract_face,
if (font_face->hfont) {
/* Check whether it's OK to go ahead and use the font-face's HFONT. */
if (_is_scale (ctm, 1.) &&
- _is_scale (font_matrix, -font_face->logfont.lfHeight)) {
+ _is_scale (font_matrix, -font_face->logfont.lfHeight * WIN32_FONT_LOGICAL_SCALE)) {
hfont = font_face->hfont;
}
}
diff --git a/src/win32/cairo-win32-gdi-compositor.c b/src/win32/cairo-win32-gdi-compositor.c
index 1d1d7f873..bc1f69e70 100644
--- a/src/win32/cairo-win32-gdi-compositor.c
+++ b/src/win32/cairo-win32-gdi-compositor.c
@@ -602,7 +602,8 @@ static cairo_bool_t check_glyphs (cairo_composite_rectangles_t *composite,
if (! _cairo_clip_is_region (composite->clip))
return FALSE;
- if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_WIN32)
+ cairo_font_type_t type = cairo_scaled_font_get_type (scaled_font);
+ if (type != CAIRO_FONT_TYPE_WIN32 && type != CAIRO_FONT_TYPE_DWRITE)
return FALSE;
if (! _cairo_pattern_is_opaque_solid (&composite->source_pattern.base))
diff --git a/src/win32/cairo-win32-printing-surface.c b/src/win32/cairo-win32-printing-surface.c
index 602a4f3f0..a3dd907c2 100644
--- a/src/win32/cairo-win32-printing-surface.c
+++ b/src/win32/cairo-win32-printing-surface.c
@@ -35,15 +35,6 @@
* Vladimir Vukicevic <vladimir@pobox.com>
*/
-#define WIN32_LEAN_AND_MEAN
-/* We require Windows 2000 features such as ETO_PDY */
-#if !defined(WINVER) || (WINVER < 0x0500)
-# define WINVER 0x0500
-#endif
-#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
-# define _WIN32_WINNT 0x0500
-#endif
-
#include "cairoint.h"
#include "cairo-default-context-private.h"
@@ -663,6 +654,7 @@ _cairo_win32_printing_surface_paint_recording_pattern (cairo_win32_printing_surf
SaveDC (surface->win32.dc); /* Allow clip path to be reset during replay */
status = _cairo_recording_surface_replay_region (&recording_surface->base,
+ pattern->region_array_id,
is_subsurface ? &recording_extents : NULL,
&surface->win32.base,
CAIRO_RECORDING_REGION_NATIVE);
@@ -2162,6 +2154,9 @@ _cairo_win32_printing_surface_supports_fine_grained_fallbacks (void *abstract_su
* provide correct complex rendering behaviour; cairo_surface_show_page() and
* associated methods must be used for correct output.
*
+ * The following mime types are supported on source patterns:
+ * %CAIRO_MIME_TYPE_JPEG, %CAIRO_MIME_TYPE_PNG.
+ *
* Return value: the newly created surface
*
* Since: 1.6
diff --git a/src/win32/cairo-win32-private.h b/src/win32/cairo-win32-private.h
index d457b7805..6af09c0e1 100644
--- a/src/win32/cairo-win32-private.h
+++ b/src/win32/cairo-win32-private.h
@@ -214,6 +214,10 @@ cairo_bool_t
_cairo_win32_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle);
+cairo_surface_t *
+_cairo_compute_glyph_mask (cairo_surface_t *surface,
+ int quality);
+
uint32_t
_cairo_win32_flags_for_dc (HDC dc, cairo_format_t format);
@@ -271,9 +275,6 @@ cairo_int_status_t
_cairo_dwrite_scaled_font_create_win32_scaled_font (cairo_scaled_font_t *scaled_font,
cairo_scaled_font_t **new_font);
-cairo_font_face_t*
-cairo_dwrite_font_face_create_for_dwrite_fontface_internal(void* dwrite_font_face);
-
#endif /* CAIRO_HAS_DWRITE_FONT */
CAIRO_END_DECLS
diff --git a/src/win32/cairo-win32-surface.c b/src/win32/cairo-win32-surface.c
index e53c16540..ca5c9d823 100644
--- a/src/win32/cairo-win32-surface.c
+++ b/src/win32/cairo-win32-surface.c
@@ -37,15 +37,6 @@
* Vladimir Vukicevic <vladimir@pobox.com>
*/
-#define WIN32_LEAN_AND_MEAN
-/* We require Windows 2000 features such as ETO_PDY */
-#if !defined(WINVER) || (WINVER < 0x0500)
-# define WINVER 0x0500
-#endif
-#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
-# define _WIN32_WINNT 0x0500
-#endif
-
#include "cairoint.h"
#include "cairo-backend-private.h"
diff --git a/src/win32/cairo-win32-system.c b/src/win32/cairo-win32-system.c
index 878553009..01bbe89df 100644
--- a/src/win32/cairo-win32-system.c
+++ b/src/win32/cairo-win32-system.c
@@ -50,15 +50,6 @@
#if CAIRO_MUTEX_IMPL_WIN32
#if !CAIRO_WIN32_STATIC_BUILD
-#define WIN32_LEAN_AND_MEAN
-/* We require Windows 2000 features such as ETO_PDY */
-#if !defined(WINVER) || (WINVER < 0x0500)
-# define WINVER 0x0500
-#endif
-#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
-# define _WIN32_WINNT 0x0500
-#endif
-
#include <windows.h>
/* declare to avoid "no previous prototype for 'DllMain'" warning */
diff --git a/src/win32/dw-extra.h b/src/win32/dw-extra.h
index 4203f3427..c79e6389c 100644
--- a/src/win32/dw-extra.h
+++ b/src/win32/dw-extra.h
@@ -1,165 +1,30 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* Mingw-w64 dwrite_3.h is broken
+/* MinGW workarounds
*
- * We only need the definitions of the following functions and their dependencies.
- * IDWriteFactory4::TranslateColorGlyphRun()
- * IDWriteFontResource::GetDefaultFontAxisValues()
- * IDWriteFontResource::GetFontAxisCount()
- * IDWriteFontResource::HasVariations()
- * IDWriteFontFace5::GetFontAxisValueCount()
- * IDWriteFontFace5::GetFontAxisValues()
- * IDWriteFontFace5::HasVariations()
- * IDWriteFontFace5::GetFontResource()
- *
- * But we need to include all the prior functions in the same struct,
- * and parent structs, so that the functions are in the correct position
- * in the vtable. The parameters of the unused functions are not
- * required as we only need a function in the struct to create a
- * function pointer in the vtable.
+ * It doesn't define operators for DWRITE_GLYPH_IMAGE_FORMATS.
+ * The DWRITE_COLOR_GLYPH_RUN struct isn't valid.
+ * <https://sourceforge.net/p/mingw-w64/bugs/913/>
*/
#ifndef DWRITE_EXTRA_H
#define DWRITE_EXTRA_H
-#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
-
-#include <dwrite_2.h>
+#if defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 10
-interface IDWriteFactory3;
-interface IDWriteFactory4;
-interface IDWriteColorGlyphRunEnumerator1;
-
-DEFINE_ENUM_FLAG_OPERATORS(DWRITE_GLYPH_IMAGE_FORMATS);
-
-struct DWRITE_COLOR_GLYPH_RUN1 : DWRITE_COLOR_GLYPH_RUN
+typedef struct DWRITE_COLOR_GLYPH_RUN1_WORKAROUND DWRITE_COLOR_GLYPH_RUN1_WORKAROUND;
+struct DWRITE_COLOR_GLYPH_RUN1_WORKAROUND : DWRITE_COLOR_GLYPH_RUN
{
DWRITE_GLYPH_IMAGE_FORMATS glyphImageFormat;
DWRITE_MEASURING_MODE measuringMode;
};
+#else
+typedef DWRITE_COLOR_GLYPH_RUN1 DWRITE_COLOR_GLYPH_RUN1_WORKAROUND;
+#error
-DEFINE_GUID(IID_IDWriteColorGlyphRunEnumerator1, 0x7c5f86da, 0xc7a1, 0x4f05, 0xb8,0xe1, 0x55,0xa1,0x79,0xfe,0x5a,0x35);
-MIDL_INTERFACE("7c5f86da-c7a1-4f05-b8e1-55a179fe5a35")
-IDWriteColorGlyphRunEnumerator1 : public IDWriteColorGlyphRunEnumerator
-{
- virtual HRESULT STDMETHODCALLTYPE GetCurrentRun(
- const DWRITE_COLOR_GLYPH_RUN1 **run) = 0;
-
-};
-__CRT_UUID_DECL(IDWriteColorGlyphRunEnumerator1, 0x7c5f86da, 0xc7a1, 0x4f05, 0xb8,0xe1, 0x55,0xa1,0x79,0xfe,0x5a,0x35)
-
-DEFINE_GUID(IID_IDWriteFactory3, 0x9a1b41c3, 0xd3bb, 0x466a, 0x87,0xfc, 0xfe,0x67,0x55,0x6a,0x3b,0x65);
-MIDL_INTERFACE("9a1b41c3-d3bb-466a-87fc-fe67556a3b65")
-IDWriteFactory3 : public IDWriteFactory2
-{
- virtual void STDMETHODCALLTYPE CreateGlyphRunAnalysis() = 0;
- virtual void STDMETHODCALLTYPE CreateCustomRenderingParams() = 0;
- virtual void STDMETHODCALLTYPE CreateFontFaceReference() = 0;
- virtual void STDMETHODCALLTYPE CreateFontFaceReference2() = 0;
- virtual void STDMETHODCALLTYPE GetSystemFontSet() = 0;
- virtual void STDMETHODCALLTYPE CreateFontSetBuilder() = 0;
- virtual void STDMETHODCALLTYPE CreateFontCollectionFromFontSet() = 0;
- virtual void STDMETHODCALLTYPE GetSystemFontCollection() = 0;
- virtual void STDMETHODCALLTYPE GetFontDownloadQueue() = 0;
-};
-__CRT_UUID_DECL(IDWriteFactory3, 0x9a1b41c3, 0xd3bb, 0x466a, 0x87,0xfc, 0xfe,0x67,0x55,0x6a,0x3b,0x65)
-
-DEFINE_GUID(IID_IDWriteFactory4, 0x4b0b5bd3, 0x0797, 0x4549, 0x8a,0xc5, 0xfe,0x91,0x5c,0xc5,0x38,0x56);
-MIDL_INTERFACE("4b0b5bd3-0797-4549-8ac5-fe915cc53856")
-IDWriteFactory4 : public IDWriteFactory3
-{
- virtual HRESULT STDMETHODCALLTYPE TranslateColorGlyphRun(
- D2D1_POINT_2F baselineOrigin,
- DWRITE_GLYPH_RUN const *glyphRun,
- DWRITE_GLYPH_RUN_DESCRIPTION const *glyphRunDescription,
- DWRITE_GLYPH_IMAGE_FORMATS desiredGlyphImageFormats,
- DWRITE_MEASURING_MODE measuringMode,
- DWRITE_MATRIX const *worldAndDpiTransform,
- UINT32 colorPaletteIndex,
- IDWriteColorGlyphRunEnumerator1 **colorLayers) = 0;
-};
-__CRT_UUID_DECL(IDWriteFactory4, 0x4b0b5bd3, 0x0797, 0x4549, 0x8a,0xc5, 0xfe,0x91,0x5c,0xc5,0x38,0x56)
-
-typedef enum DWRITE_FONT_AXIS_TAG {
- DWRITE_FONT_AXIS_TAG_WEIGHT = 0x74686777,
- DWRITE_FONT_AXIS_TAG_WIDTH = 0x68746477,
- DWRITE_FONT_AXIS_TAG_SLANT = 0x746e6c73,
- DWRITE_FONT_AXIS_TAG_OPTICAL_SIZE = 0x7a73706f,
- DWRITE_FONT_AXIS_TAG_ITALIC = 0x6c617469
-} DWRITE_FONT_AXIS_TAG;
-
-typedef struct DWRITE_FONT_AXIS_VALUE {
- DWRITE_FONT_AXIS_TAG axisTag;
- FLOAT value;
-} DWRITE_FONT_AXIS_VALUE;
-
-DEFINE_GUID(IID_IDWriteFontResource, 0x1f803a76, 0x6871, 0x48e8, 0x98,0x7f, 0xb9,0x75,0x55,0x1c,0x50,0xf2);
-MIDL_INTERFACE("1f803a76-6871-48e8-987f-b975551c50f2")
-IDWriteFontResource : public IUnknown
-{
- virtual void STDMETHODCALLTYPE GetFontFile() = 0;
- virtual void STDMETHODCALLTYPE GetFontFaceIndex() = 0;
- virtual UINT32 STDMETHODCALLTYPE GetFontAxisCount() = 0;
- virtual HRESULT STDMETHODCALLTYPE GetDefaultFontAxisValues(
- const DWRITE_FONT_AXIS_VALUE *values,
- UINT32 num_values) = 0;
- virtual void STDMETHODCALLTYPE GetFontAxisRanges() = 0;
- virtual void STDMETHODCALLTYPE GetFontAxisAttributes() = 0;
- virtual void STDMETHODCALLTYPE GetAxisNames() = 0;
- virtual void STDMETHODCALLTYPE GetAxisValueNameCount() = 0;
- virtual void STDMETHODCALLTYPE GetAxisValueNames() = 0;
- virtual WINBOOL STDMETHODCALLTYPE HasVariations() = 0;
- virtual void STDMETHODCALLTYPE CreateFontFace() = 0;
- virtual void STDMETHODCALLTYPE CreateFontFaceReference() = 0;
-};
-__CRT_UUID_DECL(IDWriteFontResource, 0x1f803a76, 0x6871, 0x48e8, 0x98,0x7f, 0xb9,0x75,0x55,0x1c,0x50,0xf2)
-
-DEFINE_GUID(IID_IDWriteFontFace3, 0xd37d7598, 0x09be, 0x4222, 0xa2,0x36, 0x20,0x81,0x34,0x1c,0xc1,0xf2);
-MIDL_INTERFACE("d37d7598-09be-4222-a236-2081341cc1f2")
-IDWriteFontFace3 : public IDWriteFontFace2
-{
- virtual void STDMETHODCALLTYPE GetFontFaceReference() = 0;
- virtual void STDMETHODCALLTYPE GetPanose() = 0;
- virtual void STDMETHODCALLTYPE GetWeight() = 0;
- virtual void STDMETHODCALLTYPE GetStretch() = 0;
- virtual void STDMETHODCALLTYPE GetStyle() = 0;
- virtual void STDMETHODCALLTYPE GetFamilyNames() = 0;
- virtual void STDMETHODCALLTYPE GetFaceNames() = 0;
- virtual void STDMETHODCALLTYPE GetInformationalStrings() = 0;
- virtual void STDMETHODCALLTYPE HasCharacter() = 0;
- virtual void STDMETHODCALLTYPE GetRecommendedRenderingMode() = 0;
- virtual void STDMETHODCALLTYPE IsCharacterLocal() = 0;
- virtual void STDMETHODCALLTYPE IsGlyphLocal() = 0;
- virtual void STDMETHODCALLTYPE AreCharactersLocal() = 0;
- virtual void STDMETHODCALLTYPE AreGlyphsLocal() = 0;
-};
-__CRT_UUID_DECL(IDWriteFontFace3, 0xd37d7598, 0x09be, 0x4222, 0xa2,0x36, 0x20,0x81,0x34,0x1c,0xc1,0xf2)
-
-DEFINE_GUID(IID_IDWriteFontFace4, 0x27f2a904, 0x4eb8, 0x441d, 0x96,0x78, 0x05,0x63,0xf5,0x3e,0x3e,0x2f);
-MIDL_INTERFACE("27f2a904-4eb8-441d-9678-0563f53e3e2f")
-IDWriteFontFace4 : public IDWriteFontFace3
-{
- virtual void STDMETHODCALLTYPE GetGlyphImageFormats_() = 0;
- virtual void STDMETHODCALLTYPE GetGlyphImageFormats() = 0;
- virtual void STDMETHODCALLTYPE GetGlyphImageData() = 0;
- virtual void STDMETHODCALLTYPE ReleaseGlyphImageData() = 0;
-};
-__CRT_UUID_DECL(IDWriteFontFace4, 0x27f2a904, 0x4eb8, 0x441d, 0x96,0x78, 0x05,0x63,0xf5,0x3e,0x3e,0x2f)
+#endif
-DEFINE_GUID(IID_IDWriteFontFace5, 0x98eff3a5, 0xb667, 0x479a, 0xb1,0x45, 0xe2,0xfa,0x5b,0x9f,0xdc,0x29);
-MIDL_INTERFACE("98eff3a5-b667-479a-b145-e2fa5b9fdc29")
-IDWriteFontFace5 : public IDWriteFontFace4
-{
- virtual UINT32 STDMETHODCALLTYPE GetFontAxisValueCount() = 0;
- virtual HRESULT STDMETHODCALLTYPE GetFontAxisValues(
- DWRITE_FONT_AXIS_VALUE *values,
- UINT32 value_count) = 0;
- virtual WINBOOL STDMETHODCALLTYPE HasVariations() = 0;
- virtual HRESULT STDMETHODCALLTYPE GetFontResource(
- IDWriteFontResource **resource) = 0;
- virtual void STDMETHODCALLTYPE Equals() = 0;
-};
-__CRT_UUID_DECL(IDWriteFontFace5, 0x98eff3a5, 0xb667, 0x479a, 0xb1,0x45, 0xe2,0xfa,0x5b,0x9f,0xdc,0x29)
+DEFINE_ENUM_FLAG_OPERATORS(DWRITE_GLYPH_IMAGE_FORMATS);
#endif /* DWRITE_EXTRA_H */
diff --git a/subprojects/glib.wrap b/subprojects/glib.wrap
index ca58d1a28..51d9cf8d4 100644
--- a/subprojects/glib.wrap
+++ b/subprojects/glib.wrap
@@ -1,5 +1,10 @@
-[wrap-git]
-directory=glib
-url=https://gitlab.gnome.org/GNOME/glib.git
-push-url=git@gitlab.gnome.org:GNOME/glib.git
-revision=2.66.7
+[wrap-file]
+directory = glib-2.74.0
+source_url = https://download.gnome.org/sources/glib/2.74/glib-2.74.0.tar.xz
+source_filename = glib-2.74.0.tar.xz
+source_hash = 3652c7f072d7b031a6b5edd623f77ebc5dcd2ae698598abcc89ff39ca75add30
+wrapdb_version = 2.74.0-1
+
+[provide]
+dependency_names = gthread-2.0, gobject-2.0, gmodule-no-export-2.0, gmodule-export-2.0, gmodule-2.0, glib-2.0, gio-2.0, gio-windows-2.0, gio-unix-2.0
+program_names = glib-genmarshal, glib-mkenums, glib-compile-schemas, glib-compile-resources, gio-querymodules, gdbus-codegen
diff --git a/test/Makefile.am b/test/Makefile.am
deleted file mode 100644
index a74d71a7c..000000000
--- a/test/Makefile.am
+++ /dev/null
@@ -1,409 +0,0 @@
-include $(top_srcdir)/build/Makefile.am.common
-
-include $(top_srcdir)/test/Makefile.sources
-
-SUBDIRS=pdiff .
-
-# Then we have a collection of tests that are only run if certain
-# features are compiled into cairo
-if HAVE_REAL_PTHREAD
-test_sources += $(pthread_test_sources)
-endif
-
-if CAIRO_HAS_FT_FONT
-test_sources += $(ft_font_test_sources)
-if CAIRO_HAS_FC_FONT
-test_sources += $(fc_font_test_sources)
-endif
-endif
-
-if CAIRO_HAS_GL_SURFACE
-test_sources += $(gl_surface_test_sources)
-endif
-
-if CAIRO_HAS_EGL_FUNCTIONS
-test_sources += $(egl_surface_test_sources)
-endif
-
-# Need to add quartz-surface-source
-if CAIRO_HAS_QUARTZ_SURFACE
-test_sources += "$(quartz_surface_test_sources) $(quartz_color_font_test_sources)"
-endif
-
-if CAIRO_HAS_PDF_SURFACE
-test_sources += $(pdf_surface_test_sources)
-endif
-
-if CAIRO_HAS_PS_SURFACE
-test_sources += $(ps_surface_test_sources)
-endif
-
-if CAIRO_HAS_SVG_SURFACE
-test_sources += $(svg_surface_test_sources)
-endif
-
-if CAIRO_HAS_TEST_SURFACES
-test_sources += $(test_fallback16_surface_test_sources)
-endif
-
-if CAIRO_HAS_XCB_SURFACE
-test_sources += $(xcb_surface_test_sources)
-endif
-
-if CAIRO_HAS_XLIB_SURFACE
-test_sources += $(xlib_surface_test_sources)
-endif
-
-if CAIRO_HAS_XLIB_XRENDER_SURFACE
-test_sources += $(xlib_xrender_surface_test_sources)
-endif
-
-if CAIRO_HAS_MULTI_PAGE_SURFACES
-test_sources += $(multi_page_surface_test_sources)
-endif
-
-# Include fallback-resolution (once!) if we have any of the vector surfaces
-if BUILD_ANY2PPM
-if CAIRO_HAS_SVG_SURFACE
-test = $(fallback_resolution_test_sources)
-endif
-if CAIRO_HAS_PDF_SURFACE
-test = $(fallback_resolution_test_sources)
-endif
-if CAIRO_HAS_PS_SURFACE
-test = $(fallback_resolution_test_sources)
-endif
-endif
-test_sources += $(test)
-
-noinst_PROGRAMS = cairo-test-suite$(EXEEXT) # always build
-noinst_SCRIPTS = check-refs.sh
-
-TESTS += cairo-test-suite$(EXEEXT)
-
-cairo-test-constructors.c: Makefile $(test_sources) make-cairo-test-constructors.sh
- (cd $(srcdir) && sh ./make-cairo-test-constructors.sh $(test_sources)) > $@ || (rm $@ ; exit 1)
-
-cairo_test_suite_SOURCES = \
- $(cairo_test_suite_sources) \
- $(cairo_test_suite_headers) \
- $(test_sources) \
- cairo-test-constructors.c
-cairo_test_suite_CFLAGS = $(AM_CFLAGS) $(real_pthread_CFLAGS)
-cairo_test_suite_LDADD = \
- $(real_pthread_LIBS) \
- $(top_builddir)/test/pdiff/libpdiff.la \
- $(top_builddir)/boilerplate/libcairoboilerplate.la \
- $(top_builddir)/src/libcairo.la \
- $(CAIRO_LDADD)
-cairo_test_suite_DEPENDENCIES = \
- $(top_builddir)/test/pdiff/libpdiff.la \
- $(top_builddir)/boilerplate/libcairoboilerplate.la \
- $(top_builddir)/src/libcairo.la
-if BUILD_ANY2PPM
-cairo_test_suite_DEPENDENCIES += \
- any2ppm$(EXEEXT)
-endif
-
-if HAVE_SHM
-EXTRA_PROGRAMS += cairo-test-trace
-cairo_test_trace_SOURCES = \
- cairo-test-trace.c \
- buffer-diff.c \
- buffer-diff.h
-cairo_test_trace_CFLAGS = $(AM_CFLAGS) $(real_pthread_CFLAGS)
-cairo_test_trace_LDADD = \
- $(real_pthread_LIBS) \
- $(top_builddir)/test/pdiff/libpdiff.la \
- $(top_builddir)/util/cairo-script/libcairo-script-interpreter.la \
- $(top_builddir)/boilerplate/libcairoboilerplate.la \
- $(top_builddir)/src/libcairo.la \
- $(top_builddir)/util/cairo-missing/libcairo-missing.la \
- $(CAIRO_LDADD) \
- $(SHM_LIBS)
-cairo_test_trace_DEPENDENCIES = \
- $(top_builddir)/test/pdiff/libpdiff.la \
- $(top_builddir)/util/cairo-script/libcairo-script-interpreter.la \
- $(top_builddir)/boilerplate/libcairoboilerplate.la \
- $(top_builddir)/src/libcairo.la \
- $(top_builddir)/util/cairo-missing/libcairo-missing.la \
- $(NULL)
-endif
-
-BUILT_SOURCES += cairo-test-constructors.c
-EXTRA_DIST += $(BUILT_SOURCES) $(noinst_SCRIPTS) COPYING make-cairo-test-constructors.sh run-cairo-test-suite.sh generate_refs.sh tiger.inc
-CLEANFILES += $(BUILT_SOURCES)
-
-EXTRA_DIST += \
-6x13.pcf \
-index.html \
-jp2.jp2 \
-jpeg.jpg \
-png.png \
-romedalen.jpg \
-romedalen.png \
-scarab.jpg \
-surface-source.c \
-testtable.js \
-reference
-
-# Any test that doesn't generate a log file goes here
-NOLOG_TESTS = \
-fallback-resolution \
-font-options \
-multi-page \
-pdf-features \
-png \
-ps-eps \
-ps-features \
-svg-clip \
-svg-surface \
-toy-font-face \
-font-variations \
-user-data
-
-# A target to summarise the failures
-check-summary:
- @FAILED_TESTS=""; \
- for t in output/*.log; do \
- if grep -e '\<FAIL\>' $$t >/dev/null 2>&1; then \
- FAILED_TESTS="$$FAILED_TESTS $$t"; \
- fi; \
- done; \
- if test -n "$$FAILED_TESTS"; then \
- echo "Failed tests:"; \
- surfaces=""; \
- for t in $$FAILED_TESTS; do \
- name="$${t##output/}"; name="$${name%.log}"; \
- echo -n " $$name: "; \
- grep -e '\<FAIL\>' $$t | sed -e 's/.*TARGET: \([^ ]*\).*/\1/' | sort | uniq | tr '\n' ' '; \
- echo; \
- for s in `grep -e '\<FAIL\>' $$t | sed -e 's/.*TARGET: \([^ ]*\).*/\1/' | sort | uniq`; do \
- ss=`echo $$s | tr '-' '_'`; \
- tt=`echo $$name | tr '-' '_'`; \
- eval $$ss=\""$${!ss} $$tt"\"; \
- echo $$surfaces | grep $$ss >/dev/null || surfaces="$$surfaces $$ss"; \
- done; \
- done; \
- echo -n "Failures per surface - "; \
- first=""; \
- for s in $$surfaces; do \
- ss=`echo $$s | tr '_' '-'`; \
- test -n "$$first" && echo -n ", "; \
- cnt=`echo $${!s} | wc -w`; \
- echo -n "$$ss: $$cnt"; \
- first="false"; \
- done; \
- echo "."; \
- for s in $$surfaces; do \
- ss=`echo $$s | tr '_' '-'`; \
- cnt=`echo $${!s} | wc -w`; \
- echo -n " $$ss [$$cnt]: "; \
- echo $${!s} | tr '_' '-'; \
- done; \
- fi
-
-AM_CPPFLAGS = \
- -I$(srcdir) \
- -I$(srcdir)/pdiff \
- -I$(top_srcdir)/boilerplate \
- -I$(top_srcdir)/util/cairo-missing \
- -I$(top_srcdir)/util/cairo-script \
- -I$(top_srcdir)/src \
- -I$(top_builddir)/src \
- $(CAIRO_CFLAGS)
-AM_LDFLAGS = $(CAIRO_LDFLAGS)
-
-$(top_builddir)/boilerplate/libcairoboilerplate.la: $(top_builddir)/src/libcairo.la
- cd $(top_builddir)/boilerplate && $(MAKE) $(AM_MAKEFLAGS) libcairoboilerplate.la
-
-$(top_builddir)/src/libcairo.la:
- cd $(top_builddir)/src && $(MAKE) $(AM_MAKEFLAGS) libcairo.la
-
-$(top_builddir)/test/pdiff/libpdiff.la:
- cd $(top_builddir)/test/pdiff && $(MAKE) $(AM_MAKEFLAGS) libpdiff.la
-
-$(top_builddir)/test/pdiff/perceptualdiff:
- cd $(top_builddir)/test/pdiff && $(MAKE) $(AM_MAKEFLAGS) perceptualdiff
-
-$(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 = \
- imagediff.c \
- buffer-diff.c \
- buffer-diff.h
-imagediff_LDADD = \
- $(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)
-
-if BUILD_ANY2PPM
-check_PROGRAMS += any2ppm
-any2ppm_CFLAGS = $(AM_CFLAGS) $(POPPLER_CFLAGS) $(LIBRSVG_CFLAGS) $(LIBSPECTRE_CFLAGS)
-# add LDADD, so poppler/librsvg uses "our" cairo
-any2ppm_LDFLAGS = $(AM_LDFLAGS) $(CAIRO_TEST_UNDEFINED_LDFLAGS)
-any2ppm_LDADD = \
- $(top_builddir)/util/cairo-script/libcairo-script-interpreter.la \
- $(top_builddir)/src/libcairo.la \
- $(CAIRO_LDADD) \
- $(CAIROBOILERPLATE_LIBS) \
- $(POPPLER_LIBS) \
- $(LIBRSVG_LIBS) \
- $(LIBSPECTRE_LIBS)
-endif
-
-if CAIRO_CAN_TEST_PDF_SURFACE
-check_PROGRAMS += pdf2png
-pdf2png_CFLAGS = $(AM_CFLAGS) $(POPPLER_CFLAGS)
-# add LDADD, so poppler uses "our" cairo
-pdf2png_LDFLAGS = $(AM_LDFLAGS) $(CAIRO_TEST_UNDEFINED_LDFLAGS)
-pdf2png_LDADD = $(top_builddir)/src/libcairo.la \
- $(CAIRO_LDADD) \
- $(POPPLER_LIBS)
-endif
-
-if CAIRO_CAN_TEST_SVG_SURFACE
-check_PROGRAMS += svg2png
-svg2png_CFLAGS = $(AM_CFLAGS) $(LIBRSVG_CFLAGS)
-# add LDADD, so librsvg uses "our" cairo
-svg2png_LDFLAGS = $(AM_LDFLAGS) $(CAIRO_TEST_UNDEFINED_LDFLAGS)
-svg2png_LDADD = $(top_builddir)/src/libcairo.la \
- $(CAIRO_LDADD) \
- $(LIBRSVG_LIBS)
-endif
-
-if CAIRO_HAS_SPECTRE
-check_PROGRAMS += ps2png
-ps2png_CFLAGS = $(AM_CFLAGS) $(LIBSPECTRE_CFLAGS)
-# add LDADD, so ps2png uses "our" cairo
-ps2png_LDFLAGS = $(AM_LDFLAGS) $(CAIRO_TEST_UNDEFINED_LDFLAGS)
-ps2png_LDADD = $(top_builddir)/src/libcairo.la \
- $(CAIRO_LDADD) \
- $(LIBSPECTRE_LIBS)
-endif
-
-EXTRA_PROGRAMS += $(TESTS)
-
-# Do a funny transition of CAIRO_TEST_TARGET through TARGETS such that
-# one can limit tested targets both through CAIRO_TEST_TARGET env var
-# and TARGETS make var on the command line. Same for the rest.
-TARGETS = $(CAIRO_TEST_TARGET)
-TARGETS_EXCLUDE = $(CAIRO_TEST_TARGET_EXCLUDE)
-FORMAT = $(CAIRO_TEST_TARGET_FORMAT)
-MODE = $(CAIRO_TEST_MODE)
-
-# Same about ENV vs CAIRO_TEST_ENV. ENV is used with "make run" only
-ENV = $(CAIRO_TEST_ENV)
-
-TESTS_ENVIRONMENT = CAIRO_TEST_MODE="$(MODE)" CAIRO_TEST_TARGET="$(TARGETS)" CAIRO_TEST_TARGET_FORMAT="$(FORMAT)" CAIRO_TEST_TARGET_EXCLUDE="$(TARGETS_EXCLUDE)" $(ENV)
-
-EXTRA_VALGRIND_FLAGS = $(CAIRO_EXTRA_VALGRIND_FLAGS)
-VALGRIND_FLAGS = \
- --tool=memcheck --suppressions=$(srcdir)/.valgrind-suppressions \
- --track-origins=yes \
- --leak-check=yes --show-reachable=yes \
- $(EXTRA_VALGRIND_FLAGS)
-
-CLEANFILES += \
- valgrind-log \
- ref.hash \
- ref.list \
- png-test.png \
- png.out.png \
- create-for-stream.pdf \
- create-for-stream.ps \
- create-for-stream.svg \
- svg-surface-source.out.svg \
- pdf-surface-source.out.pdf \
- ps-surface-source.out.ps \
- pdf-features.pdf \
- pdf-mime-data.out* \
- pdf-tagged-text.out* \
- ps-features.ps \
- svg-clip.svg \
- svg-surface.svg \
- multi-page.pdf \
- multi-page.ps \
- $(NULL)
-
-# This used to be a simple 'echo ${RM} *.ps *.pdf *.svg *.etc', but
-# most systems cannot handle all of our clean files together.
-# Then it became a fancy find using many GNU extensions, but then the ugly
-# reality of portability was raised and it became....
-clean-local:
- rm -rf output
- -${FIND} . -name '*.log' -print | ${XARGS} ${RM}
- -${FIND} . -name '*.[is]' -print | ${XARGS} ${RM}
-clean-caches:
- -${FIND} output -name '*.fail.*' -print | ${XARGS} ${RM}
- -${FIND} output -name '*.pass.*' -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`
-FAILED_TESTS = `grep -l '\<FAIL\>' $(test_sources:.c=.log) 2>/dev/null | tr '\n' ' ' | sed -e 's/[.]log */ /g; s/^ //; s/ $$//'`
-
-recheck = check CAIRO_TESTS="$(FAILED_TESTS)"
-
-# Re-checks all failed tests, i.e. tests with a log file that has a failure
-recheck:
- @echo Re-checking failed tests
- @$(MAKE) $(AM_MAKEFLAGS) $(recheck)
-
-# Checks tests.
-# Target doesn't fail if tests fail.
-test:
- @$(MAKE) $(AM_MAKEFLAGS) check
-
-# Re-checks tests.
-# Target doesn't fail if tests fail.
-retest:
- @CAIRO_TESTS="$(FAILED_TESTS)"; \
- $(MAKE) $(AM_MAKEFLAGS) check
-
-# Run tests under a tool specified by TOOL. For example, make run TOOL=gdb
-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:
- $(MAKE) $(AM_MAKEFLAGS) check TESTS_ENVIRONMENT='$(TESTS_ENVIRONMENT) CAIRO_TEST_MODE="$(MODE),foreground CAIRO_TEST_TIMEOUT=0" $(top_builddir)/libtool --mode=execute valgrind $(VALGRIND_FLAGS)' 2>&1 | tee valgrind-log
-
-#%.log: %.c cairo-test-suite
-#-./cairo-test-suite $(<:.c=)
-
-NOLOG_TESTS_LOG = $(NOLOG_TESTS:=.log)
-
-$(NOLOG_TESTS_LOG):
- @echo dummy > $@
-
-# Identify identical reference images
-check-ref-dups: check-refs.sh $(top_builddir)/test/pdiff/perceptualdiff
- sh $(srcdir)/check-refs.sh $(top_builddir)/test/pdiff/perceptualdiff
-
-# Remove identical reference images (DANGEROUS)
-clean-ref-dups: check-refs.sh $(top_builddir)/test/pdiff/perceptualdiff
- sh $(srcdir)/check-refs.sh | cut -d' ' -f2 | while read f; do git rm "reference/$$f"; done
-
-results.tar:
- @tar cf $@ index.html testtable.js *.log output/*.log; \
- for i in output/*.fail.png ; do \
- testname=$${i#output/} ; \
- testname=$${testname%%.*} ; \
- echo tar uf $@ reference/$${testname}*.ref.png $${i%fail.png}out.png $${i%fail.png}diff.png ; \
- tar uf $@ reference/$${testname}*.ref.png $${i%fail.png}out.png $${i%fail.png}diff.png ; \
- done
-
-results.tar.gz: results.tar
- gzip -c $< > $@
-
-release-verify-sane-tests:
-
-.PHONY: check-valgrind test recheck retest check-ref-dups release-verify-sane-tests
-
-EXTRA_DIST += Makefile.win32
diff --git a/test/Makefile.sources b/test/Makefile.sources
deleted file mode 100644
index 330aa9da1..000000000
--- a/test/Makefile.sources
+++ /dev/null
@@ -1,479 +0,0 @@
-test_sources = \
- a1-bug.c \
- a1-clip.c \
- a1-fill.c \
- a1-image-sample.c \
- a1-mask.c \
- a1-mask-sample.c \
- a1-sample.c \
- a1-traps-sample.c \
- a1-rasterisation.c \
- a8-clear.c \
- a8-mask.c \
- aliasing.c \
- alpha-similar.c \
- arc-direction.c \
- arc-infinite-loop.c \
- arc-looping-dash.c \
- api-special-cases.c \
- big-line.c \
- big-empty-box.c \
- big-empty-triangle.c \
- big-little-box.c \
- big-little-triangle.c \
- bug-spline.c \
- big-trap.c \
- bilevel-image.c \
- bug-40410.c \
- bug-361.c \
- bug-431.c \
- bug-448.c \
- bug-51910.c \
- bug-75705.c \
- bug-84115.c \
- bug-bo-rectangular.c \
- bug-bo-collins.c \
- bug-bo-ricotz.c \
- bug-source-cu.c \
- bug-extents.c \
- bug-seams.c \
- bug-image-compositor.c \
- caps.c \
- checkerboard.c \
- caps-joins.c \
- caps-joins-alpha.c \
- caps-joins-curve.c \
- caps-tails-curve.c \
- caps-sub-paths.c \
- clear.c \
- clear-source.c \
- clip-all.c \
- clip-complex-bug61592.c \
- clip-complex-shape.c \
- clip-contexts.c \
- clip-disjoint.c \
- clip-disjoint-hatching.c \
- clip-disjoint-quad.c \
- clip-device-offset.c \
- clip-double-free.c \
- clip-draw-unbounded.c \
- clip-empty.c \
- clip-empty-group.c \
- clip-empty-save.c \
- clip-fill.c \
- clip-fill-no-op.c \
- clip-fill-rule.c \
- clip-fill-rule-pixel-aligned.c \
- clip-group-shapes.c \
- clip-image.c \
- clip-intersect.c \
- clip-mixed-antialias.c \
- clip-nesting.c \
- clip-operator.c \
- clip-push-group.c \
- clip-polygons.c \
- clip-rectilinear.c \
- clip-shape.c \
- clip-stroke.c \
- clip-stroke-no-op.c \
- clip-text.c \
- clip-twice.c \
- clip-twice-rectangle.c \
- clip-unbounded.c \
- clip-zero.c \
- clipped-group.c \
- clipped-surface.c \
- close-path.c \
- close-path-current-point.c \
- composite-integer-translate-source.c \
- composite-integer-translate-over.c \
- composite-integer-translate-over-repeat.c \
- copy-disjoint.c \
- copy-path.c \
- coverage.c \
- create-for-stream.c \
- create-from-broken-png-stream.c \
- create-from-png.c \
- create-from-png-stream.c \
- culled-glyphs.c \
- curve-to-as-line-to.c \
- dash-caps-joins.c \
- dash-curve.c \
- dash-infinite-loop.c \
- dash-no-dash.c \
- dash-offset.c \
- dash-offset-negative.c \
- dash-scale.c \
- dash-state.c \
- dash-zero-length.c \
- degenerate-arc.c \
- degenerate-arcs.c \
- degenerate-curve-to.c \
- degenerate-dash.c \
- degenerate-linear-gradient.c \
- degenerate-path.c \
- degenerate-pen.c \
- degenerate-radial-gradient.c \
- degenerate-rel-curve-to.c \
- degenerate-solid-dash.c \
- drunkard-tails.c \
- device-offset.c \
- device-offset-fractional.c \
- device-offset-positive.c \
- device-offset-scale.c \
- error-setters.c \
- extend-pad.c \
- extend-pad-border.c \
- extend-pad-similar.c \
- extend-reflect.c \
- extend-reflect-similar.c \
- extend-repeat.c \
- extend-repeat-similar.c \
- extended-blend.c \
- fallback.c \
- fill-alpha.c \
- fill-alpha-pattern.c \
- fill-and-stroke.c \
- fill-and-stroke-alpha.c \
- fill-and-stroke-alpha-add.c \
- fill-degenerate-sort-order.c \
- fill-disjoint.c \
- fill-empty.c \
- fill-image.c \
- fill-missed-stop.c \
- fill-rule.c \
- filter-bilinear-extents.c \
- filter-nearest-offset.c \
- filter-nearest-transformed.c \
- finer-grained-fallbacks.c \
- font-face-get-type.c \
- font-matrix-translation.c \
- font-options.c \
- glyph-cache-pressure.c \
- get-and-set.c \
- get-clip.c \
- get-group-target.c \
- get-path-extents.c \
- gradient-alpha.c \
- gradient-constant-alpha.c \
- gradient-zero-stops.c \
- gradient-zero-stops-mask.c \
- group-clip.c \
- group-paint.c \
- group-state.c \
- group-unaligned.c \
- hairline.c \
- half-coverage.c \
- halo.c \
- hatchings.c \
- horizontal-clip.c \
- huge-linear.c \
- huge-radial.c \
- image-surface-source.c \
- image-bug-710072.c \
- implicit-close.c \
- infinite-join.c \
- in-fill-empty-trapezoid.c \
- in-fill-trapezoid.c \
- invalid-matrix.c \
- inverse-text.c \
- inverted-clip.c \
- joins.c \
- joins-loop.c \
- joins-star.c \
- joins-retrace.c \
- large-clip.c \
- large-font.c \
- large-source.c \
- large-source-roi.c \
- large-twin-antialias-mixed.c \
- leaky-dash.c \
- leaky-dashed-rectangle.c \
- leaky-dashed-stroke.c \
- leaky-polygon.c \
- line-width.c \
- line-width-large-overlap.c \
- line-width-overlap.c \
- line-width-scale.c \
- line-width-tolerance.c \
- line-width-zero.c \
- linear-gradient.c \
- linear-gradient-extend.c \
- linear-gradient-large.c \
- linear-gradient-one-stop.c \
- linear-gradient-reflect.c \
- linear-gradient-subset.c \
- linear-step-function.c \
- linear-uniform.c \
- long-dashed-lines.c \
- long-lines.c \
- map-to-image.c \
- mask.c \
- mask-alpha.c \
- mask-ctm.c \
- mask-glyphs.c \
- mask-surface-ctm.c \
- mask-transformed-image.c \
- mask-transformed-similar.c \
- mesh-pattern.c \
- mesh-pattern-accuracy.c \
- mesh-pattern-conical.c \
- mesh-pattern-control-points.c \
- mesh-pattern-fold.c \
- mesh-pattern-overlap.c \
- mesh-pattern-transformed.c \
- mime-data.c \
- mime-surface-api.c \
- miter-precision.c \
- move-to-show-surface.c \
- negative-stride-image.c \
- new-sub-path.c \
- nil-surface.c \
- operator.c \
- operator-alpha.c \
- operator-alpha-alpha.c \
- operator-clear.c \
- operator-source.c \
- operator-www.c \
- outline-tolerance.c \
- overflow.c \
- over-above-source.c \
- over-around-source.c \
- over-below-source.c \
- over-between-source.c \
- overlapping-boxes.c \
- overlapping-glyphs.c \
- overlapping-dash-caps.c \
- paint.c \
- paint-clip-fill.c \
- paint-repeat.c \
- paint-source-alpha.c \
- paint-with-alpha.c \
- paint-with-alpha-group-clip.c \
- partial-clip-text.c \
- partial-coverage.c \
- pass-through.c \
- path-append.c \
- path-currentpoint.c \
- path-stroke-twice.c \
- path-precision.c \
- pattern-get-type.c \
- pattern-getters.c \
- pdf-isolated-group.c \
- pixman-downscale.c \
- pixman-rotate.c \
- png.c \
- push-group.c \
- push-group-color.c \
- push-group-path-offset.c \
- radial-gradient.c \
- radial-gradient-extend.c \
- radial-outer-focus.c \
- random-clips.c \
- random-intersections-eo.c \
- random-intersections-nonzero.c \
- random-intersections-curves-eo.c \
- random-intersections-curves-nz.c \
- raster-source.c \
- record.c \
- record1414x.c \
- record2x.c \
- record90.c \
- recordflip.c \
- record-extend.c \
- record-neg-extents.c \
- record-mesh.c \
- record-replay-extend.c \
- record-transform-paint.c \
- record-write-png.c \
- recording-ink-extents.c \
- recording-surface-pattern.c \
- recording-surface-extend.c \
- rectangle-rounding-error.c \
- rectilinear-fill.c \
- rectilinear-grid.c \
- rectilinear-miter-limit.c \
- rectilinear-dash.c \
- rectilinear-dash-scale.c \
- rectilinear-stroke.c \
- reflected-stroke.c \
- rel-path.c \
- rgb24-ignore-alpha.c \
- rotate-image-surface-paint.c \
- rotate-stroke-box.c \
- rotated-clip.c \
- rounded-rectangle-fill.c \
- rounded-rectangle-stroke.c \
- sample.c \
- scale-down-source-surface-paint.c \
- scale-offset-image.c \
- scale-offset-similar.c \
- scale-source-surface-paint.c \
- scaled-font-zero-matrix.c \
- stroke-ctm-caps.c \
- stroke-clipped.c \
- stroke-image.c \
- stroke-open-box.c \
- select-font-face.c \
- select-font-no-show-text.c \
- self-copy.c \
- self-copy-overlap.c \
- self-intersecting.c \
- set-source.c \
- show-glyphs-advance.c \
- show-glyphs-many.c \
- show-text-current-point.c \
- shape-general-convex.c \
- shape-sierpinski.c \
- shifted-operator.c \
- simple.c \
- skew-extreme.c \
- smask.c \
- smask-fill.c \
- smask-image-mask.c \
- smask-mask.c \
- smask-paint.c \
- smask-stroke.c \
- smask-text.c \
- smp-glyph.c \
- solid-pattern-cache-stress.c \
- source-clip.c \
- source-clip-scale.c \
- source-surface-scale-paint.c \
- spline-decomposition.c \
- stride-12-image.c \
- stroke-pattern.c \
- subsurface.c \
- subsurface-image-repeat.c \
- subsurface-repeat.c \
- subsurface-reflect.c \
- subsurface-pad.c \
- subsurface-modify-child.c \
- subsurface-modify-parent.c \
- subsurface-outside-target.c \
- subsurface-scale.c \
- subsurface-similar-repeat.c \
- surface-finish-twice.c \
- surface-pattern.c \
- surface-pattern-big-scale-down.c \
- surface-pattern-operator.c \
- surface-pattern-scale-down.c \
- surface-pattern-scale-down-extend.c \
- surface-pattern-scale-up.c \
- text-antialias.c \
- text-antialias-subpixel.c \
- text-cache-crash.c \
- text-glyph-range.c \
- text-pattern.c \
- text-rotate.c \
- text-subpixel.c \
- text-transform.c \
- text-unhinted-metrics.c \
- text-zero-len.c \
- thin-lines.c \
- tighten-bounds.c \
- tiger.c \
- toy-font-face.c \
- transforms.c \
- translate-show-surface.c \
- trap-clip.c \
- twin.c \
- twin-antialias-gray.c \
- twin-antialias-mixed.c \
- twin-antialias-none.c \
- twin-antialias-subpixel.c \
- unaligned-box.c \
- unantialiased-shapes.c \
- unbounded-operator.c \
- unclosed-strokes.c \
- user-data.c \
- user-font.c \
- user-font-color.c \
- user-font-mask.c \
- user-font-proxy.c \
- user-font-rescale.c \
- user-font-subpixel.c \
- world-map.c \
- white-in-noop.c \
- xcb-huge-image-shm.c \
- xcb-huge-subimage.c \
- xcb-stress-cache.c \
- xcb-snapshot-assert.c \
- xcomposite-projection.c \
- xlib-expose-event.c \
- zero-alpha.c \
- zero-mask.c
-
-pthread_test_sources = \
- pthread-same-source.c \
- pthread-show-text.c \
- pthread-similar.c \
- $(NULL)
-
-ft_font_test_sources = \
- font-variations.c
-
-fc_font_test_sources = \
- bitmap-font.c \
- ft-color-font.c \
- ft-font-create-for-ft-face.c \
- ft-show-glyphs-positioning.c \
- ft-show-glyphs-table.c \
- ft-text-vertical-layout-type1.c \
- ft-text-vertical-layout-type3.c \
- ft-text-antialias-none.c
-
-gl_surface_test_sources = \
- gl-device-release.c \
- gl-oversized-surface.c \
- gl-surface-source.c
-
-egl_surface_test_sources = \
- egl-oversized-surface.c \
- egl-surface-source.c
-
-quartz_surface_test_sources = quartz-surface-source.c
-
-quartz_color_font_test_sources = quartz-color-font.c
-
-pdf_surface_test_sources = \
- pdf-features.c \
- pdf-mime-data.c \
- pdf-operators-text.c \
- pdf-surface-source.c \
- pdf-tagged-text.c
-
-ps_surface_test_sources = \
- ps-eps.c \
- ps-features.c \
- ps-surface-source.c
-
-svg_surface_test_sources = \
- svg-surface.c \
- svg-clip.c \
- svg-surface-source.c
-
-xcb_surface_test_sources = \
- xcb-surface-source.c
-
-xlib_surface_test_sources = \
- xlib-surface.c \
- xlib-surface-source.c
-
-xlib_xrender_surface_test_sources = get-xrender-format.c
-
-multi_page_surface_test_sources = multi-page.c mime-unique-id.c
-
-fallback_resolution_test_sources = fallback-resolution.c
-
-cairo_test_suite_headers = \
- buffer-diff.h \
- cairo-test.h \
- cairo-test-private.h \
- world-map.h \
- $(NULL)
-
-cairo_test_suite_sources = \
- buffer-diff.c \
- cairo-test.c \
- cairo-test-runner.c
diff --git a/test/Makefile.win32 b/test/Makefile.win32
deleted file mode 100644
index ba8ea5b86..000000000
--- a/test/Makefile.win32
+++ /dev/null
@@ -1,55 +0,0 @@
-top_srcdir = ..
-include $(top_srcdir)/build/Makefile.win32.common
-include $(top_srcdir)/test/Makefile.sources
-
-CFLAGS += \
- -I$(top_srcdir)/boilerplate \
- -I$(top_srcdir)/util/cairo-script/ \
- -I./pdiff \
- $(NULL)
-
-TEST_LIBS = \
- ./pdiff/$(CFG)/pdiff.lib \
- $(top_builddir)/boilerplate/$(CFG)/boiler.lib \
- $(top_builddir)/src/$(CFG)/cairo-static.lib \
- $(NULL)
-
-all: inform $(CFG)/cairo-test-suite.exe
-
-cairo-test-constructors.c: Makefile.sources Makefile.win32 $(test_sources) make-cairo-test-constructors.sh
- sh ./make-cairo-test-constructors.sh $(test_sources) > $@
-
-SOURCES = $(cairo_test_suite_sources) $(test_sources) cairo-test-constructors.c
-
-OBJECTS = $(patsubst %.c, $(CFG)/%-static.obj, $(SOURCES))
-
-ANY2PPM_OBJS = \
- $(CFG)/any2ppm-static.obj \
- $(top_builddir)/util/cairo-script/$(CFG)/libcairo-script-interpreter.lib \
- $(top_builddir)/src/$(CFG)/cairo-static.lib \
- $(NULL)
-
-$(CFG)/cairo-test-suite.exe: $(OBJECTS) $(TEST_LIBS)
- @$(LD) $(CAIRO_LDFLAGS) -OUT:$@ $(OBJECTS) $(TEST_LIBS) $(CAIRO_LIBS)
-
-$(CFG)/any2ppm.exe: $(ANY2PPM_OBJS)
- $(LD) $(CAIRO_LDFLAGS) -OUT:$@ $^ $(CAIRO_LIBS)
-
-./pdiff/$(CFG)/pdiff.lib:
- $(MAKE) -C pdiff -f Makefile.win32
-
-$(top_builddir)/src/$(CFG)/cairo-static.lib:
- $(MAKE) -C $(top_srcdir)/src -f Makefile.win32
-
-$(top_builddir)/boilerplate/$(CFG)/boiler.lib:
- $(MAKE) -C $(top_srcdir)/boilerplate -f Makefile.win32
-
-$(top_builddir)/util/cairo-script/$(CFG)/libcairo-script-interpreter.lib:
- $(MAKE) -C $(top_srcdir)/util/cairo-script -f Makefile.win32
-
-.PHONY: check test
-
-check: inform $(CFG)/any2ppm.exe $(CFG)/cairo-test-suite.exe
- @ANY2PPM=$(CFG)\\any2ppm.exe $(CFG)/cairo-test-suite.exe
-
-test: inform check
diff --git a/test/README b/test/README
index ea775cfcd..e8b5ff6cc 100644
--- a/test/README
+++ b/test/README
@@ -1,108 +1,168 @@
-Regression test suite for cairo.
-
How to use cairo's test suite
=============================
Using this test should be as simple as running:
- make test
+ meson test -C $builddir -v
assuming that the cairo distribution in the directory above has been
-configured and built. The test suite here goes through some effort to
-run against the locally compiled library rather than any installed
-version, but those efforts may fall short depending on the level of your
-libtool madness.
+configured and built in $builddir. The test suite here will use the
+locally compiled library rather than installed version.
+
+The above command runs some source code as well as the rendering
+tests. All the rendering tests are in a single meson test named
+"cairo". It can be run with:
-The results of the test suite run are summarized in an index.html
-file, which, when viewed in a web browser makes it quite easy to
-visually see any failed renderings alongside the corresponding
-reference image, (and a diff image as well).
+ meson test -C $builddir -v cairo
+
+The results of the test suite run are summarized in an index.html file
+written to $builddir, which, when viewed in a web browser makes it
+quite easy to visually see any failed renderings alongside the
+corresponding reference image, (and a diff image as well).
As some browsers do not permit Javascript to read from the local
-filesystem, the view-test-results.py script can used to view the
-results. It starts a http server serving the current directory before
-displaying the test results in a browser.
+filesystem, the view-test-results.py script in the $builddir can used
+to view the results. It starts a http server serving the current
+directory before displaying the test results in a browser.
The test suite needs to be run before any code is committed and before
any release. See below for hints and rules governing the use of the suite.
-The test suite is built as a single binary, which allows you to choose
-individual or categories of tests to run. For example, to run specific tests:
- ./cairo-test-suite record-neg-extents-unbounded record-neg-extents-bounded
-Or if you want to run all paint.* related tests you can use:
- ./cairo-test-suite paint
-Or if you want to check the current status of known failures:
- ./cairo-test-suite XFAIL
-Or to run a subset of tests, use the -k option to run only the tests
-that include the given keyword:
- ./cairo-test-suite -k downscale
-The binary also permits controlling which backend is used via the
-CAIRO_TEST_TARGET environment variable, so for instance:
- CAIRO_TEST_TARGET=gl ./cairo-test-suite -k blur
-This binary should be backwards-compatible with all library versions,
-allowing you to compare current versus past behaviour for any test.
-
-The test suite needs to find the "test" directory in the source
-tree. The srcdir environment variable can be used to specify
-the location of this directory. If this environment variable is not
-set, the binary looks for the directory "srcdir" in the current
-directory. The meson build system symlinks "srcdir" in the
-$builddir/test directory to the "test" directory in the source
-tree. If this is not found the binary defaults to the current
-directory.
-
-Tailoring tests running
------------------------
-There are some mechanisms to limit the tests run during "make test".
-These come very handy when doing development, but should not be used
-to circumvent the "pass" requirements listed below.
+Running specific tests
+----------------------
+During development it is desirable to only run a single test or groups
+of related tests. Individual tests can be run by specifying the tests
+names as arguments to the cairo test.
+
+ meson test -v cairo --test-args "record-neg-extents-unbounded record-neg-extents-bounded"
-make's TARGETS environment variable can be used to limit the backends when
-running the tests. It should contain a (space-, comma-separated) list of
-backends. CAIRO_TESTS environment variable, which is a comma-, space-seperated
-lists, can be used to limit the tests run.
-For example:
+The test suite is built as a single binary, "cairo-test-suite", which
+can be run directly instead of via meson. This may be more convenient
+when specifying multiple test arguments. The executable needs to be
+run in $builddir/test in order to find the image conversion
+executables. Simply running the executable will run all tests. eg
- CAIRO_TESTS="zero-alpha" make test TARGETS=image,ps
+ cd $builddir/test
+ ./cairo-test-suite
-make's FORMAT variable can also be used to limit the content formats when
-running the tests. It should contain a (space-, comma-separated) list of
-content formats to test.
-For example:
+Normally the executable will use the locally compiled library. But if
+you have a LD_LIBRARY_PATH defined or built cairo with an -rpath, the
+executable may not link with the locally compiled library.
- CAIRO_TESTS="zero-alpha" make test TARGETS=image,ps FORMAT="rgb,rgba"
+Individual tests can be run be specifying the tests names as arguments
+to cairo-test-suite. For example, to run specific tests:
-Another very handy mechanism when trying to fix bugs is:
+ ./cairo-test-suite record-neg-extents-unbounded record-neg-extents-bounded
- make retest
+Or if you want to run all paint.* related tests you can use:
-This will re-run the test suite, but only on tests that failed on the
-last run. So this is a much faster way of checking if changes actually
-fix bugs rather than running the entire test suite again.
+ ./cairo-test-suite paint
-The test suite first compares the output from the current run against the
-previous in order to skip more expensive image comparisons . If you think
-this is interfering with the results, you can clear the cached results using:
+Or if you want to check the current status of known failures:
- make clean-caches
+ ./cairo-test-suite XFAIL
-Running tests under modified environments or tools
--------------------------------------------------
-To run tests under a tool like gdb, one can use the run target and
-the TOOL variable. For example:
+Or to run a subset of tests, use the -k option to run only the tests
+that include the given keyword:
+
+ ./cairo-test-suite -k downscale
- CAIRO_TESTS=user-font make run TOOL=gdb TARGETS=pdf
+The -l option lists all tests available. For convenience, the file
+"completion.bash" in $builddir can be sourced to provide bash
+completion of the test names in cairo-test-suite.
-If you want to run under valgrind, there is a specific target for that
-that also sets a bunch of useful valgrind options. Try:
+By default, each test that is run will be tested on all backends that
+have been built. The CAIRO_TEST_TARGET environment variable can be
+used to select specific backends. For example:
- CAIRO_TESTS=user-font make check-valgrind
+ CAIRO_TEST_TARGET=pdf ./cairo-test-suite text-rotate
-You can run tests under a modified environment you can use the ENV
-make variable. However, that environment will also affect the libtool
-wrapper of the tests. To only affect the actual test binaries, pass
-such environment as TOOL:
+Each test is run twice on each backend, once for each format. The
+CAIRO_TEST_TARGET_FORMAT environment variable selects a single
+format. The formats are "rgba" and "rgb". For example to run the
+text-rotate test only on the image backend and only for the "rgba"
+format:
- CAIRO_TESTS=user-font make run TOOL="LD_PRELOAD=/path/to/something.so"
+ CAIRO_TEST_TARGET=image CAIRO_TEST_TARGET_FORMAT=rgba ./cairo-test-suite text-rotate
+
+Running tests under modified environments or tools
+--------------------------------------------------
+To run tests under in gdb, one can simply run the cairo-suite-suite in
+gdb. Usually a specific test will be desired. eg
+
+ CAIRO_TEST_TARGET=image CAIRO_TEST_TARGET_FORMAT=rgba gdb --args ./cairo-test-suite text-rotate
+
+The cairo test suite runs each test in a child process so that crashes
+do not stop the test. When running the test suite under tools, the "-f"
+option disables forking. eg to run a test under valgrind:
+
+ CAIRO_TEST_TARGET=image CAIRO_TEST_TARGET_FORMAT=rgba valgrind ./cairo-test-suite -f text-rotate
+
+The cairo test suite detects if it is running under gdb and disables
+forking. Hence the reason the gdb example above did not use "-f".
+
+Complete list of test options
+-----------------------------
+cairo-test-suite options:
+
+ ./cairo-test-suite [-afkxsl] [test-names|keywords ...]
+
+ -a all; run the full set of tests. By default the test suite
+ skips similar surface and device offset testing.
+ -f foreground; do not fork
+ -k match tests by keyword
+ -l list only; just list selected test case names without executing
+ -s include slow, long running tests
+ -x exit on first failure
+
+Environment Variables:
+
+CAIRO_TEST_TARGET
+ Run the test only the the listed targets. eg
+ CAIRO_TEST_TARGET="image"
+ CAIRO_TEST_TARGET="pdf,ps3,ps2"
+
+CAIRO_TEST_TARGET_FORMAT
+ Run the test only the the listed targets. eg
+ CAIRO_TEST_TARGET_FORMAT="rgba"
+ CAIRO_TEST_TARGET_FORMAT="rgba,rgb"
+
+CAIRO_TEST_MODE
+ May contain a list of one or more of the following options
+ "full" - equivalent to the "-a" option
+ "similar"
+ "offset"
+ "scale"
+ "foreground" - equivalent to the "-f" option
+ "exit-on-failure" - equivalent to the "-x" option
+ eg
+ CAIRO_TEST_MODE="full,foreground"
+
+CAIRO_TESTS
+ A list of test to run. This is equivalent to listing the tests as
+ arguments to cairo=test-suite. eg
+ CAIRO_TESTS="record-neg-extents-unbounded record-neg-extents-bounded"
+ The tests may be separated by any of " \t,:;".
+
+srcdir
+ The test suite needs to find the "test" directory in the source
+ tree. The srcdir environment variable can be used to specify the
+ location of this directory. If this environment variable is not set,
+ the binary looks for the directory "srcdir" in the current
+ directory. The meson build system symlinks "srcdir" in the
+ $builddir/test directory to the "test" directory in the source
+ tree. If this is not found the binary defaults to the current
+ directory.
+
+CAIRO_REF_DIR
+ The directory containing the reference images. By default the test
+ suite looks for "reference" in $srcdir. For convenience, you can set
+ CAIRO_REF_DIR to point at a previous test directory, relative to the
+ current test directory, and any previous output will be used by
+ preference as reference images.
+
+CAIRO_TEST_TIMEOUT
+ The maximum time, in seconds, an indivdual test may run before it is
+ stopped. The default is 60 seconds.
Getting the elusive zero failures
---------------------------------
@@ -115,55 +175,10 @@ which the reference images were generated, then you will likely see
the test suite reporting "failures", (even if cairo is working just
fine).
-We are constantly working to reduce the number of variables that need
-to be tweaked to get a clean run, (for example, by bundling fonts with
-the test suite itself), and also working to more carefully document
-the software configuration used to generate the reference images.
-
-Here are some of the relevant details:
-
- * Your system must have a copy of the DejaVu font, the sha1sum of
- the version used are listed in [...]. These are
- "DejaVu Sans" (DejaVuSans.ttf) [e9831ee4fd2e1d0ac54508a548c6a449545eba3f];
- "DejaVu Sans Mono" (DejaVuSansMono.ttf) [25d854fbd0450a372615a26a8ef9a1024bd3efc6];
- "DejaVu Serif" (DejaVuSerif.ttf) [78a81850dc7883969042cf3d6dfd18eea7e43e2f];
- [the DejaVu fonts can be installed from the fonts-dejavu-core 2.34-1 Debian package]
- and also
- "Nimbus Sans L" (n019003l.pfb)
- [which can be found in the gsfonts Debian package].
-
- * Currently, you must be using a build of cairo using freetype
- (cairo-ft) as the default font backend. Otherwise all tests
- involving text are likely to fail.
-
- * To test the pdf backend, you will want the very latest version of
- poppler as made available via git:
-
- git clone git://anongit.freedesktop.org/git/poppler/poppler
-
- As of this writing, no released version of poppler contains all
- the fixes you will need to avoid false negatives from the test
- suite.
-
- * To test the ps backend, you will need ghostscript version 9.06.
-
- * Testing the xlib backend is problematic since many X server
- drivers have bugs that are exercised by the test suite. (Or, if
- not actual bugs, differ slightly in their output in such a way
- that the test suite will report errors.) This can be quite handy
- if you want to debug an X server driver, but since most people
- don't want to do that, another option is to run against a headless
- X server that uses only software for all rendering. One such X
- server is Xvfb which can be started like this:
-
- Xvfb -screen 0 1680x1024x24 -ac -nolisten tcp :2
-
- after which the test suite can be run against it like so:
-
- DISPLAY=:2 make test
-
- We have been using Xvfb for testing cairo releases and ensuring
- that all tests behave as expected with this X server.
+Since the test suite must pass the Continuous Integration test in the
+Gitlab instance hosting the cairo repository, the easiest way to get a
+new or updated test to pass is to extract the test output from the
+cairo gitlab CI to use as reference images.
What if I can't make my system match?
-------------------------------------
@@ -179,17 +194,18 @@ suite before your changes, and then use the CAIRO_REF_DIR environment
variable to use that output as the reference images for a run after
your changes. The process looks like this:
- # Before code change there may be failures we don't care about
- make test
+ # Before code change there may be failures we don't care about
+ cd $builddir/test
+ ./cairo-test-suite
- # Let's save those output images
- mkdir /some/directory/
- cp -r test/output /some/directory/
+ # Let's save those output images
+ mkdir /some/directory/
+ cp -r output /some/directory/
- # hack, hack, hack
+ # hack, hack, hack
- # Now to see if nothing changed:
- CAIRO_REF_DIR=/some/directory/ make test
+ # Now to see if nothing changed:
+ CAIRO_REF_DIR=/some/directory/ ./cairo-test-suite
Best practices for cairo developers
===================================
@@ -197,16 +213,67 @@ If we all follow the guidelines below, then both the test suite and
cairo itself will stay much healthier, and we'll all have a lot more
fun hacking on cairo.
-Before committing
------------------
-All tests should return a result of PASS or XFAIL. The XFAIL results
-indicate known bugs. The final message should be one of the following:
+Before creating a Merge Request
+-------------------------------
+After pushing your branch to your cairo fork on gitlab.freedesktop.org,
+check that the CI passes. A MR cannot be merged until the CI passes.
- All XX tests behaved as expected (YY expected failures)
- All XX tests passed
+It is likely that you will need to download test output images from
+the Gitlab CI to use as reference images in order to get CI to pass.
+
+The reference image filenames have the form:
+
+<test name>.*.ref.png for correct images that pass.
+
+<test name>.*.xfail.png for incorrect images due to bugs.
+
+The <test name>.ref.png is the most general image that all backends
+and formats for the <test name> test will be required to match.
+
+When comparing test output to the reference images, the test suite
+performs a perceptual diff which permits some minor pixel differences
+that are not visually discernible. Some targets may have differences
+that exceed the threshold of the perceptual diff but still appear the
+same as the reference image when eyeballed. In these cases, target
+specific reference images can be created that override the general
+reference image for the specific target.
+
+Reference images for specific backends can be created using filenames of the form:
+ <test name>.<target>.ref.png
+
+eg clip.pdf.ref.png
+
+The target name "ps" can be used for both "ps2" and "ps3" targets.
+
+Reference images for specific formats can be created using filenames of the form:
+ <test name>.<target>.<format>.ref.png
-If any tests have a status of FAIL, then the new code has caused a
-regression error which should be fixed before the code is committed.
+eg
+ clip.pdf.argb32.ref.png
+ clip.pdf.rgb24.ref.png
+
+The recommended practice for creating reference images for a new test is:
+
+1. Create a <test name>.ref.png reference image from <test name>.image.argb32.out.png
+output.
+
+2. Push to gitlab and check the CI result.
+
+3. If the image target fails, copy the <test name>.image.argb32.out.png output
+from CI and use as the reference image.
+
+4. Once the image target passes in CI, check that the other targets
+pass. If any fail, create <test name>.<target>.ref.png reference images if the
+output appears correct.
+
+5. If a target output is incorrect, try to determine if the cairo
+target output is correct. eg view pdf files in Adobe Reader. If the
+cairo target output is correct, it can be assumed the image converson
+from target to png is buggy. File a bug against the conversion tool
+and create a <test name>.<target>.xfail.png reference image.
+
+In all cases, before creating a reference image from test output, the
+image should be viewed to ensure that it is correct.
When a new bug is found
-----------------------
@@ -222,7 +289,7 @@ the style of existing tests. The new-bug.ref.png image should contain
the desired result of new-bug.c if the bug were fixed while
new-bug.xfail.png contains the current results of the test.
-Makefile.sources should be edited by adding new-bug.c to test_sources.
+"meson.build" should be edited by adding new-bug.c to test_sources.
And last but not least, don't forget to "git add" the new files.
When a new feature is added
@@ -263,34 +330,14 @@ PostScript, and SVG), into an image that can be used for the image
comparison. This means that any bugs in that conversion tool will
result in false negatives in the test suite.
-We've identified several such bugs in the poppler library which is
-used to convert PDF to an image. This is particularly discouraging
-because 1) poppler is free software that will be used by *many* cairo
-users, and 2) poppler calls into cairo for its rendering so it should
-be able to do a 100% faithful conversion.
-
-So we have an interest in ensuring that these poppler bugs get fixed
-sooner rather than later. As such, we're trying to be good citizens by
-reporting all such poppler bugs that we identify to the poppler
-bugzilla. Here's a tracking bug explaining the situation:
-
- Poppler does not yet handle everything in the cairo test suite
- https://bugs.freedesktop.org/show_bug.cgi?id=12143
-
Here's the rule: If a cairo-pdf test reports a failure, but viewing
the resulting PDF file with acroread suggests that the PDF itself is
correct, then there's likely a bug in poppler. In this case, we can
-simply report the poppler bug, (making it block 12143 above), post the
-PDF result from the test suite, and list the bug in this file. Once
-we've done this, we can capture poppler's buggy output as a
-pdf-specific reference image (as reference/*.xfail.png) so that the
-test suite will regard the test as passing, (and we'll ensure there
-is no regression).
+simply report the poppler bug. Once we've done this, we can capture
+poppler's buggy output as a pdf-specific reference image (as
+reference/*.xfail.png) so that the test suite will regard the test as
+passing, (and we'll ensure there is no regression).
Once the poppler bug gets fixed, the test suite will start reporting a
false negative again, and this will be easy to fix by simply removing
the pdf-specific reference image.
-
-Here are the reported poppler bugs and the tests they affect:
-
-[Newest was closed in 2009.]
diff --git a/test/api-special-cases.c b/test/api-special-cases.c
index ce54200b7..d926aa652 100644
--- a/test/api-special-cases.c
+++ b/test/api-special-cases.c
@@ -63,9 +63,6 @@
#include "cairo-test.h"
-#if CAIRO_HAS_GL_SURFACE
-#include <cairo-gl.h>
-#endif
#if CAIRO_HAS_PDF_SURFACE
#include <cairo-pdf.h>
#endif
@@ -1312,38 +1309,6 @@ test_cairo_tee_surface_index (cairo_surface_t *surface)
#endif /* CAIRO_HAS_TEE_SURFACE */
-#if CAIRO_HAS_GL_SURFACE
-
-static cairo_test_status_t
-test_cairo_gl_surface_set_size (cairo_surface_t *surface)
-{
- cairo_gl_surface_set_size (surface, 5, 5);
- return CAIRO_TEST_SUCCESS;
-}
-
-static cairo_test_status_t
-test_cairo_gl_surface_get_width (cairo_surface_t *surface)
-{
- unsigned int width = cairo_gl_surface_get_width (surface);
- return width == 0 || surface_has_type (surface, CAIRO_SURFACE_TYPE_GL) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
-}
-
-static cairo_test_status_t
-test_cairo_gl_surface_get_height (cairo_surface_t *surface)
-{
- unsigned int height = cairo_gl_surface_get_height (surface);
- return height == 0 || surface_has_type (surface, CAIRO_SURFACE_TYPE_GL) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR;
-}
-
-static cairo_test_status_t
-test_cairo_gl_surface_swapbuffers (cairo_surface_t *surface)
-{
- cairo_gl_surface_swapbuffers (surface);
- return CAIRO_TEST_SUCCESS;
-}
-
-#endif /* CAIRO_HAS_GL_SURFACE */
-
#if CAIRO_HAS_PDF_SURFACE
static cairo_test_status_t
@@ -1675,12 +1640,6 @@ struct {
TEST (cairo_tee_surface_remove, CAIRO_SURFACE_TYPE_TEE, TRUE),
TEST (cairo_tee_surface_index, CAIRO_SURFACE_TYPE_TEE, FALSE),
#endif
-#if CAIRO_HAS_GL_SURFACE
- TEST (cairo_gl_surface_set_size, CAIRO_SURFACE_TYPE_GL, TRUE),
- TEST (cairo_gl_surface_get_width, CAIRO_SURFACE_TYPE_GL, FALSE),
- TEST (cairo_gl_surface_get_height, CAIRO_SURFACE_TYPE_GL, FALSE),
- TEST (cairo_gl_surface_swapbuffers, CAIRO_SURFACE_TYPE_GL, TRUE),
-#endif
#if CAIRO_HAS_PDF_SURFACE
TEST (cairo_pdf_surface_restrict_to_version, CAIRO_SURFACE_TYPE_PDF, TRUE),
TEST (cairo_pdf_surface_set_size, CAIRO_SURFACE_TYPE_PDF, TRUE),
diff --git a/test/bug-277.c b/test/bug-277.c
new file mode 100644
index 000000000..f4de539a4
--- /dev/null
+++ b/test/bug-277.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright © 2022 Uli Schlachter
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Uli Schlachter <psychon@znc.in>
+ */
+
+#include "cairo-test.h"
+#include "cairo-script.h"
+
+struct write_data {
+ cairo_bool_t finished;
+ cairo_test_status_t test_status;
+};
+
+static cairo_surface_t*
+create_recording_surface ()
+{
+ /* Create a non-empty recording surface with arbitrary content */
+ cairo_surface_t *surf = cairo_recording_surface_create (CAIRO_CONTENT_COLOR, NULL);
+ cairo_t *cr = cairo_create (surf);
+
+ cairo_move_to (cr, 0, 0);
+ cairo_line_to (cr, 10, 0);
+ cairo_stroke (cr);
+
+ cairo_destroy (cr);
+ return surf;
+}
+
+static cairo_status_t
+write_func(void *closure, const unsigned char* bytes, unsigned int length)
+{
+ struct write_data *data = closure;
+ (void) bytes; (void) length;
+
+ if (data->finished)
+ data->test_status = CAIRO_TEST_ERROR;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_test_status_t
+preamble (cairo_test_context_t *ctx)
+{
+ struct write_data write_data = { FALSE, CAIRO_TEST_SUCCESS };
+ cairo_device_t *script_device = cairo_script_create_for_stream (write_func, &write_data);
+ cairo_surface_t *recording = create_recording_surface ();
+ cairo_surface_t *script;
+ cairo_t *cr;
+
+ /* Draw the recording surface to a script surface */
+ script = cairo_script_surface_create (script_device, CAIRO_CONTENT_COLOR, 5, 5);
+ cr = cairo_test_create (script, ctx);
+ cairo_set_source_surface (cr, recording, 0, 0);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+ cairo_surface_destroy (script);
+
+ /* Finish the script device; no further writing allowed afterwards */
+ cairo_device_finish (script_device);
+ write_data.finished = TRUE;
+ cairo_device_destroy (script_device);
+
+ cairo_surface_destroy (recording);
+
+ return write_data.test_status;
+}
+
+CAIRO_TEST (bug_277,
+ "Regression test: Script surface emitting test after finish()",
+ NULL, /* keywords */
+ NULL, /* requirements */
+ 0, 0,
+ preamble, NULL)
diff --git a/test/bug-535.c b/test/bug-535.c
new file mode 100644
index 000000000..5283b2ec7
--- /dev/null
+++ b/test/bug-535.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright © 2022 Uli Schlachter, Antony Lee
+ *
+ * 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: Uli Schlachter <psychon@znc.in>
+ */
+
+#include "cairo-test.h"
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ // Once upon a time, the "rectangle detection" in cairo-script was triggered
+ // by this degenerate rectangle and produces CAIRO_STATUS_INVALID_PATH_DATA.
+
+ cairo_move_to (cr, 0, 0);
+ cairo_line_to (cr, 9, 0);
+ cairo_fill (cr);
+
+ // Fill the whole surface so that argb32 and rgb24 can share a ref image
+ cairo_paint (cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (bug_535,
+ "Regression test for bug #535 in cairo-svg",
+ "degenerate", /* keywords */
+ NULL, /* requirements */
+ 1, 1,
+ NULL, draw)
+
diff --git a/test/cairo-logo-font.ttx b/test/cairo-logo-font.ttx
new file mode 100644
index 000000000..9e4b832c0
--- /dev/null
+++ b/test/cairo-logo-font.ttx
@@ -0,0 +1,539 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.19">
+
+ <GlyphOrder>
+ <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="A"/>
+ </GlyphOrder>
+
+ <head>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x3e7355ef"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000001"/>
+ <unitsPerEm value="1000"/>
+ <created value="Wed Jun 15 00:00:00 2022"/>
+ <modified value="Wed Jun 15 00:00:00 2022"/>
+ <xMin value="0"/>
+ <yMin value="0"/>
+ <xMax value="1000"/>
+ <yMax value="1000"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="6"/>
+ <fontDirectionHint value="2"/>
+ <indexToLocFormat value="0"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="0x00010000"/>
+ <ascent value="1000"/>
+ <descent value="0"/>
+ <lineGap value="200"/>
+ <advanceWidthMax value="1000"/>
+ <minLeftSideBearing value="0"/>
+ <minRightSideBearing value="0"/>
+ <xMaxExtent value="1000"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ <numberOfHMetrics value="2"/>
+ </hhea>
+
+ <maxp>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="0x10000"/>
+ <numGlyphs value="2"/>
+ <maxPoints value="1"/>
+ <maxContours value="1"/>
+ <maxCompositePoints value="1"/>
+ <maxCompositeContours value="1"/>
+ <maxZones value="1"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="256"/>
+ <maxSizeOfInstructions value="1"/>
+ <maxComponentElements value="2"/>
+ <maxComponentDepth value="1"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="1000"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00000001"/>
+ <ySubscriptXSize value="600"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="600"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="300"/>
+ <yStrikeoutSize value="0"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="0"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="djr "/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="65"/>
+ <usLastCharIndex value="65"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-100"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="300"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="720"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="3"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="1000" lsb="0"/>
+ <mtx name="A" width="1000" lsb="0"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="0" platEncID="3" language="0">
+ <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+
+ <!-- The xMin, yMin, xMax and yMax values
+ will be recalculated by the compiler. -->
+
+ <TTGlyph name=".notdef"/><!-- contains no outline data -->
+
+ <TTGlyph name="A">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Cairo Logo
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Cairo Logo Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="0"/>
+ <underlineThickness value="0"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+
+ <SVG>
+
+ <svgDoc endGlyphID="0" startGlyphID="0">
+ <![CDATA[<svg xmlns="http://www.w3.org/2000/svg"></svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="1" startGlyphID="1">
+ <![CDATA[<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="310" height="508">
+ <defs id="cairo-artwork_defs">
+ <g id="hacker_emblem">
+ <!-- Note: This is similar though not identical to Keith Packard's SVG version
+ of the hacker emblem (http://www.catb.org/hacker-emblem/glider.svg) -->
+ <g id="hacker_emblem_grid" fill="white" stroke="none">
+ <!-- Outside: Top, Right, Bottom, Left -->
+ <rect x="-2.95" y="-3.05" width="6" height="0.1" />
+ <rect x="2.95" y="-2.95" width="0.1" height="6" />
+ <rect x="-3.05" y="2.95" width="6" height="0.1" />
+ <rect x="-3.05" y="-3.05" width="0.1" height="6" />
+ <!-- Vertical: Left, Right -->
+ <rect x="-1.05" y="-2.95" width="0.1" height="5.9" />
+ <rect x="0.95" y="-2.95" width="0.1" height="5.9" />
+ <!-- Horizontal: TopLeft, TopMiddle, TopRight -->
+ <rect x="-2.95" y="-1.05" width="1.9" height="0.1" />
+ <rect x="-0.95" y="-1.05" width="1.9" height="0.1" />
+ <rect x="1.05" y="-1.05" width="1.9" height="0.1" />
+ <!-- Horizontal: BottomLeft, BottomMiddle, BottomRight -->
+ <rect x="-2.95" y="0.95" width="1.9" height="0.1" />
+ <rect x="-0.95" y="0.95" width="1.9" height="0.1" />
+ <rect x="1.05" y="0.95" width="1.9" height="0.1" />
+ </g>
+ <g id="hacker_emblem_dots" fill="white">
+ <circle cx="0" cy="-2" r="0.7" />
+ <circle cx="2" cy="0" r="0.7" />
+ <circle cx="-2" cy="2" r="0.7" />
+ <circle cx="0" cy="2" r="0.7" />
+ <circle cx="2" cy="2" r="0.7" />
+ </g>
+ </g>
+ <g id="scarab" fill="#3B80AE">
+ <g transform="translate(-150, -170)">
+ <path id="scarab_head" d="M205.599,94.567c0-11.668-24.914-21.129-55.628-21.129
+ c-30.723,0-55.624,9.46-55.624,21.129c0,10.203,24.901,7.346,55.624,7.346C180.685,101.913,205.599,104.233,205.599,94.567z"/>
+ <path id="scarab_torso" d="M136.423,161.506c0,0,12.751,12.577,13.547,13.362
+ c2.262-2.232,13.545-13.362,13.545-13.362c7.135-7.036,87.111-6.399,91.066-6.363c-0.469-6.298-1.254-12.472-2.325-18.519
+ c-15.183-19.279-42.811-32.225-74.485-32.225h-55.518c-31.745,0-59.439,13.011-74.598,32.37c-1.054,6-1.829,12.128-2.296,18.374
+ C49.321,155.106,129.288,154.47,136.423,161.506z"/>
+ <path id="scarab_spine" d="M149.97,301.187c2.005-24.729,8.386-103.483,8.405-103.721
+ c-0.09-0.219-6.478-15.578-8.405-20.214c-1.936,4.655-8.316,19.995-8.408,20.214C141.582,197.704,147.965,276.458,149.97,301.187z"/>
+ <path id="scarab_wing_left" d="M140.403,197.149l8.862-21.31l-13.686-13.499
+ c-5.65-5.573-67.074-6.235-90.259-6.019l-0.006-0.622c-0.154,2.144-0.271,4.302-0.35,6.475
+ c-0.076,2.207,10.392,4.706,10.392,6.717c0,2.319-10.457,5.084-10.359,7.631c2.993,73.349,48.53,131.631,104.372,132.048
+ l-9.02-111.29L140.403,197.149z"/>
+ <path id="scarab_wing_right" d="M244.585,168.891c0-2.011,10.467-4.506,10.391-6.715
+ c-0.079-2.174-0.195-4.332-0.351-6.479l-0.004,0.624c-23.186-0.216-84.608,0.445-90.26,6.017l-13.688,13.502l8.915,21.438
+ l-9.017,111.29c55.854-0.417,101.378-58.698,104.373-132.049C255.04,173.976,244.585,171.209,244.585,168.891z"/>
+ <path id="scarab_leg_front_left" d="M44.506,141.12c-4.135-0.856-4.895-1.54-7.935-2.92
+ c-9.59-3.364-10.376-5.481-16.08-11.86c-7.426-8.306-12.661-20.142-17.1-29.463c-3.576-7.525-3.984-16.409-2.86-24.273
+ c0.991-6.935,7.144-12.869,12.074-18.92c5.844-7.191,10.356-14.822,17.924-21.354c7.736-6.682,23.203-9.809,26.168-19.648
+ C57.86,8.819,54.334,1.766,61.482,0c-0.366,4.703,3.639,8.477,2.397,13.575c-1.129,4.627-4.368,5.811-9.611,9.099
+ c-7.564,4.746-18.366,8.779-24.748,13.965c-7.175,5.827-4.369,13.771-10.569,20.057c-2.001,2.03-7.901,4.706-9.137,6.83
+ c-1.861,3.199-0.297,9.572-0.116,13.12c0.425,8.284,5.588,14.244,9.555,22.045c4.152,8.141,6.429,15.409,13.411,22.519
+ c4.183,4.262,11.429,4.802,16.21,10.647l-3.555,4.186L44.506,141.12z"/>
+ <path id="scarab_leg_middle_left" d="M43.94,191.922l-0.809-7.346
+ c-9.506-4.579-10.339-9.772-20.738-12.466c-23.728-6.151-21.361,11.25-15.532,26.373c5.676,14.726,8.237,30.23,14.345,44.795
+ c2.805,6.688,6.919,13.213,14.298,15.127c0.372-8.435-0.917-10.651-6.113-16.919c-4.395-5.293-3.326-12.548-6.072-18.504
+ c-3.581-7.804-4.196-15.646-7.279-23.502c-1.363-3.479-8.33-13.966-6.452-17.861c3.183-6.603,9.178-0.083,12.179,2.077
+ c4.218,3.036,6.467,2.223,11.681,2.898C34.041,186.673,37.005,188.756,43.94,191.922z"/>
+ <path id="scarab_leg_back_left" d="M65.839,257.063l-2.771-4.837
+ c-6.68,8.928-6.993,16.228-10.056,23.347c-5.277,12.263-0.157,28.851,9.854,37.676c6.052,5.375,15.907,9.618,23.122,13.136
+ c10.035,4.892,20.113,11.286,31.336,13.396c2.482,0.466,8.798,1.295,6.693-3.522c-0.975-2.237-8.091-4.591-10.146-5.734
+ c-8.312-4.623-16.377-10.524-24.142-16.176c-9.498-6.862-20.843-11.186-28.311-20.684c-3.054-3.885-3.544-4.922-2.816-9.39
+ c0.693-4.263,1.344-9.174,2.241-13.439C61.855,266.029,63.274,261.378,65.839,257.063z"/>
+ <path id="scarab_leg_front_right" d="M255.487,141.12c4.134-0.856,4.896-1.54,7.936-2.92
+ c9.583-3.364,10.369-5.481,16.071-11.86c7.428-8.306,12.661-20.142,17.115-29.463c3.574-7.525,3.983-16.409,2.86-24.273
+ c-0.992-6.935-7.157-12.869-12.087-18.92c-5.843-7.191-10.356-14.822-17.919-21.354c-7.735-6.682-23.202-9.809-26.167-19.648
+ C242.135,8.819,245.66,1.766,238.511,0c0.366,4.703-3.637,8.477-2.396,13.575c1.131,4.627,4.368,5.811,9.611,9.099
+ c7.563,4.746,18.367,8.779,24.747,13.965c7.17,5.827,4.362,13.771,10.563,20.057c2.001,2.03,7.901,4.706,9.139,6.83
+ c1.859,3.199,0.295,9.572,0.113,13.12c-0.424,8.284-5.588,14.244-9.553,22.045c-4.152,8.141-6.431,15.409-13.404,22.519
+ c-4.184,4.262-11.429,4.802-16.211,10.647l3.556,4.186L255.487,141.12z"/>
+ <path id="scarab_leg_middle_right" d="M256.053,191.922l0.81-7.346
+ c9.507-4.579,10.34-9.772,20.73-12.466c23.741-6.151,21.374,11.25,15.534,26.373c-5.676,14.726-8.238,30.23-14.347,44.795
+ c-2.804,6.688-6.911,13.213-14.291,15.127c-0.371-8.435,0.918-10.651,6.113-16.919c4.39-5.293,3.319-12.548,6.066-18.504
+ c3.58-7.804,4.197-15.646,7.278-23.502c1.363-3.479,8.33-13.966,6.453-17.861c-3.184-6.603-9.179-0.083-12.181,2.077
+ c-4.217,3.036-6.458,2.223-11.672,2.898C265.951,186.673,262.986,188.756,256.053,191.922z"/>
+ <path id="scarab_leg_back_right" d="M234.155,257.063l2.771-4.837
+ c6.679,8.928,6.991,16.228,10.057,23.347c5.274,12.263,0.154,28.851-9.854,37.676c-6.055,5.375-15.903,9.618-23.117,13.136
+ c-10.034,4.892-20.127,11.286-31.351,13.396c-2.481,0.466-8.789,1.295-6.691-3.522c0.976-2.237,8.092-4.591,10.146-5.734
+ c8.312-4.623,16.392-10.524,24.155-16.176c9.498-6.862,20.838-11.186,28.305-20.684c3.055-3.885,3.543-4.922,2.818-9.39
+ c-0.696-4.263-1.346-9.174-2.244-13.439C238.137,266.029,236.718,261.378,234.155,257.063z"/>
+ </g>
+ </g>
+ <radialGradient id="gradient_radial_dung"
+ cx="0" cy="0" r="60"
+ fx="0" fy="0" gradientUnits="userSpaceOnUse"
+ >
+ <stop offset="0" stop-color="#9a9a9a" />
+ <stop offset="0.70" stop-color="#bababa" />
+ <stop offset="0.95" stop-color="#FFFFFF" />
+ </radialGradient>
+ <g id="dung">
+ <circle cx="0" cy="0" r="60" fill="url(#gradient_radial_dung)" />
+ <g transform="translate(-61, -61)">
+ <!-- rough equivalent: <circle cx="0" cy="0" r="60" stroke="#8a8a8a" stroke-width="2" /> -->
+ <path fill="#8a8a8a" d="M0,61c0,33.636,27.364,61,61,61s61-27.364,61-61S94.636,0,61,0S0,27.364,0,61z
+ M2,61C2,28.467,28.467,2,61,2c32.532,0,59,26.467,59,59c0,32.533-26.468,59-59,59C28.467,120,2,93.533,2,61z"/>
+ </g>
+ <use xlink:href="#hacker_emblem" x="0" y="0" transform="scale(9)" />
+ </g>
+
+ <!-- scarab dimensions: 300x340 -->
+ <!-- dung dimensions: 120x120 (radius: 60) -->
+ <!-- scarab and dung dimensions: 300x400 -->
+
+ <g id="cairo_logo">
+ <!-- dimensions: 300x400, centered -->
+ <!-- The logo (scarab and dung), with the center-point of the bounding box at (0,0) -->
+ <use xlink:href="#dung" x="0" y="0" transform="translate(0, -140)" />
+ <use xlink:href="#scarab" x="0" y="0" transform="translate(0, 30)" />
+ </g>
+ <g id="cairo_logo_dung-centered">
+ <!-- The logo (scarab and dung), with the dung at (0,0), the scarab below -->
+ <use xlink:href="#dung" x="0" y="0" />
+ <use xlink:href="#scarab" x="0" y="0" transform="translate(0,170)" />
+ </g>
+ <g id="cairo_logo_scarab-centered">
+ <!-- The logo (scarab and dung), with the scarab's rotational center at (0,0), the dung above -->
+ <!-- The scarab's rotational center in this case is not the center of its bounding box,
+ but is calculated to be the intersection-point of the torso, spine and wings -->
+ <use xlink:href="#dung" x="0" y="0" transform="translate(0, -175.85)" />
+ <use xlink:href="#scarab" x="0" y="0" transform="translate(0, -5.85)" />
+ </g>
+ <g id="cairo_logo_top-centered">
+ <!-- The logo (scarab and dung), with the top-center point of the bounding box at (0,0) -->
+ <use xlink:href="#dung" x="0" y="0" transform="translate(0, 60)" />
+ <use xlink:href="#scarab" x="0" y="0" transform="translate(0, 230)" /><!-- (0,170+60) -->
+ </g>
+ <g id="cairo_logo_bottom-centered">
+ <!-- The logo (scarab and dung), with the bottom-center point of the bounding box at (0,0) -->
+ <use xlink:href="#dung" x="0" y="0" transform="translate(0, -340)" />
+ <use xlink:href="#scarab" x="0" y="0" transform="translate(0, -170)" />
+ </g>
+ <g id="cairo_logo_right-centered">
+ <!-- The logo (scarab and dung), with the right-center point of the bounding box at (0,0) -->
+ <use xlink:href="#dung" x="0" y="0" transform="translate(-150, -140)" />
+ <use xlink:href="#scarab" x="0" y="0" transform="translate(-150, 30)" />
+ </g>
+ <g id="cairo_logo_left-centered">
+ <!-- The logo (scarab and dung), with the left-center point of the bounding box at (0,0) -->
+ <use xlink:href="#dung" x="0" y="0" transform="translate(150, -140)" />
+ <use xlink:href="#scarab" x="0" y="0" transform="translate(150, 30)" />
+ </g>
+ <g id="cairo_logo_topleft-centered">
+ <!-- The logo (scarab and dung), with the top-left point of the bounding box at (0,0) -->
+ <use xlink:href="#dung" x="0" y="0" transform="translate(150, 60)" />
+ <use xlink:href="#scarab" x="0" y="0" transform="translate(150, 230)" /><!-- (150, 170+60) -->
+ </g>
+ <g id="cairo_logo_topright-centered">
+ <!-- The logo (scarab and dung), with the top-right point of the bounding box at (0,0) -->
+ <use xlink:href="#dung" x="0" y="0" transform="translate(-150, 60)" />
+ <use xlink:href="#scarab" x="0" y="0" transform="translate(-150, 230)" /><!-- (-150,170+60) -->
+ </g>
+ <g id="cairo_logo_bottomleft-centered">
+ <!-- The logo (scarab and dung), with the bottom-left point of the bounding box at (0,0) -->
+ <use xlink:href="#dung" x="0" y="0" transform="translate(150, -340)" />
+ <use xlink:href="#scarab" x="0" y="0" transform="translate(150, -170)" />
+ </g>
+ <g id="cairo_logo_bottomright-centered">
+ <!-- The logo (scarab and dung), with the bottom-right point of the bounding box at (0,0) -->
+ <use xlink:href="#dung" x="0" y="0" transform="translate(-150, -340)" />
+ <use xlink:href="#scarab" x="0" y="0" transform="translate(-150, -170)" />
+ </g>
+
+ <g id="cairo_text" transform="translate(0,-97)">
+ <g transform="scale(0.1484,0.1484)"> <g transform="translate(-1139,-208.5)">
+ <!-- 63 (c), advance 444, 0 horiBearing 38,522 -->
+ <path transform="translate(65,0)" d="
+ M 412, 433
+ C 385, 422 336, 413 298, 413
+ C 142, 413 38, 525 38, 680
+ C 38, 826 144, 947 298, 947
+ C 332, 947 377, 944 416, 926
+ L 409, 842
+ C 380, 861 340, 871 308, 871
+ C 187, 871 138, 771 138, 680
+ C 138, 583 197, 489 302, 489
+ C 332, 489 368, 496 404, 511
+ L 412, 433 " />
+ <!-- 61 (a), advance 556, 0 horiBearing 46,522 -->
+ <path transform="translate(486.75,0)" d="
+ M 109, 541
+ C 147, 509 204, 489 257, 489
+ C 351, 489 383, 534 383, 622
+ C 346, 620 320, 620 283, 620
+ C 186, 620 46, 660 46, 788
+ C 46, 899 123, 947 233, 947
+ C 319, 947 369, 900 391, 869
+ L 393, 869
+ L 393, 935
+ L 481, 935
+ C 479, 920 477, 893 477, 835
+ L 477, 624
+ C 477, 485 418, 413 272, 413
+ C 207, 413 151, 433 104, 461
+ L 109, 541
+ M 383, 737
+ C 383, 813 334, 871 241, 871
+ C 198, 871 146, 842 146, 788
+ C 146, 698 272, 690 323, 690
+ C 343, 690 363, 692 383, 692
+ L 383, 737 " />
+ <!-- 69 (i), advance 278, 0 horiBearing 86,730 -->
+ <path transform="translate(1000,0)" d="
+ M 92, 935
+ L 186, 935
+ L 186, 425
+ L 92, 425
+ L 92, 935
+ M 88, 261
+ A 51, 51 0 1 1 190,261
+ A 51, 51 0 1 1 88,261" />
+ <!-- 72 (r), advance 389, 0 horiBearing 80,522 -->
+ <path transform="translate(1234.25,0)" d="
+ M 80, 935
+ L 174, 935
+ L 174, 703
+ C 174, 575 229, 495 313, 495
+ C 329, 495 348, 497 365, 504
+ L 365, 420
+ C 345, 416 331, 413 303, 413
+ C 249, 413 195, 451 170, 504
+ L 168, 504
+ L 168, 425
+ L 80, 425
+ L 80, 935 " />
+ <!-- 6f (o), advance 611, 0 horiBearing 46,522 -->
+ <path transform="translate(1610,0)" d="
+ M 46, 680
+ C 46, 826 152, 947 306, 947
+ C 459, 947 565, 826 565, 680
+ C 565, 525 461, 413 306, 413
+ C 150, 413 46, 525 46, 680
+ M 146, 680
+ C 146, 583 205, 489 306, 489
+ C 406, 489 465, 583 465, 680
+ C 465, 771 416, 871 306, 871
+ C 195, 871 146, 771 146, 680 " />
+ <!-- bounds: 38, 205 <-> 2232, 947 -->
+ </g> </g>
+ </g>
+
+ <!-- scaled by 0.72, shifted around to hit pixel boundaries -->
+ <g id="cairo_text_small" transform="translate(0,-71)">
+ <g transform="scale(0.085,0.085)"> <g transform="translate(-1139,-208.5)">
+ <!-- 63 (c), advance 444, 0 horiBearing 38,522 -->
+ <path transform="translate(-151,0)" d="
+ M 412, 433
+ C 385, 422 336, 413 298, 413
+ C 142, 413 38, 525 38, 680
+ C 38, 826 144, 947 298, 947
+ C 332, 947 377, 944 416, 926
+ L 409, 842
+ C 380, 861 340, 871 308, 871
+ C 187, 871 138, 771 138, 680
+ C 138, 583 197, 489 302, 489
+ C 332, 489 368, 496 404, 511
+ L 412, 433 " />
+ <!-- 61 (a), advance 556, 0 horiBearing 46,522 -->
+ <path transform="translate(379.5,0)" d="
+ M 109, 541
+ C 147, 509 204, 489 257, 489
+ C 351, 489 383, 534 383, 622
+ C 346, 620 320, 620 283, 620
+ C 186, 620 46, 660 46, 788
+ C 46, 899 123, 947 233, 947
+ C 319, 947 369, 900 391, 869
+ L 393, 869
+ L 393, 935
+ L 481, 935
+ C 479, 920 477, 893 477, 835
+ L 477, 624
+ C 477, 485 418, 413 272, 413
+ C 207, 413 151, 433 104, 461
+ L 109, 541
+ M 383, 737
+ C 383, 813 334, 871 241, 871
+ C 198, 871 146, 842 146, 788
+ C 146, 698 272, 690 323, 690
+ C 343, 690 363, 692 383, 692
+ L 383, 737 " />
+ <!-- 69 (i), advance 278, 0 horiBearing 86,730 -->
+ <path transform="translate(1000,0)" d="
+ M 92, 935
+ L 186, 935
+ L 186, 425
+ L 92, 425
+ L 92, 935
+ M 88, 261
+ A 51, 51 0 1 1 190,261
+ A 51, 51 0 1 1 88,261" />
+ <!-- 72 (r), advance 389, 0 horiBearing 80,522 -->
+ <path transform="translate(1341.5,0)" d="
+ M 80, 935
+ L 174, 935
+ L 174, 703
+ C 174, 575 229, 495 313, 495
+ C 329, 495 348, 497 365, 504
+ L 365, 420
+ C 345, 416 331, 413 303, 413
+ C 249, 413 195, 451 170, 504
+ L 168, 504
+ L 168, 425
+ L 80, 425
+ L 80, 935 " />
+ <!-- 6f (o), advance 611, 0 horiBearing 46,522 -->
+ <path transform="translate(1826,0)" d="
+ M 46, 680
+ C 46, 826 152, 947 306, 947
+ C 459, 947 565, 826 565, 680
+ C 565, 525 461, 413 306, 413
+ C 150, 413 46, 525 46, 680
+ M 146, 680
+ C 146, 583 205, 489 306, 489
+ C 406, 489 465, 583 465, 680
+ C 465, 771 416, 871 306, 871
+ C 195, 871 146, 771 146, 680 " />
+ <!-- bounds: 38, 205 <-> 2232, 947 -->
+ </g> </g>
+ </g>
+
+ <g id="cairo_logo_with_text">
+ <!-- The logo (scarab and dung), with the text 'cairo' below, the dot of the 'i' positioned between the hind legs of the scarab -->
+ <!-- dimensions: 300x490, centered -->
+ <use xlink:href="#cairo_logo_top-centered" transform="translate(0, -245)" />
+ <use xlink:href="#cairo_text" transform="translate(0, 245)" />
+ </g>
+
+ <g id="cairo_banner">
+ <!-- The logo on the left, the text 'cairo' in the center, and a mirror image of the logo on the right -->
+ <!-- The logos are scaled such that the scarab body nearly matches the height of the text characters (excepting the 'i')
+ and the dung should nearly aligns with the dot of the 'i'. The bottoms of the logos are aligned with the bottom of the text. -->
+ <!-- dimensions: 370x88, centered -->
+ <use xlink:href="#cairo_logo_bottomleft-centered" transform="translate(-180, 40), scale(0.1944)" />
+ <use xlink:href="#cairo_text_small" transform="translate(0, 42)" fill="black" />
+ <use xlink:href="#cairo_logo_bottomleft-centered" transform="translate(180, 40), scale(0.1944), scale(-1, 1)" />
+ </g>
+ </defs>
+ <g transform="translate(5, -500)">
+ <use xlink:href="#cairo_logo_with_text" transform="translate(150, 245)" />
+ </g>
+</svg>]]>
+ </svgDoc>
+ <colorPalettes>
+ </colorPalettes>
+ </SVG>
+
+</ttFont>
diff --git a/test/cairo-svg-test-color.ttx b/test/cairo-svg-test-color.ttx
new file mode 100644
index 000000000..a915a704b
--- /dev/null
+++ b/test/cairo-svg-test-color.ttx
@@ -0,0 +1,362 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.38">
+
+ <GlyphOrder>
+ <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="zero"/>
+ <GlyphID id="2" name="one"/>
+ <GlyphID id="3" name="two"/>
+ <GlyphID id="4" name="three"/>
+ <GlyphID id="5" name="four"/>
+ <GlyphID id="6" name="five"/>
+ <GlyphID id="7" name="six"/>
+ <GlyphID id="8" name="seven"/>
+ </GlyphOrder>
+
+ <head>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x1d3a9a74"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Wed Jun 15 00:00:00 2022"/>
+ <modified value="Fri Jan 27 08:44:23 2023"/>
+ <xMin value="0"/>
+ <yMin value="0"/>
+ <xMax value="1000"/>
+ <yMax value="1000"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="6"/>
+ <fontDirectionHint value="2"/>
+ <indexToLocFormat value="0"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="0x00010000"/>
+ <ascent value="1000"/>
+ <descent value="0"/>
+ <lineGap value="200"/>
+ <advanceWidthMax value="1100"/>
+ <minLeftSideBearing value="0"/>
+ <minRightSideBearing value="100"/>
+ <xMaxExtent value="1000"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ <numberOfHMetrics value="1"/>
+ </hhea>
+
+ <maxp>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="0x10000"/>
+ <numGlyphs value="9"/>
+ <maxPoints value="4"/>
+ <maxContours value="1"/>
+ <maxCompositePoints value="0"/>
+ <maxCompositeContours value="0"/>
+ <maxZones value="1"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="256"/>
+ <maxSizeOfInstructions value="1"/>
+ <maxComponentElements value="0"/>
+ <maxComponentDepth value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="1000"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00000001"/>
+ <ySubscriptXSize value="600"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="600"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="300"/>
+ <yStrikeoutSize value="0"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="0"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="djr "/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="48"/>
+ <usLastCharIndex value="55"/>
+ <sTypoAscender value="1000"/>
+ <sTypoDescender value="0"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="300"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="720"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="3"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="1100" lsb="0"/>
+ <mtx name="five" width="1100" lsb="0"/>
+ <mtx name="four" width="1100" lsb="0"/>
+ <mtx name="one" width="1100" lsb="0"/>
+ <mtx name="seven" width="1100" lsb="0"/>
+ <mtx name="six" width="1100" lsb="0"/>
+ <mtx name="three" width="1100" lsb="0"/>
+ <mtx name="two" width="1100" lsb="0"/>
+ <mtx name="zero" width="1100" lsb="0"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="0" platEncID="3" language="0">
+ <map code="0x30" name="zero"/><!-- DIGIT ZERO -->
+ <map code="0x31" name="one"/><!-- DIGIT ONE -->
+ <map code="0x32" name="two"/><!-- DIGIT TWO -->
+ <map code="0x33" name="three"/><!-- DIGIT THREE -->
+ <map code="0x34" name="four"/><!-- DIGIT FOUR -->
+ <map code="0x35" name="five"/><!-- DIGIT FIVE -->
+ <map code="0x36" name="six"/><!-- DIGIT SIX -->
+ <map code="0x37" name="seven"/><!-- DIGIT SEVEN -->
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+
+ <!-- The xMin, yMin, xMax and yMax values
+ will be recalculated by the compiler. -->
+
+ <TTGlyph name=".notdef"/><!-- contains no outline data -->
+
+ <TTGlyph name="five" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="four" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="one" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="seven" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="six" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="three" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="two" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="zero" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Cairo Svg Test Color
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Cairo Svg Test Color Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="0"/>
+ <underlineThickness value="0"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+ <CPAL>
+ <version value="0"/>
+ <numPaletteEntries value="2"/>
+ <palette index="0">
+ <color index="0" value="#C5A1D7FF"/>
+ <color index="1" value="#80DFC8FF"/>
+ </palette>
+ <palette index="1">
+ <color index="0" value="#6392A9FF"/>
+ <color index="1" value="#7896B3FF"/>
+ </palette>
+ </CPAL>
+
+ <SVG>
+ <svgDoc endGlyphID="0" startGlyphID="0">
+ <![CDATA[<svg xmlns="http://www.w3.org/2000/svg"></svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="1" startGlyphID="1">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="var(--color0, red)" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="2" startGlyphID="2">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="var(--color1, blue)" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="3" startGlyphID="3">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="currentColor" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="4" startGlyphID="4">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="currentColor" fill-opacity="0.5" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="5" startGlyphID="5">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <linearGradient id="grad" x1="33%" x21="66%">
+ <stop offset="0%" stop-color="currentColor" stop-opacity="1" />
+ <stop offset="100%" stop-color="red" stop-opacity="1" />
+ </linearGradient>
+ </defs>
+ <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="6" startGlyphID="6">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <linearGradient id="grad" x1="33%" x21="66%">
+ <stop offset="0%" stop-color="currentColor" stop-opacity="0.3" />
+ <stop offset="100%" stop-color="red" stop-opacity="0.3" />
+ </linearGradient>
+ </defs>
+ <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="7" startGlyphID="7">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <radialGradient id="grad" cx="50%" cy="50%"
+ fx="0.75" fy="0.35" r="0.5">
+ <stop offset="0%" stop-color="currentColor" stop-opacity="1" />
+ <stop offset="100%" stop-color="blue" stop-opacity="1" />
+ </radialGradient>
+ </defs>
+ <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="8" startGlyphID="8">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <radialGradient id="grad" cx="50%" cy="50%"
+ fx="0.75" fy="0.35" r="0.5">
+ <stop offset="0%" stop-color="currentColor" stop-opacity="0.5" />
+ <stop offset="100%" stop-color="blue" stop-opacity="0.5" />
+ </radialGradient>
+ </defs>
+ <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" />
+</svg>]]>
+ </svgDoc>
+ </SVG>
+
+</ttFont>
diff --git a/test/cairo-svg-test-doc.ttx b/test/cairo-svg-test-doc.ttx
new file mode 100644
index 000000000..c2cdb2817
--- /dev/null
+++ b/test/cairo-svg-test-doc.ttx
@@ -0,0 +1,689 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.19">
+
+ <GlyphOrder>
+ <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="zero"/>
+ <GlyphID id="2" name="one"/>
+ <GlyphID id="3" name="two"/>
+ <GlyphID id="4" name="three"/>
+ <GlyphID id="5" name="four"/>
+ <GlyphID id="6" name="five"/>
+ <GlyphID id="7" name="six"/>
+ <GlyphID id="8" name="seven"/>
+ <GlyphID id="9" name="eight"/>
+ <GlyphID id="10" name="nine"/>
+ <GlyphID id="11" name="A"/>
+ </GlyphOrder>
+
+ <head>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x6d925ed5"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Wed Jun 15 00:00:00 2022"/>
+ <modified value="Fri Jul 1 06:21:40 2022"/>
+ <xMin value="0"/>
+ <yMin value="0"/>
+ <xMax value="1000"/>
+ <yMax value="1000"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="6"/>
+ <fontDirectionHint value="2"/>
+ <indexToLocFormat value="0"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="0x00010000"/>
+ <ascent value="1000"/>
+ <descent value="0"/>
+ <lineGap value="200"/>
+ <advanceWidthMax value="1100"/>
+ <minLeftSideBearing value="0"/>
+ <minRightSideBearing value="100"/>
+ <xMaxExtent value="1000"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ <numberOfHMetrics value="1"/>
+ </hhea>
+
+ <maxp>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="0x10000"/>
+ <numGlyphs value="12"/>
+ <maxPoints value="4"/>
+ <maxContours value="1"/>
+ <maxCompositePoints value="0"/>
+ <maxCompositeContours value="0"/>
+ <maxZones value="1"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="256"/>
+ <maxSizeOfInstructions value="1"/>
+ <maxComponentElements value="0"/>
+ <maxComponentDepth value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="1000"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00000001"/>
+ <ySubscriptXSize value="600"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="600"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="300"/>
+ <yStrikeoutSize value="0"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="0"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="djr "/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="48"/>
+ <usLastCharIndex value="65"/>
+ <sTypoAscender value="1000"/>
+ <sTypoDescender value="0"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="300"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="720"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="3"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="1100" lsb="0"/>
+ <mtx name="A" width="1100" lsb="0"/>
+ <mtx name="eight" width="1100" lsb="0"/>
+ <mtx name="five" width="1100" lsb="0"/>
+ <mtx name="four" width="1100" lsb="0"/>
+ <mtx name="nine" width="1100" lsb="0"/>
+ <mtx name="one" width="1100" lsb="0"/>
+ <mtx name="seven" width="1100" lsb="0"/>
+ <mtx name="six" width="1100" lsb="0"/>
+ <mtx name="three" width="1100" lsb="0"/>
+ <mtx name="two" width="1100" lsb="0"/>
+ <mtx name="zero" width="1100" lsb="0"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="0" platEncID="3" language="0">
+ <map code="0x30" name="zero"/><!-- DIGIT ZERO -->
+ <map code="0x31" name="one"/><!-- DIGIT ONE -->
+ <map code="0x32" name="two"/><!-- DIGIT TWO -->
+ <map code="0x33" name="three"/><!-- DIGIT THREE -->
+ <map code="0x34" name="four"/><!-- DIGIT FOUR -->
+ <map code="0x35" name="five"/><!-- DIGIT FIVE -->
+ <map code="0x36" name="six"/><!-- DIGIT SIX -->
+ <map code="0x37" name="seven"/><!-- DIGIT SEVEN -->
+ <map code="0x38" name="eight"/><!-- DIGIT EIGHT -->
+ <map code="0x39" name="nine"/><!-- DIGIT NINE -->
+ <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+
+ <!-- The xMin, yMin, xMax and yMax values
+ will be recalculated by the compiler. -->
+
+ <TTGlyph name=".notdef"/><!-- contains no outline data -->
+
+ <TTGlyph name="A" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="eight" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="five" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="four" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="nine" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="one" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="seven" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="six" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="three" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="two" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="zero" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Cairo Svg Test Doc
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Cairo Svg Test Doc Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="0"/>
+ <underlineThickness value="0"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+ <CPAL>
+ <version value="0"/>
+ <numPaletteEntries value="2"/>
+ <palette index="0">
+ <color index="0" value="#C5A1D7FF"/>
+ <color index="1" value="#80DFC8FF"/>
+ </palette>
+ <palette index="1">
+ <color index="0" value="#6392A9FF"/>
+ <color index="1" value="#7896B3FF"/>
+ </palette>
+ </CPAL>
+
+ <SVG>
+
+ <svgDoc endGlyphID="0" startGlyphID="0">
+ <![CDATA[<svg xmlns="http://www.w3.org/2000/svg"></svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="1" startGlyphID="1">
+ <![CDATA[<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
+ <rect x="10" y="-90" width="80" height="80"
+ fill="none" stroke="black" stroke-width="10"/>
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="2" startGlyphID="2">
+ <![CDATA[<svg viewBox="-5 -5 10 10" xmlns="http://www.w3.org/2000/svg">
+ <rect x="-4" y="-14" width="8" height="8"
+ fill="none" stroke="black" stroke-width="1"/>
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="3" startGlyphID="3">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <image x="0" y="-1000" width="1000" height="1000"
+ xlink:href="data:image/png;base64,
+iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9
+kT1Iw0AYht+m1opUHOwgopChOlkQFXXUKhShQqkVWnUwufQPmjQkKS6OgmvBwZ/FqoOLs64OroIg
++APi6OSk6CIlfpcUWsR4x3EP733vy913gFAvM9XsGANUzTJS8ZiYya6KwVd0YggBmtMSM/W5ZDIB
+z/F1Dx/f76I8y7vuz9Gj5EwG+ETiWaYbFvEG8dSmpXPeJw6zoqQQnxOPGnRB4keuyy6/cS44LPDM
+sJFOzROHicVCG8ttzIqGSjxJHFFUjfKFjMsK5y3OarnKmvfkLwzltJVlrtMaRByLWEISImRUUUIZ
+FqK0a6SYSNF5zMM/4PiT5JLJVQIjxwIqUCE5fvA/+N1bMz8x7iaFYkDgxbY/hoHgLtCo2fb3sW03
+TgD/M3CltfyVOjDzSXqtpUWOgN5t4OK6pcl7wOUO0P+kS4bkSH5aQj4PvJ/RN2WBvluge83tW/Mc
+pw9AmnqVuAEODoGRAmWve7y7q71v/9Y0+/cDaP1yo4gSHTAAAAAGYktHRAD/AP8A/6C9p5MAAAAJ
+cEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfmBh0FBzE5rnzLAAAAGXRFWHRDb21tZW50AENyZWF0
+ZWQgd2l0aCBHSU1QV4EOFwAAF45JREFUaN5NmnmPZOd13n/vdrdau6p6X2cjw5FIarMjAYmDwP7H
+Buz4K/ib8IMFQaAgtiVLoRRSociZIWc4Pb1Xda237vIu+eNWD91AoYHuu9R7luc85zlHfPyzvwxC
+CJRSzUdKpJAIKVBSIZVESoGUGqkkQggIASkE2miMiTGRQWmNkAqlNVobBMDmPgApwVmHrWu894QQ
+CCHgvcMHh6stdVVh6xpra5xzeO/xLry/NtBcj5AIIRFSEbzFe49+OIQQAgDnPSiBbL4KUki0Nmhj
+EFIhmz8jCGhtMFHzP6kNSjbPkVJuDNC88OGLSCnRujlYAELwBB/w3uOURWlFXSlUrTYHCVhrsdbi
+nYMQmpcTCMGDbyxklELnqxVZlhEnMe00RmtNXlT4zT1CiM2XUkitUUo1X5RAYwSNVM0hpJSNR1Tj
+GQDvHMH7H7wYxSitQIBznrquCD6g/A/etNbi6sYrVVUhpaSuKpxrjOGdJwgAj6Ixnp7f3xOcY7uX
+koiSSHq2tmIqJ5nmDgSEjSWEEO89h5CNbRrT/uAJuTm0kCBEY3sB3nmEkGjTeLDxkCd4R+0tbO5H
+GYRonqOsbV4QAhiNEDThJj3Ob8LNe4IQ6LquSSJBMb+DJEbLDqv5HEFgf2vAfSFwm9AQgBQCAc0D
+mtMhnGvCSza5JVXjPSEEMki8dwQNUor3BxZC4JxDSYXXAS003nlq6sZwm+u0VoSgYRMB3nu89yjv
+sbbJI2stuixLYi2JtCB4j/OerNXG2pp8MeNkZ4/7UlA4scmaTXw/eEgqpNKbsFIo80P4KaXe3+G9
+33jQN/GNQAiIohgjIkIIOGubCPAe4SRBBqTSGEBKiXNNoldVSV1VgMOHJo908BatBFpKUAofwPqA
+1IY4Sbi6vODw6JhZrcitINBY6n1ia4UypvGA1Jtc2RxISgQNmDjnmuOH5lCB0ACB0htLO5QySKUJ
+/gHRNogZNO1EESlQQuCQfPXqbYN4zuKcQ7MJF6M1QRkCAakU7U6XVtYijlMuLy94/PgJN+tAXoEy
+5j3SSalQ2qB0hNIKIR5gXDWhhAAhiIxBCEHw7j38eu+xwRMCTV7JxstJ6pBCYG1NL1KIakm5XiDi
+mKJyWA9pnJDna4Jv7tEASkmM1mBiRJSCVAQfEErT7Q+RAi4vLzk9OeWm1NRe8IDDSjfJ+YDryugm
+R4RAbpI2iAYctNIELwnBbzzUWDiEJokfwjGKElItSOqcYrHAC0Wr08V7qOoCrSDa1C4fAjiHbGqC
+IIkNWRqhdESSddAmoi4rAoJWp4fSEefn33O8FZHGGi3VxitgjEZrjRQCfIMkG5gjCFBKNcWMQBAC
+ROO5wMYAQqC1xhiDkpJRS7DFgipfESUt+oMRUZxS1RZb1yhtqF1A6wit9cPHgJBEJiJNIlZWEJuI
+yGjanS7tdpe6LljM5tzf3fP2u1f86NOf8tXFErEpeloJpGxCFATOe0QIiOAJtoFv5wLONcgFzWGt
+d3jvfvCcr9lSBevxFfm6Imv1iJIMtKGoAx5JCJbaB1br4n2RDSGgIxNTWY8yMVJKtjoJ66pExm28
+k2iTEJAcnD4ijiPOv39D+vVXPPvwYy6XnkBjTUkDpw+1QkqBtxYTxzjvCIALHufY5IoHIQk4rHfs
+dWKicsLlu7fErT7HHzwj7XSxtSXPS2qviPMlaE0R9HvkZINoWinF/XxJGhuEaSGATqqxviROeoQQ
+iGNDvfaYTTH7/uKSk0dPuL+eouOMdqeLtTVCgKstaZq8x3wdpyRJRgAm9xOyrIVUEhU30FyVOU92
+2qwuX3F3fU2vNyLt9DFCUeUlJmkTqIi1opUYpG8xWVmUVCA9nuY5WghBWVm8MqRJipMGIQVtbTDU
+xKJiPZ8xn9xxP5kwnU4pqpKXL1+xv3vI9WxJvbQkaUZQEYaAK0ustSzXOXHWwtY1rU6HNElZLleb
+QgrClfzouM/tyy8Zj8cMBiN2Dk+R0lB7CEGwXMyJsERRwBkJnR7VbIzRDe+rbQM6OooilFJcXFxx
+cBhhIkeBwtUOQk2IPMFbnHWUZUlVV3gfuLy+JW31SJUgVoJgK7TSIAVKR9wsl0Qm4ur8Lds7O8zr
+mrqucOucxbrEuprjYZtqUvLq5UtGox2ybg+TtUmzLs5DsVqQhhVSwMpKtDLkziCFRKkG/bRSeEB1
+Or3PlJJ0OxmDwQC3nFBbx83tFdI7itJSV5YgoaprDo+PMUazWq+pqpp22iJKE9I0Y11WGAkhOG5u
+b2lnGb1uC7xltcxZr5cc7QwZdlv0WgnVcsLk8px3Fxc8OjxEKUmcthju7KKlJNaANORlwNclJoq4
+mJcUVUUIDoJAiA2r9iFQWUdZOySO8WxJ4RaUZcVUgI5bmCxj2O3SHu7g6wrrHM55ptN7autpLZc4
+F9je2WXQHTCezEhjTb5eEBvJ6ekJ08USgsOohnvNbs4RtmBrsMUTLSmqnJ7uIao1dr0k6/YpdMTa
+KtK0xlaeiY02sKtwLsKHGuEE4NFFsabVarNcLvAIFkVBXlr29w4Y7WwTxTHWVSgpGN/cYG2FkIok
+a1FaT1Hm6EJTVo502aKqSlpJhNYSay11XXBzfc79dMn29pDx7B5XFWhfo2NDnKT84oMPmU/GCJ2Q
+z2csxzcgFT4I2tqx9BXnF+dcsEUAlIkxG1JceY+UBm1tTVmWFDZjPJujTIJdTFgs7jk6O6XdH7Cc
+jnn93bfkec5ytaSqa7r9PtoYBr0+Uilmy5wojhhu9XF1TUdq4iRBiYaEvru44uZyTRJFrFZLcCW9
+TpvgPOvlmuNnz6nLgmK+YD65Z7UsSA3IakUlYF44fGbQRqG02iBohSkjnKtRaZp99sBiy9rSymKq
+suTkyTP6gyHju1tmiyXOeW5ubwhAK2sgd3s0xDpHu92h1e5SVTVb3TbgWeRrILAzGpDnBWkSs9Vt
+s7e7w93dLVtbA2bTOVoKiqpECkEaa/qDIc7VrGdTyvUauxxj6zU+2yIn2XSfDTnVWiOlIASPare7
+nyVZhlaGTq+D95bKOgajHebzBXd3dzhXM53OqF2g3+txdnKM957T00ebqhozGu3gPThviYxmvV6j
+pWBvMCBqtYmiiEgrdGTYHY3w3lFXFVVVNdcK6G0N6Q62aPeGvLt4y+W7c/Ki4ODpc+5KSWFBbIio
+EHLDrmn6JJMkRElKlCbsbG/T7XTZPzxECFiuc4IUSKVBabZ3dzg+OsQGSZS2yIuSbn9IXVmGwx5P
+Hh1T1Y40S7m5uWY2ueObV9/y5ZdfIkTARDE+NN5vt9t89NGHZO02zjUE9Ysvv+Ty4gohAov5HCEV
+O8enTArPJK9/0BWspSwLrK0b5m4MstPpkmUtojgmzVJMknF0ckbtAsZE5HlBkIr9/X263S5eaNZF
+xf7+EU+fPuN+MmU8mbAzHNLLYqy1dNKMrW6XTq9HnMScHu3x6GiP5WKOdZ4oikizDneTGds7O7R7
+PfJ1gVaal6++ZTqbk3b7YAwrJ3l5s8CHhik4a7GuJnjXkM2HRi6K40ZiAawXDHf2sNbhbM1qtaLT
+6zEajUizlE6nizYR1lqKokAISVXkeG/xdUmxXnJ7e0O+XJKvC+I44c33b3BViatL5vMZL168Ynt3
+j9HuPt2tEVmnx8nJKTpJGe3to6RmOp1ikgQrJPOiJjIxQj60uQ42bLmRsDTKGLSta6q6ot3ukLZb
+dHpdrs/PcR463S7tTgcQZGnGzu4OSimODvaZzqbYOqfMFzw63CXSithEHIz6VFXByeE+OjKkUUwW
+KSIJ88kdKsroDwacX92ymM0xCsqypNVqcXV923AoJNu7e0ynC7q9PlcFSCdxoekilWp0MqObFpsK
+tHOOJIpx1pLECYvplFanRxtPVVbsbO8RfM1oNOLo6AgtYTmd0sliBr0OnVZCGmuKfM79dMwnHz1D
+6ojz80t6/S6nhzsIW6OVRMnAwc4A7xzfvXjBsN+j085wzrNeF3RpxIbZdMZZf8Dh8SnLdUmgBOFR
+SiLUxhNCoFQjFnqt0UI0SBBFjToopcboCGMUjx7v0e20ubg4Zzq+RVRrXr/6LWmy4os/X/Hhk0/4
++PlHDIcj7u6nvP7+nJ9+8hPSNKXX67EzHDRs4eaK1XJBEhsePz4CV/Hk9IDeYEQSRdxcXbHK16Ak
+dW0J3jOe3NHK2lzOVljnUdIgRGi4nFJoJRAhNAVSKdT27t5nAogjw2g0QiIpigJrLVGSkOc5q+k9
+j/e3+OJ3v+Vv/lPCzWSKefZjnjx9gp19QXvwjJNHH/DyxUuGo20CgeFwQDttMZ1O6PW7fPrpx+wP
+O9ze3fL5//0NxfI1l2+vyVpdnPfMZ3MGo22q2tJptdC60bEupjlq0wlKKfEERAhoJTfXNH2QfIAv
+V1u8tUgpKMuCyeSOf/vNv/DqxZ/5+U8/4Wd/8R/Z2TmmOxiSxA3XYfUVx/spn//bb1kUFqTi8uoa
+KTXdThcdR8RxzLOPfkTtIK+/ZpG9pvXjH/PX/+UJP3oy5nf/+hu0EkRJgrUehcRvZM77+YLKBYRq
+FEylFMIHQnCb6GlUmqZTFBJvLSF4rq6vWa6WpGnC3e01MlhOjo/wCFaV5We//Av+9E3Ojz95znH9
+Lfu7I5ZrwcvzObUXdPtbxGlCUa6Z3t/j6oqqsgx3D7k8/4aTk4R8PMZe/G9qVqTdbc4eP+H08WOU
+gHfnbxnfXHH+/Rtm0ynzvMR5j3WNfPSgkTVCh9wIhs3fVK/X/0wpiRABrRSj7R0m41v6vQ5PHj9i
+sViQr5ZU64LHHzxDygFvvr+hnQlurhf8+ncVl1c3fPyTT7k4/55ev4+taiIpMFGE94Hto2P+z7/+
+gZ09wVYn4Xh/i6S1x6//+2v+89/8A8YY0sjQ63RYrXLa7RadTod5aVk7gZCNpEQIKCXRSqE3B7G2
+xvmADsFD8EihKaoSISVFkXN48IgkTWi125y/u+T65o6vX7zi5z/5hJ//4u9YlTV//uYlMvwzs/mM
+u6tLkiQjzws0gdIYTBTT6kjy2ZRvX7/mxZuc58+7BCJqb/nrf/wn4jTi3ZvXVEWJc56j0xMuzs9Z
+LJa4oBGqoSONZB1QUqKVRCIJwRGC+He61kZSCc4RxRFPHp8RxxF7e3sEPLfXl1gXcM7xzavvOH93
+yUcf/5hPfvIxq7ImGR0ymy+5v5/T73fo9PtUtmKd50ghuXz3jmxrl6dnR3z46ackWcLNxQXfvXrF
+1cUllXXsDgc8+w8fkSQR88ktN+N76mxIFBncpv8RG91ZblRO7wJBuAbVet3+Z0IEyrJECMn+4RFn
+Z8csp2PiNGV7e4dBv88f/vA51zfXGK0RSuGC4upmzHg65+76mtV8yt7+AdujEaPBFrvbA9ZFRVVW
+XF9eUaA5e3TG3s6Ir776E19/+Sdurm/QStGKIp48e8bR6Qm2rpHB4XXE3Kn3Cv+DOmm0QiuJ2IjZ
+1jnqukInaUK318X7RiVZTO9ZzLpYH4iNYb1aoaKYf/jH/8YfP/+c8XiMMobHaUpeW6qywkSaODFs
+7++TKEkaa5TUdDpdhFTc3N0xnc1YLNd8/vvPeX1+zv3tDVIKep02R4f7HB4fsVrMqYqCTneLarwm
+ULyfADTyKygpwHmss43M5DzBe1S/3/vMe0ddlmgJVVXQ7/e5H485f/ManOPq6pLF7J7BcMTN7d2G
+ERumk3t6W0Nur67I87zRiyNDN0tot7usiop35++4ur7Z9Cwd2qkh2BKjFc+envH4yRO2Bn20aurG
+anbP/XTBi8tGO5Abyi5EIDbNEOlBuHbObaZeHrV/ePhZbCK0bhqUOIp+GKAEy2q15OzxI7Z3hjx9
++hQhIF/l1NY2Ek8cc3p2wu3NNUJp+r0erazFfD7j5nbMYj7F1o7jsxOkaITtar1CS8FgOKCVRiym
+93zxxy+Yjm9YLuZc3M6ZrJvZoPUO5y1aSiJj0FJhbd2M47x/fyAdRQajDc5BZAxGKxaLBUfHh1y+
+fc3Hz59zdnZGq52hpGRvf588X5NXnjgyPHp8hneOJ49OubtfcPntKxa3V9TWQoBur8tf/vJXKK1Z
+zCYs7u85ODig3+tw+uQxs8kYt7VFVRaslguKouY2t7iHISgerRWYhkI9iN1CiM1wtMkVaXREp9sh
+jhPanTZJHINzWOs4ODjg6xcv+d3vf0++LqitByHobg1ZFyWrPOf25oadnW3OTo+5f/eKePySX23V
+/LJToe6+w5YF7W6HLEtIohjrPL1ej0cffIiR4n3NODl7RJpmZN0t8spuBPJmSqaEBNcMiKT8gcI3
+478GftXJ6elnSknW+Yq6rOj1+qzzFdZ7nK3ZHvRYTO+pqpI46+AC9HoDDvZ2kcEzm004PNhn5/CY
+k8dP+dPXrxFVSStOWe8+47/+3d/T63W5fvuWm5s78vUaISVZq0UUZ6yLNbfv3vLm9UuMifnucsLa
+gVSNOK2UQmvZKIuyGaIGAt55bO3eq5bq8eMnn9m62kyTPHe3N0RRBELSbreROuLs7BGd7oDVaoXz
+8MEHTynWCyKt2R5uoZUhTlNaWYuqrPgfv/4XcpHwq7/9ew729xChJk2a4dDh/jZbo23m8zlVsWI+
+uSafT7BVxar03C1LShcQUv4wVRYCrQ1s2G7wnrq2m6ruEYAOeKRUuFDhnKPVbuGcY2d/n939fYSz
+TOcL3nz7DfvHZ5w83uZufM9gMMTVNdY6TJKwWMwp8jX9wRbBRIyefYi3FdZVYD1vX7/BRDFJp0Or
+04Zqyer+gmpd4p2nN9xneTenqCZIodHGUJZlM3uUBu9BCI9sxi5oJfFaI72nrmt0CAJJM7fwQJRm
+nD56RL5cYmtLGhmyWNLfek6VL1iMr5lNbhlujzBa0e1uka/XBO+ZTWfc3tyg45i6toxvr8niBjK7
+w22wBUorFtNbynyBy+e0sgyRDKhEyvLdmEgrPArBhpV7h4p0M9YDlHgYk0ucD+ACwjnUzu7OZ943
+o6v21hbBB6hrBtu7fP2nP5K1OxweHWNEYDgaUeVLWt0es8mEqizJ12u8h/HknqqquHz7lt3hgKIq
+sSE0CocQ4GuSLGG9mGPLHOMK2qMDkt4eXqcsCsd3r99Q1jUog6dpgR+2JYw2TY5s9i6stbjNFNpa
+i272TmC0vcvt1SXaaOh2eP3i//Hs+SeMhkMWyzXbwz62XLF3csZqsaDXbqG0Il8tGK8WoGOG2/v8
+6q/+CrynnWUgAnVdcXf9PVmkWY0d2/tHFIslRC2K2pFkEeuipKwdelO1MXKjmDSVW0uJ180YPNCI
+ELXzVPUPhVEmSUwcxVycv6VYr6mrmqoseP7JT7Flwbu355R1zbffvUHomLIsieMILQWtWHOwM+J4
+u88gctjVlPl8jtQKExsIjvViiqtKymJN1t3CASbbwqkEGyR5UZF1+iAVi/EYpTVJ2oJN57dpmpol
+hc0GxkPteJjdCwK6KBqpppVlrJYrnK3ZPzri/O05CDg6Pubi7ffs7x9QW0d+e0cnizGy2R+x64Jg
+SzpZRtbrsrawXkwpVjNsXSG8RzbbL1TFGiEVrd4QW1ekWZegYmrrWS3mrNc5cdqC4DcTY0WSpiht
+QP6wnPPweb+AAOj5bEaaxqxWK+LY0N3q8+LrF0Ra8+jJI6aTCe1WxjpfkqZHpFpT5Qv6wz5VndNO
+U0wWEyUt4labWDQvtc7jfcDXFVKAwqG0bnRbExGlbWSUEIKgrNbcXl7Q6XbJPWBrImMgTZteXan3
+7e/Dz4PqGAL4EJp+xDmPNhqtIxbTBd5Zkm6LgODq4pzR7gGtVsY//6//yc9+8ilGSWrv6PSGSKVI
+kpg0zVBJRqpjXAhUdY0gEKxGbQQ1rTVJ1kLHMVIn1M7hPdzfj6mLHCEF1joiqXDOvl9KeL/+sYFe
+ABFoFnLqBr61c5bgJQhDZWvy5ZI0idneO+D1qxfsHx5z/uY7fvqLX9BODJfv3rG3PYTQwkQpcWQQ
+WmPiDGUSlNZY7xuq4z1qM3qWWiHY/JYaKSTW1qzzkuVsSl0WdLp98Ip8k8RShPdKifeBsBEa2Czd
+BNcsrHnv+f9Qc51Rfhz5VAAAAABJRU5ErkJggg=="/>
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="4" startGlyphID="4">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <image x="0" y="-1000" width="1000" height="1000"
+ transform="scale(0.5) rotate(-45),translate(800,500)"
+ xlink:href="data:image/png;base64,
+iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9
+kT1Iw0AYht+m1opUHOwgopChOlkQFXXUKhShQqkVWnUwufQPmjQkKS6OgmvBwZ/FqoOLs64OroIg
++APi6OSk6CIlfpcUWsR4x3EP733vy913gFAvM9XsGANUzTJS8ZiYya6KwVd0YggBmtMSM/W5ZDIB
+z/F1Dx/f76I8y7vuz9Gj5EwG+ETiWaYbFvEG8dSmpXPeJw6zoqQQnxOPGnRB4keuyy6/cS44LPDM
+sJFOzROHicVCG8ttzIqGSjxJHFFUjfKFjMsK5y3OarnKmvfkLwzltJVlrtMaRByLWEISImRUUUIZ
+FqK0a6SYSNF5zMM/4PiT5JLJVQIjxwIqUCE5fvA/+N1bMz8x7iaFYkDgxbY/hoHgLtCo2fb3sW03
+TgD/M3CltfyVOjDzSXqtpUWOgN5t4OK6pcl7wOUO0P+kS4bkSH5aQj4PvJ/RN2WBvluge83tW/Mc
+pw9AmnqVuAEODoGRAmWve7y7q71v/9Y0+/cDaP1yo4gSHTAAAAAGYktHRAD/AP8A/6C9p5MAAAAJ
+cEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfmBh0FBzE5rnzLAAAAGXRFWHRDb21tZW50AENyZWF0
+ZWQgd2l0aCBHSU1QV4EOFwAAF45JREFUaN5NmnmPZOd13n/vdrdau6p6X2cjw5FIarMjAYmDwP7H
+Buz4K/ib8IMFQaAgtiVLoRRSociZIWc4Pb1Xda237vIu+eNWD91AoYHuu9R7luc85zlHfPyzvwxC
+CJRSzUdKpJAIKVBSIZVESoGUGqkkQggIASkE2miMiTGRQWmNkAqlNVobBMDmPgApwVmHrWu894QQ
+CCHgvcMHh6stdVVh6xpra5xzeO/xLry/NtBcj5AIIRFSEbzFe49+OIQQAgDnPSiBbL4KUki0Nmhj
+EFIhmz8jCGhtMFHzP6kNSjbPkVJuDNC88OGLSCnRujlYAELwBB/w3uOURWlFXSlUrTYHCVhrsdbi
+nYMQmpcTCMGDbyxklELnqxVZlhEnMe00RmtNXlT4zT1CiM2XUkitUUo1X5RAYwSNVM0hpJSNR1Tj
+GQDvHMH7H7wYxSitQIBznrquCD6g/A/etNbi6sYrVVUhpaSuKpxrjOGdJwgAj6Ixnp7f3xOcY7uX
+koiSSHq2tmIqJ5nmDgSEjSWEEO89h5CNbRrT/uAJuTm0kCBEY3sB3nmEkGjTeLDxkCd4R+0tbO5H
+GYRonqOsbV4QAhiNEDThJj3Ob8LNe4IQ6LquSSJBMb+DJEbLDqv5HEFgf2vAfSFwm9AQgBQCAc0D
+mtMhnGvCSza5JVXjPSEEMki8dwQNUor3BxZC4JxDSYXXAS003nlq6sZwm+u0VoSgYRMB3nu89yjv
+sbbJI2stuixLYi2JtCB4j/OerNXG2pp8MeNkZ4/7UlA4scmaTXw/eEgqpNKbsFIo80P4KaXe3+G9
+33jQN/GNQAiIohgjIkIIOGubCPAe4SRBBqTSGEBKiXNNoldVSV1VgMOHJo908BatBFpKUAofwPqA
+1IY4Sbi6vODw6JhZrcitINBY6n1ia4UypvGA1Jtc2RxISgQNmDjnmuOH5lCB0ACB0htLO5QySKUJ
+/gHRNogZNO1EESlQQuCQfPXqbYN4zuKcQ7MJF6M1QRkCAakU7U6XVtYijlMuLy94/PgJN+tAXoEy
+5j3SSalQ2qB0hNIKIR5gXDWhhAAhiIxBCEHw7j38eu+xwRMCTV7JxstJ6pBCYG1NL1KIakm5XiDi
+mKJyWA9pnJDna4Jv7tEASkmM1mBiRJSCVAQfEErT7Q+RAi4vLzk9OeWm1NRe8IDDSjfJ+YDryugm
+R4RAbpI2iAYctNIELwnBbzzUWDiEJokfwjGKElItSOqcYrHAC0Wr08V7qOoCrSDa1C4fAjiHbGqC
+IIkNWRqhdESSddAmoi4rAoJWp4fSEefn33O8FZHGGi3VxitgjEZrjRQCfIMkG5gjCFBKNcWMQBAC
+ROO5wMYAQqC1xhiDkpJRS7DFgipfESUt+oMRUZxS1RZb1yhtqF1A6wit9cPHgJBEJiJNIlZWEJuI
+yGjanS7tdpe6LljM5tzf3fP2u1f86NOf8tXFErEpeloJpGxCFATOe0QIiOAJtoFv5wLONcgFzWGt
+d3jvfvCcr9lSBevxFfm6Imv1iJIMtKGoAx5JCJbaB1br4n2RDSGgIxNTWY8yMVJKtjoJ66pExm28
+k2iTEJAcnD4ijiPOv39D+vVXPPvwYy6XnkBjTUkDpw+1QkqBtxYTxzjvCIALHufY5IoHIQk4rHfs
+dWKicsLlu7fErT7HHzwj7XSxtSXPS2qviPMlaE0R9HvkZINoWinF/XxJGhuEaSGATqqxviROeoQQ
+iGNDvfaYTTH7/uKSk0dPuL+eouOMdqeLtTVCgKstaZq8x3wdpyRJRgAm9xOyrIVUEhU30FyVOU92
+2qwuX3F3fU2vNyLt9DFCUeUlJmkTqIi1opUYpG8xWVmUVCA9nuY5WghBWVm8MqRJipMGIQVtbTDU
+xKJiPZ8xn9xxP5kwnU4pqpKXL1+xv3vI9WxJvbQkaUZQEYaAK0ustSzXOXHWwtY1rU6HNElZLleb
+QgrClfzouM/tyy8Zj8cMBiN2Dk+R0lB7CEGwXMyJsERRwBkJnR7VbIzRDe+rbQM6OooilFJcXFxx
+cBhhIkeBwtUOQk2IPMFbnHWUZUlVV3gfuLy+JW31SJUgVoJgK7TSIAVKR9wsl0Qm4ur8Lds7O8zr
+mrqucOucxbrEuprjYZtqUvLq5UtGox2ybg+TtUmzLs5DsVqQhhVSwMpKtDLkziCFRKkG/bRSeEB1
+Or3PlJJ0OxmDwQC3nFBbx83tFdI7itJSV5YgoaprDo+PMUazWq+pqpp22iJKE9I0Y11WGAkhOG5u
+b2lnGb1uC7xltcxZr5cc7QwZdlv0WgnVcsLk8px3Fxc8OjxEKUmcthju7KKlJNaANORlwNclJoq4
+mJcUVUUIDoJAiA2r9iFQWUdZOySO8WxJ4RaUZcVUgI5bmCxj2O3SHu7g6wrrHM55ptN7autpLZc4
+F9je2WXQHTCezEhjTb5eEBvJ6ekJ08USgsOohnvNbs4RtmBrsMUTLSmqnJ7uIao1dr0k6/YpdMTa
+KtK0xlaeiY02sKtwLsKHGuEE4NFFsabVarNcLvAIFkVBXlr29w4Y7WwTxTHWVSgpGN/cYG2FkIok
+a1FaT1Hm6EJTVo502aKqSlpJhNYSay11XXBzfc79dMn29pDx7B5XFWhfo2NDnKT84oMPmU/GCJ2Q
+z2csxzcgFT4I2tqx9BXnF+dcsEUAlIkxG1JceY+UBm1tTVmWFDZjPJujTIJdTFgs7jk6O6XdH7Cc
+jnn93bfkec5ytaSqa7r9PtoYBr0+Uilmy5wojhhu9XF1TUdq4iRBiYaEvru44uZyTRJFrFZLcCW9
+TpvgPOvlmuNnz6nLgmK+YD65Z7UsSA3IakUlYF44fGbQRqG02iBohSkjnKtRaZp99sBiy9rSymKq
+suTkyTP6gyHju1tmiyXOeW5ubwhAK2sgd3s0xDpHu92h1e5SVTVb3TbgWeRrILAzGpDnBWkSs9Vt
+s7e7w93dLVtbA2bTOVoKiqpECkEaa/qDIc7VrGdTyvUauxxj6zU+2yIn2XSfDTnVWiOlIASPare7
+nyVZhlaGTq+D95bKOgajHebzBXd3dzhXM53OqF2g3+txdnKM957T00ebqhozGu3gPThviYxmvV6j
+pWBvMCBqtYmiiEgrdGTYHY3w3lFXFVVVNdcK6G0N6Q62aPeGvLt4y+W7c/Ki4ODpc+5KSWFBbIio
+EHLDrmn6JJMkRElKlCbsbG/T7XTZPzxECFiuc4IUSKVBabZ3dzg+OsQGSZS2yIuSbn9IXVmGwx5P
+Hh1T1Y40S7m5uWY2ueObV9/y5ZdfIkTARDE+NN5vt9t89NGHZO02zjUE9Ysvv+Ty4gohAov5HCEV
+O8enTArPJK9/0BWspSwLrK0b5m4MstPpkmUtojgmzVJMknF0ckbtAsZE5HlBkIr9/X263S5eaNZF
+xf7+EU+fPuN+MmU8mbAzHNLLYqy1dNKMrW6XTq9HnMScHu3x6GiP5WKOdZ4oikizDneTGds7O7R7
+PfJ1gVaal6++ZTqbk3b7YAwrJ3l5s8CHhik4a7GuJnjXkM2HRi6K40ZiAawXDHf2sNbhbM1qtaLT
+6zEajUizlE6nizYR1lqKokAISVXkeG/xdUmxXnJ7e0O+XJKvC+I44c33b3BViatL5vMZL168Ynt3
+j9HuPt2tEVmnx8nJKTpJGe3to6RmOp1ikgQrJPOiJjIxQj60uQ42bLmRsDTKGLSta6q6ot3ukLZb
+dHpdrs/PcR463S7tTgcQZGnGzu4OSimODvaZzqbYOqfMFzw63CXSithEHIz6VFXByeE+OjKkUUwW
+KSIJ88kdKsroDwacX92ymM0xCsqypNVqcXV923AoJNu7e0ynC7q9PlcFSCdxoekilWp0MqObFpsK
+tHOOJIpx1pLECYvplFanRxtPVVbsbO8RfM1oNOLo6AgtYTmd0sliBr0OnVZCGmuKfM79dMwnHz1D
+6ojz80t6/S6nhzsIW6OVRMnAwc4A7xzfvXjBsN+j085wzrNeF3RpxIbZdMZZf8Dh8SnLdUmgBOFR
+SiLUxhNCoFQjFnqt0UI0SBBFjToopcboCGMUjx7v0e20ubg4Zzq+RVRrXr/6LWmy4os/X/Hhk0/4
++PlHDIcj7u6nvP7+nJ9+8hPSNKXX67EzHDRs4eaK1XJBEhsePz4CV/Hk9IDeYEQSRdxcXbHK16Ak
+dW0J3jOe3NHK2lzOVljnUdIgRGi4nFJoJRAhNAVSKdT27t5nAogjw2g0QiIpigJrLVGSkOc5q+k9
+j/e3+OJ3v+Vv/lPCzWSKefZjnjx9gp19QXvwjJNHH/DyxUuGo20CgeFwQDttMZ1O6PW7fPrpx+wP
+O9ze3fL5//0NxfI1l2+vyVpdnPfMZ3MGo22q2tJptdC60bEupjlq0wlKKfEERAhoJTfXNH2QfIAv
+V1u8tUgpKMuCyeSOf/vNv/DqxZ/5+U8/4Wd/8R/Z2TmmOxiSxA3XYfUVx/spn//bb1kUFqTi8uoa
+KTXdThcdR8RxzLOPfkTtIK+/ZpG9pvXjH/PX/+UJP3oy5nf/+hu0EkRJgrUehcRvZM77+YLKBYRq
+FEylFMIHQnCb6GlUmqZTFBJvLSF4rq6vWa6WpGnC3e01MlhOjo/wCFaV5We//Av+9E3Ojz95znH9
+Lfu7I5ZrwcvzObUXdPtbxGlCUa6Z3t/j6oqqsgx3D7k8/4aTk4R8PMZe/G9qVqTdbc4eP+H08WOU
+gHfnbxnfXHH+/Rtm0ynzvMR5j3WNfPSgkTVCh9wIhs3fVK/X/0wpiRABrRSj7R0m41v6vQ5PHj9i
+sViQr5ZU64LHHzxDygFvvr+hnQlurhf8+ncVl1c3fPyTT7k4/55ev4+taiIpMFGE94Hto2P+z7/+
+gZ09wVYn4Xh/i6S1x6//+2v+89/8A8YY0sjQ63RYrXLa7RadTod5aVk7gZCNpEQIKCXRSqE3B7G2
+xvmADsFD8EihKaoSISVFkXN48IgkTWi125y/u+T65o6vX7zi5z/5hJ//4u9YlTV//uYlMvwzs/mM
+u6tLkiQjzws0gdIYTBTT6kjy2ZRvX7/mxZuc58+7BCJqb/nrf/wn4jTi3ZvXVEWJc56j0xMuzs9Z
+LJa4oBGqoSONZB1QUqKVRCIJwRGC+He61kZSCc4RxRFPHp8RxxF7e3sEPLfXl1gXcM7xzavvOH93
+yUcf/5hPfvIxq7ImGR0ymy+5v5/T73fo9PtUtmKd50ghuXz3jmxrl6dnR3z46ackWcLNxQXfvXrF
+1cUllXXsDgc8+w8fkSQR88ktN+N76mxIFBncpv8RG91ZblRO7wJBuAbVet3+Z0IEyrJECMn+4RFn
+Z8csp2PiNGV7e4dBv88f/vA51zfXGK0RSuGC4upmzHg65+76mtV8yt7+AdujEaPBFrvbA9ZFRVVW
+XF9eUaA5e3TG3s6Ir776E19/+Sdurm/QStGKIp48e8bR6Qm2rpHB4XXE3Kn3Cv+DOmm0QiuJ2IjZ
+1jnqukInaUK318X7RiVZTO9ZzLpYH4iNYb1aoaKYf/jH/8YfP/+c8XiMMobHaUpeW6qywkSaODFs
+7++TKEkaa5TUdDpdhFTc3N0xnc1YLNd8/vvPeX1+zv3tDVIKep02R4f7HB4fsVrMqYqCTneLarwm
+ULyfADTyKygpwHmss43M5DzBe1S/3/vMe0ddlmgJVVXQ7/e5H485f/ManOPq6pLF7J7BcMTN7d2G
+ERumk3t6W0Nur67I87zRiyNDN0tot7usiop35++4ur7Z9Cwd2qkh2BKjFc+envH4yRO2Bn20aurG
+anbP/XTBi8tGO5Abyi5EIDbNEOlBuHbObaZeHrV/ePhZbCK0bhqUOIp+GKAEy2q15OzxI7Z3hjx9
++hQhIF/l1NY2Ek8cc3p2wu3NNUJp+r0erazFfD7j5nbMYj7F1o7jsxOkaITtar1CS8FgOKCVRiym
+93zxxy+Yjm9YLuZc3M6ZrJvZoPUO5y1aSiJj0FJhbd2M47x/fyAdRQajDc5BZAxGKxaLBUfHh1y+
+fc3Hz59zdnZGq52hpGRvf588X5NXnjgyPHp8hneOJ49OubtfcPntKxa3V9TWQoBur8tf/vJXKK1Z
+zCYs7u85ODig3+tw+uQxs8kYt7VFVRaslguKouY2t7iHISgerRWYhkI9iN1CiM1wtMkVaXREp9sh
+jhPanTZJHINzWOs4ODjg6xcv+d3vf0++LqitByHobg1ZFyWrPOf25oadnW3OTo+5f/eKePySX23V
+/LJToe6+w5YF7W6HLEtIohjrPL1ej0cffIiR4n3NODl7RJpmZN0t8spuBPJmSqaEBNcMiKT8gcI3
+478GftXJ6elnSknW+Yq6rOj1+qzzFdZ7nK3ZHvRYTO+pqpI46+AC9HoDDvZ2kcEzm004PNhn5/CY
+k8dP+dPXrxFVSStOWe8+47/+3d/T63W5fvuWm5s78vUaISVZq0UUZ6yLNbfv3vLm9UuMifnucsLa
+gVSNOK2UQmvZKIuyGaIGAt55bO3eq5bq8eMnn9m62kyTPHe3N0RRBELSbreROuLs7BGd7oDVaoXz
+8MEHTynWCyKt2R5uoZUhTlNaWYuqrPgfv/4XcpHwq7/9ew729xChJk2a4dDh/jZbo23m8zlVsWI+
+uSafT7BVxar03C1LShcQUv4wVRYCrQ1s2G7wnrq2m6ruEYAOeKRUuFDhnKPVbuGcY2d/n939fYSz
+TOcL3nz7DfvHZ5w83uZufM9gMMTVNdY6TJKwWMwp8jX9wRbBRIyefYi3FdZVYD1vX7/BRDFJp0Or
+04Zqyer+gmpd4p2nN9xneTenqCZIodHGUJZlM3uUBu9BCI9sxi5oJfFaI72nrmt0CAJJM7fwQJRm
+nD56RL5cYmtLGhmyWNLfek6VL1iMr5lNbhlujzBa0e1uka/XBO+ZTWfc3tyg45i6toxvr8niBjK7
+w22wBUorFtNbynyBy+e0sgyRDKhEyvLdmEgrPArBhpV7h4p0M9YDlHgYk0ucD+ACwjnUzu7OZ943
+o6v21hbBB6hrBtu7fP2nP5K1OxweHWNEYDgaUeVLWt0es8mEqizJ12u8h/HknqqquHz7lt3hgKIq
+sSE0CocQ4GuSLGG9mGPLHOMK2qMDkt4eXqcsCsd3r99Q1jUog6dpgR+2JYw2TY5s9i6stbjNFNpa
+i272TmC0vcvt1SXaaOh2eP3i//Hs+SeMhkMWyzXbwz62XLF3csZqsaDXbqG0Il8tGK8WoGOG2/v8
+6q/+CrynnWUgAnVdcXf9PVmkWY0d2/tHFIslRC2K2pFkEeuipKwdelO1MXKjmDSVW0uJ180YPNCI
+ELXzVPUPhVEmSUwcxVycv6VYr6mrmqoseP7JT7Flwbu355R1zbffvUHomLIsieMILQWtWHOwM+J4
+u88gctjVlPl8jtQKExsIjvViiqtKymJN1t3CASbbwqkEGyR5UZF1+iAVi/EYpTVJ2oJN57dpmpol
+hc0GxkPteJjdCwK6KBqpppVlrJYrnK3ZPzri/O05CDg6Pubi7ffs7x9QW0d+e0cnizGy2R+x64Jg
+SzpZRtbrsrawXkwpVjNsXSG8RzbbL1TFGiEVrd4QW1ekWZegYmrrWS3mrNc5cdqC4DcTY0WSpiht
+QP6wnPPweb+AAOj5bEaaxqxWK+LY0N3q8+LrF0Ra8+jJI6aTCe1WxjpfkqZHpFpT5Qv6wz5VndNO
+U0wWEyUt4labWDQvtc7jfcDXFVKAwqG0bnRbExGlbWSUEIKgrNbcXl7Q6XbJPWBrImMgTZteXan3
+7e/Dz4PqGAL4EJp+xDmPNhqtIxbTBd5Zkm6LgODq4pzR7gGtVsY//6//yc9+8ilGSWrv6PSGSKVI
+kpg0zVBJRqpjXAhUdY0gEKxGbQQ1rTVJ1kLHMVIn1M7hPdzfj6mLHCEF1joiqXDOvl9KeL/+sYFe
+ABFoFnLqBr61c5bgJQhDZWvy5ZI0idneO+D1qxfsHx5z/uY7fvqLX9BODJfv3rG3PYTQwkQpcWQQ
+WmPiDGUSlNZY7xuq4z1qM3qWWiHY/JYaKSTW1qzzkuVsSl0WdLp98Ip8k8RShPdKifeBsBEa2Czd
+BNcsrHnv+f9Qc51Rfhz5VAAAAABJRU5ErkJggg=="/>
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="5" startGlyphID="5">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1000" height="1000">
+ <clipPath id="clip" clipPathUnits="userSpaceOnUse" >
+ <circle cx="500" cy="-500" r="400" />
+ </clipPath>
+
+ <rect x="100" y="-900" width="800" height="800"
+ stroke="green" stroke-width="100"
+ clip-path="url(#clip)" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="6" startGlyphID="6">
+ <![CDATA[<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000">
+ <clipPath id="clip" clipPathUnits="objectBoundingBox">
+ <circle cx=".5" cy=".5" r=".5" />
+ </clipPath>
+
+ <rect x="100" y="-900" width="800" height="800"
+ stroke="green" stroke-width="100"
+ clip-path="url(#clip)" />
+
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="7" startGlyphID="7">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1000" height="1000">
+ <clipPath id="clip" clipPathUnits="userSpaceOnUse" >
+ <circle cx="500" cy="-500" r="400" />
+ <rect x="100" y="-900" width="800" height="400"/>
+ </clipPath>
+
+ <rect x="100" y="-900" width="800" height="800"
+ stroke="green" stroke-width="100"
+ clip-path="url(#clip)" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="8" startGlyphID="8">
+ <![CDATA[<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000">
+ <clipPath id="clip" clipPathUnits="objectBoundingBox">
+ <circle cx=".5" cy=".5" r=".5" />
+ <rect x="0" y="0" width="1" height="0.5"/>
+ </clipPath>
+
+ <rect x="100" y="-900" width="800" height="800"
+ stroke="green" stroke-width="100"
+ clip-path="url(#clip)" />
+
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="9" startGlyphID="9">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1000" height="1000">
+ <clipPath id="clip" clipPathUnits="userSpaceOnUse" >
+ <circle cx="500" cy="-500" r="400" />
+ </clipPath>
+
+ <clipPath id="clip2" clipPathUnits="userSpaceOnUse" >
+ <rect x="100" y="-900" width="800" height="400"/>
+ </clipPath>
+
+ <g clip-path="url(#clip)">
+ <rect x="100" y="-900" width="800" height="800"
+ stroke="green" stroke-width="100"
+ clip-path="url(#clip2)" />
+ </g>
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="10" startGlyphID="10">
+ <![CDATA[<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000">
+ <clipPath id="clip" clipPathUnits="objectBoundingBox">
+ <circle cx=".5" cy=".5" r=".5" />
+ </clipPath>
+
+ <clipPath id="clip2" clipPathUnits="objectBoundingBox">
+ <rect x="0" y="0" width="1" height="0.5"/>
+ </clipPath>
+
+ <g clip-path="url(#clip)">
+ <rect x="100" y="-900" width="800" height="800"
+ stroke="green" stroke-width="100"
+ clip-path="url(#clip2)" />
+ </g>
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="11" startGlyphID="11">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" >
+ <defs>
+ <circle id="circle"
+ cx="0" cy="0" r="250" />
+ </defs>
+
+ <g opacity="0.5">
+ <use xlink:href="#circle" x="330" y="-500"
+ fill="red" />
+ <use xlink:href="#circle" x="670" y="-500"
+ fill="green" />
+ </g>
+</svg>]]>
+ </svgDoc>
+ </SVG>
+
+</ttFont>
diff --git a/test/cairo-svg-test-fill.ttx b/test/cairo-svg-test-fill.ttx
new file mode 100644
index 000000000..b6867ec8f
--- /dev/null
+++ b/test/cairo-svg-test-fill.ttx
@@ -0,0 +1,365 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.19">
+
+ <GlyphOrder>
+ <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="zero"/>
+ <GlyphID id="2" name="one"/>
+ <GlyphID id="3" name="two"/>
+ <GlyphID id="4" name="three"/>
+ <GlyphID id="5" name="four"/>
+ <GlyphID id="6" name="five"/>
+ <GlyphID id="7" name="six"/>
+ <GlyphID id="8" name="seven"/>
+ <GlyphID id="9" name="eight"/>
+ </GlyphOrder>
+
+ <head>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x71e2812"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Wed Jun 15 00:00:00 2022"/>
+ <modified value="Fri Jul 1 06:21:40 2022"/>
+ <xMin value="0"/>
+ <yMin value="0"/>
+ <xMax value="1000"/>
+ <yMax value="1000"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="6"/>
+ <fontDirectionHint value="2"/>
+ <indexToLocFormat value="0"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="0x00010000"/>
+ <ascent value="1000"/>
+ <descent value="0"/>
+ <lineGap value="200"/>
+ <advanceWidthMax value="1100"/>
+ <minLeftSideBearing value="0"/>
+ <minRightSideBearing value="100"/>
+ <xMaxExtent value="1000"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ <numberOfHMetrics value="1"/>
+ </hhea>
+
+ <maxp>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="0x10000"/>
+ <numGlyphs value="10"/>
+ <maxPoints value="4"/>
+ <maxContours value="1"/>
+ <maxCompositePoints value="0"/>
+ <maxCompositeContours value="0"/>
+ <maxZones value="1"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="256"/>
+ <maxSizeOfInstructions value="1"/>
+ <maxComponentElements value="0"/>
+ <maxComponentDepth value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="1000"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00000001"/>
+ <ySubscriptXSize value="600"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="600"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="300"/>
+ <yStrikeoutSize value="0"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="0"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="djr "/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="48"/>
+ <usLastCharIndex value="56"/>
+ <sTypoAscender value="1000"/>
+ <sTypoDescender value="0"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="300"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="720"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="3"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="1100" lsb="0"/>
+ <mtx name="eight" width="1100" lsb="0"/>
+ <mtx name="five" width="1100" lsb="0"/>
+ <mtx name="four" width="1100" lsb="0"/>
+ <mtx name="one" width="1100" lsb="0"/>
+ <mtx name="seven" width="1100" lsb="0"/>
+ <mtx name="six" width="1100" lsb="0"/>
+ <mtx name="three" width="1100" lsb="0"/>
+ <mtx name="two" width="1100" lsb="0"/>
+ <mtx name="zero" width="1100" lsb="0"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="0" platEncID="3" language="0">
+ <map code="0x30" name="zero"/><!-- DIGIT ZERO -->
+ <map code="0x31" name="one"/><!-- DIGIT ONE -->
+ <map code="0x32" name="two"/><!-- DIGIT TWO -->
+ <map code="0x33" name="three"/><!-- DIGIT THREE -->
+ <map code="0x34" name="four"/><!-- DIGIT FOUR -->
+ <map code="0x35" name="five"/><!-- DIGIT FIVE -->
+ <map code="0x36" name="six"/><!-- DIGIT SIX -->
+ <map code="0x37" name="seven"/><!-- DIGIT SEVEN -->
+ <map code="0x38" name="eight"/><!-- DIGIT EIGHT -->
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+
+ <!-- The xMin, yMin, xMax and yMax values
+ will be recalculated by the compiler. -->
+
+ <TTGlyph name=".notdef"/><!-- contains no outline data -->
+
+ <TTGlyph name="eight" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="five" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="four" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="one" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="seven" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="six" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="three" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="two" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="zero" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Cairo Svg Test Fill
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Cairo Svg Test Fill Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="0"/>
+ <underlineThickness value="0"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+ <CPAL>
+ <version value="0"/>
+ <numPaletteEntries value="2"/>
+ <palette index="0">
+ <color index="0" value="#C5A1D7FF"/>
+ <color index="1" value="#80DFC8FF"/>
+ </palette>
+ <palette index="1">
+ <color index="0" value="#6392A9FF"/>
+ <color index="1" value="#7896B3FF"/>
+ </palette>
+ </CPAL>
+
+ <SVG>
+
+ <svgDoc endGlyphID="0" startGlyphID="0">
+ <![CDATA[<svg xmlns="http://www.w3.org/2000/svg"></svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="1" startGlyphID="1">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="indigo" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="2" startGlyphID="2">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="#AA55AA" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="3" startGlyphID="3">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="#A5A" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="4" startGlyphID="4">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="rgb (75, 0 , 130)" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="5" startGlyphID="5">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="currentColor" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="6" startGlyphID="6">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="var(--color1, red)" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="7" startGlyphID="7">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="magenta" fill-opacity="0.5" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="8" startGlyphID="8">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ color="green" >
+ <rect x="100" y="-750" width="800" height="500"
+ fill="currentColor" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="9" startGlyphID="9">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <g transform="scale(5,5) translate(0,-150)">
+ <polygon fill-rule="nonzero"
+ points="50,0 21,90 98,35 2,35 79,90"/>
+ <polygon fill-rule="evenodd"
+ points="150,0 121,90 198,35 102,35 179,90"/>
+ </g>
+</svg>]]>
+ </svgDoc>
+ </SVG>
+
+</ttFont>
diff --git a/test/cairo-svg-test-gradient.ttx b/test/cairo-svg-test-gradient.ttx
new file mode 100644
index 000000000..4a7a22175
--- /dev/null
+++ b/test/cairo-svg-test-gradient.ttx
@@ -0,0 +1,441 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.19">
+
+ <GlyphOrder>
+ <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="zero"/>
+ <GlyphID id="2" name="one"/>
+ <GlyphID id="3" name="two"/>
+ <GlyphID id="4" name="three"/>
+ <GlyphID id="5" name="four"/>
+ <GlyphID id="6" name="five"/>
+ <GlyphID id="7" name="six"/>
+ <GlyphID id="8" name="seven"/>
+ <GlyphID id="9" name="eight"/>
+ <GlyphID id="10" name="nine"/>
+ </GlyphOrder>
+
+ <head>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x4322c7de"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Wed Jun 15 00:00:00 2022"/>
+ <modified value="Fri Jul 1 06:21:39 2022"/>
+ <xMin value="0"/>
+ <yMin value="0"/>
+ <xMax value="1000"/>
+ <yMax value="1000"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="6"/>
+ <fontDirectionHint value="2"/>
+ <indexToLocFormat value="0"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="0x00010000"/>
+ <ascent value="1000"/>
+ <descent value="0"/>
+ <lineGap value="200"/>
+ <advanceWidthMax value="1100"/>
+ <minLeftSideBearing value="0"/>
+ <minRightSideBearing value="100"/>
+ <xMaxExtent value="1000"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ <numberOfHMetrics value="1"/>
+ </hhea>
+
+ <maxp>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="0x10000"/>
+ <numGlyphs value="11"/>
+ <maxPoints value="4"/>
+ <maxContours value="1"/>
+ <maxCompositePoints value="0"/>
+ <maxCompositeContours value="0"/>
+ <maxZones value="1"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="256"/>
+ <maxSizeOfInstructions value="1"/>
+ <maxComponentElements value="0"/>
+ <maxComponentDepth value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="1000"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00000001"/>
+ <ySubscriptXSize value="600"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="600"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="300"/>
+ <yStrikeoutSize value="0"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="0"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="djr "/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="48"/>
+ <usLastCharIndex value="57"/>
+ <sTypoAscender value="1000"/>
+ <sTypoDescender value="0"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="300"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="720"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="3"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="1100" lsb="0"/>
+ <mtx name="eight" width="1100" lsb="0"/>
+ <mtx name="five" width="1100" lsb="0"/>
+ <mtx name="four" width="1100" lsb="0"/>
+ <mtx name="nine" width="1100" lsb="0"/>
+ <mtx name="one" width="1100" lsb="0"/>
+ <mtx name="seven" width="1100" lsb="0"/>
+ <mtx name="six" width="1100" lsb="0"/>
+ <mtx name="three" width="1100" lsb="0"/>
+ <mtx name="two" width="1100" lsb="0"/>
+ <mtx name="zero" width="1100" lsb="0"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="0" platEncID="3" language="0">
+ <map code="0x30" name="zero"/><!-- DIGIT ZERO -->
+ <map code="0x31" name="one"/><!-- DIGIT ONE -->
+ <map code="0x32" name="two"/><!-- DIGIT TWO -->
+ <map code="0x33" name="three"/><!-- DIGIT THREE -->
+ <map code="0x34" name="four"/><!-- DIGIT FOUR -->
+ <map code="0x35" name="five"/><!-- DIGIT FIVE -->
+ <map code="0x36" name="six"/><!-- DIGIT SIX -->
+ <map code="0x37" name="seven"/><!-- DIGIT SEVEN -->
+ <map code="0x38" name="eight"/><!-- DIGIT EIGHT -->
+ <map code="0x39" name="nine"/><!-- DIGIT NINE -->
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+
+ <!-- The xMin, yMin, xMax and yMax values
+ will be recalculated by the compiler. -->
+
+ <TTGlyph name=".notdef"/><!-- contains no outline data -->
+
+ <TTGlyph name="eight" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="five" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="four" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="nine" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="one" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="seven" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="six" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="three" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="two" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="zero" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Cairo Svg Test Gradient
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Cairo Svg Test Gradient Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="0"/>
+ <underlineThickness value="0"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+ <CPAL>
+ <version value="0"/>
+ <numPaletteEntries value="2"/>
+ <palette index="0">
+ <color index="0" value="#C5A1D7FF"/>
+ <color index="1" value="#80DFC8FF"/>
+ </palette>
+ <palette index="1">
+ <color index="0" value="#6392A9FF"/>
+ <color index="1" value="#7896B3FF"/>
+ </palette>
+ </CPAL>
+
+ <SVG>
+
+ <svgDoc endGlyphID="0" startGlyphID="0">
+ <![CDATA[<svg xmlns="http://www.w3.org/2000/svg"></svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="1" startGlyphID="1">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <linearGradient id="grad" x1="33%" x21="66%">
+ <stop offset="0%" stop-color="blue" stop-opacity="1" />
+ <stop offset="100%" stop-color="red" stop-opacity="0.5" />
+ </linearGradient>
+ </defs>
+ <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="2" startGlyphID="2">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <linearGradient id="grad" x1="33%" x2="66%"
+ spreadMethod="reflect">
+ <stop offset="0%" stop-color="blue" stop-opacity="1" />
+ <stop offset="100%" stop-color="red" stop-opacity="1" />
+ </linearGradient>
+ </defs>
+ <rect x="0" y="-900" width="1000" height="800" fill="url(#grad)" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="3" startGlyphID="3">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <linearGradient id="grad" x1="33%" x2="66%"
+ spreadMethod="repeat">
+ <stop offset="0%" stop-color="blue" stop-opacity="1" />
+ <stop offset="100%" stop-color="red" stop-opacity="1" />
+ </linearGradient>
+ </defs>
+ <rect x="0" y="-900" width="1000" height="800" fill="url(#grad)" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="4" startGlyphID="4">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <linearGradient id="grad" x1="300" y1="-500" x2="600" y2="-500"
+ gradientUnits="userSpaceOnUse">
+ <stop offset="0%" stop-color="blue" stop-opacity="1" />
+ <stop offset="100%" stop-color="red" stop-opacity="1" />
+ </linearGradient>
+ </defs>
+ <rect x="0" y="-900" width="1000" height="800" fill="url(#grad)" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="5" startGlyphID="5">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <linearGradient id="grad" gradientTransform="rotate(45)">
+ <stop offset="0%" stop-color="blue" stop-opacity="1" />
+ <stop offset="100%" stop-color="red" stop-opacity="1" />
+ </linearGradient>
+ </defs>
+ <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="6" startGlyphID="6">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <radialGradient id="grad" cx="50%" cy="50%"
+ fx="0.75" fy="0.35" r="0.5">
+ <stop offset="0%" stop-color="white" stop-opacity="1" />
+ <stop offset="100%" stop-color="green" stop-opacity="1" />
+ </radialGradient>
+ </defs>
+ <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="7" startGlyphID="7">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <radialGradient id="grad" cx="75%" cy="25%" r="33%"
+ fx="0.64" fy="0.18" fr="0.17"
+ spreadMethod="reflect" >
+ <stop offset="0%" stop-color="white" stop-opacity="1" />
+ <stop offset="100%" stop-color="green" stop-opacity="1" />
+ </radialGradient>
+ </defs>
+ <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="8" startGlyphID="8">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <radialGradient id="grad" cx="75%" cy="25%" r="33%"
+ fx="0.64" fy="0.18" fr="0.17"
+ spreadMethod="repeat" >
+ <stop offset="0%" stop-color="white" stop-opacity="1" />
+ <stop offset="100%" stop-color="green" stop-opacity="1" />
+ </radialGradient>
+ </defs>
+ <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="9" startGlyphID="9">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <radialGradient id="grad" cx="450" cy="-550" r="400"
+ fx="600" fy="-400" fr="10"
+ gradientUnits="userSpaceOnUse" >
+ <stop offset="0%" stop-color="red" stop-opacity="1" />
+ <stop offset="100%" stop-color="green" stop-opacity="0.5" />
+ </radialGradient>
+ </defs>
+ <rect x="0" y="-1000" width="1000" height="1000" fill="url(#grad)" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="10" startGlyphID="10">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <radialGradient id="grad" cx="50%" cy="25%"
+ fx="0.75" fy="0.35" r="0.5"
+ gradientTransform="scale(1, 2)">
+ <stop offset="0%" stop-color="red" stop-opacity="1" />
+ <stop offset="100%" stop-color="green" stop-opacity="1" />
+ </radialGradient>
+ </defs>
+ <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" />
+</svg>]]>
+ </svgDoc>
+ </SVG>
+
+</ttFont>
diff --git a/test/cairo-svg-test-path.ttx b/test/cairo-svg-test-path.ttx
new file mode 100644
index 000000000..9173a537d
--- /dev/null
+++ b/test/cairo-svg-test-path.ttx
@@ -0,0 +1,281 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.19">
+
+ <GlyphOrder>
+ <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="zero"/>
+ <GlyphID id="2" name="one"/>
+ <GlyphID id="3" name="two"/>
+ <GlyphID id="4" name="three"/>
+ </GlyphOrder>
+
+ <head>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x20ff0b91"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Wed Jun 15 00:00:00 2022"/>
+ <modified value="Fri Jul 1 06:21:40 2022"/>
+ <xMin value="0"/>
+ <yMin value="0"/>
+ <xMax value="1000"/>
+ <yMax value="1000"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="6"/>
+ <fontDirectionHint value="2"/>
+ <indexToLocFormat value="0"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="0x00010000"/>
+ <ascent value="1000"/>
+ <descent value="0"/>
+ <lineGap value="200"/>
+ <advanceWidthMax value="1100"/>
+ <minLeftSideBearing value="0"/>
+ <minRightSideBearing value="100"/>
+ <xMaxExtent value="1000"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ <numberOfHMetrics value="1"/>
+ </hhea>
+
+ <maxp>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="0x10000"/>
+ <numGlyphs value="5"/>
+ <maxPoints value="4"/>
+ <maxContours value="1"/>
+ <maxCompositePoints value="0"/>
+ <maxCompositeContours value="0"/>
+ <maxZones value="1"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="256"/>
+ <maxSizeOfInstructions value="1"/>
+ <maxComponentElements value="0"/>
+ <maxComponentDepth value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="1000"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00000001"/>
+ <ySubscriptXSize value="600"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="600"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="300"/>
+ <yStrikeoutSize value="0"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="0"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="djr "/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="48"/>
+ <usLastCharIndex value="51"/>
+ <sTypoAscender value="1000"/>
+ <sTypoDescender value="0"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="300"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="720"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="3"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="1100" lsb="0"/>
+ <mtx name="one" width="1100" lsb="0"/>
+ <mtx name="three" width="1100" lsb="0"/>
+ <mtx name="two" width="1100" lsb="0"/>
+ <mtx name="zero" width="1100" lsb="0"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="0" platEncID="3" language="0">
+ <map code="0x30" name="zero"/><!-- DIGIT ZERO -->
+ <map code="0x31" name="one"/><!-- DIGIT ONE -->
+ <map code="0x32" name="two"/><!-- DIGIT TWO -->
+ <map code="0x33" name="three"/><!-- DIGIT THREE -->
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+
+ <!-- The xMin, yMin, xMax and yMax values
+ will be recalculated by the compiler. -->
+
+ <TTGlyph name=".notdef"/><!-- contains no outline data -->
+
+ <TTGlyph name="one" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="three" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="two" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="zero" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Cairo Svg Test Path
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Cairo Svg Test Path Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="0"/>
+ <underlineThickness value="0"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+ <CPAL>
+ <version value="0"/>
+ <numPaletteEntries value="2"/>
+ <palette index="0">
+ <color index="0" value="#C5A1D7FF"/>
+ <color index="1" value="#80DFC8FF"/>
+ </palette>
+ <palette index="1">
+ <color index="0" value="#6392A9FF"/>
+ <color index="1" value="#7896B3FF"/>
+ </palette>
+ </CPAL>
+
+ <SVG>
+
+ <svgDoc endGlyphID="0" startGlyphID="0">
+ <![CDATA[<svg xmlns="http://www.w3.org/2000/svg"></svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="1" startGlyphID="1">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <path fill="none" stroke="black" stroke-width="20"
+ d="M 200 -200
+ L 500 -500
+ H 800
+ V -200
+ " />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="2" startGlyphID="2">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <path fill="none" stroke="black" stroke-width="20"
+ d="M200,-400
+ C200,-200
+ 500,-200
+ 500,-400
+ S800,-600
+ 800,-400" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="3" startGlyphID="3">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <path fill="none" stroke="black" stroke-width="20"
+ d="M200,-300
+ Q400,-50
+ 600,-300
+ T1000,-300"
+ />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="4" startGlyphID="4">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <path fill="none" stroke="black" stroke-width="20"
+ d="M500,-500
+ L 712 -712
+ A300,300 0 1,0 712, -288 z"
+ />
+</svg>]]>
+ </svgDoc>
+ </SVG>
+
+</ttFont>
diff --git a/test/cairo-svg-test-shapes.ttx b/test/cairo-svg-test-shapes.ttx
new file mode 100644
index 000000000..15a573a64
--- /dev/null
+++ b/test/cairo-svg-test-shapes.ttx
@@ -0,0 +1,333 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.19">
+
+ <GlyphOrder>
+ <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="zero"/>
+ <GlyphID id="2" name="one"/>
+ <GlyphID id="3" name="two"/>
+ <GlyphID id="4" name="three"/>
+ <GlyphID id="5" name="four"/>
+ <GlyphID id="6" name="five"/>
+ <GlyphID id="7" name="six"/>
+ </GlyphOrder>
+
+ <head>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0xa8919a30"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Wed Jun 15 00:00:00 2022"/>
+ <modified value="Fri Jul 1 06:21:40 2022"/>
+ <xMin value="0"/>
+ <yMin value="0"/>
+ <xMax value="1000"/>
+ <yMax value="1000"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="6"/>
+ <fontDirectionHint value="2"/>
+ <indexToLocFormat value="0"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="0x00010000"/>
+ <ascent value="1000"/>
+ <descent value="0"/>
+ <lineGap value="200"/>
+ <advanceWidthMax value="1100"/>
+ <minLeftSideBearing value="0"/>
+ <minRightSideBearing value="100"/>
+ <xMaxExtent value="1000"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ <numberOfHMetrics value="1"/>
+ </hhea>
+
+ <maxp>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="0x10000"/>
+ <numGlyphs value="8"/>
+ <maxPoints value="4"/>
+ <maxContours value="1"/>
+ <maxCompositePoints value="0"/>
+ <maxCompositeContours value="0"/>
+ <maxZones value="1"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="256"/>
+ <maxSizeOfInstructions value="1"/>
+ <maxComponentElements value="0"/>
+ <maxComponentDepth value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="1000"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00000001"/>
+ <ySubscriptXSize value="600"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="600"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="300"/>
+ <yStrikeoutSize value="0"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="0"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="djr "/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="48"/>
+ <usLastCharIndex value="54"/>
+ <sTypoAscender value="1000"/>
+ <sTypoDescender value="0"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="300"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="720"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="3"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="1100" lsb="0"/>
+ <mtx name="five" width="1100" lsb="0"/>
+ <mtx name="four" width="1100" lsb="0"/>
+ <mtx name="one" width="1100" lsb="0"/>
+ <mtx name="six" width="1100" lsb="0"/>
+ <mtx name="three" width="1100" lsb="0"/>
+ <mtx name="two" width="1100" lsb="0"/>
+ <mtx name="zero" width="1100" lsb="0"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="0" platEncID="3" language="0">
+ <map code="0x30" name="zero"/><!-- DIGIT ZERO -->
+ <map code="0x31" name="one"/><!-- DIGIT ONE -->
+ <map code="0x32" name="two"/><!-- DIGIT TWO -->
+ <map code="0x33" name="three"/><!-- DIGIT THREE -->
+ <map code="0x34" name="four"/><!-- DIGIT FOUR -->
+ <map code="0x35" name="five"/><!-- DIGIT FIVE -->
+ <map code="0x36" name="six"/><!-- DIGIT SIX -->
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+
+ <!-- The xMin, yMin, xMax and yMax values
+ will be recalculated by the compiler. -->
+
+ <TTGlyph name=".notdef"/><!-- contains no outline data -->
+
+ <TTGlyph name="five" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="four" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="one" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="six" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="three" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="two" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="zero" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Cairo Svg Test Shapes
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Cairo Svg Test Shapes Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="0"/>
+ <underlineThickness value="0"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+ <CPAL>
+ <version value="0"/>
+ <numPaletteEntries value="2"/>
+ <palette index="0">
+ <color index="0" value="#C5A1D7FF"/>
+ <color index="1" value="#80DFC8FF"/>
+ </palette>
+ <palette index="1">
+ <color index="0" value="#6392A9FF"/>
+ <color index="1" value="#7896B3FF"/>
+ </palette>
+ </CPAL>
+
+ <SVG>
+
+ <svgDoc endGlyphID="0" startGlyphID="0">
+ <![CDATA[<svg xmlns="http://www.w3.org/2000/svg"></svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="1" startGlyphID="1">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"/>
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="2" startGlyphID="2">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500" rx="100" ry="100"/>
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="3" startGlyphID="3">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <circle cx="500" cy="-500" r="400"/>
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="4" startGlyphID="4">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <ellipse cx="500" cy="-500" rx="400" ry="200"/>
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="5" startGlyphID="5">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="200" y1="-200" x2="800" y2="-800" stroke="black" stroke-width="20"/>
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="6" startGlyphID="6">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <polyline fill="none" stroke="black" stroke-width="20"
+ points="100, -100,
+ 300, -100,
+ 300, -300,
+ 500, -300,
+ 500, -500,
+ 700, -500
+ 700, -700
+ 900, -700
+ 900, -900" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="7" startGlyphID="7">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="500" height="500">
+<polygon points="350, -75
+ 379, -161
+ 469, -161
+ 397, -215
+ 423, -301
+ 350, -250
+ 277, -301
+ 303, -215
+ 231, -161
+ 321, -161" />
+</svg>]]>
+ </svgDoc>
+ </SVG>
+
+</ttFont>
diff --git a/test/cairo-svg-test-stroke.ttx b/test/cairo-svg-test-stroke.ttx
new file mode 100644
index 000000000..a403da928
--- /dev/null
+++ b/test/cairo-svg-test-stroke.ttx
@@ -0,0 +1,608 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.19">
+
+ <GlyphOrder>
+ <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="zero"/>
+ <GlyphID id="2" name="one"/>
+ <GlyphID id="3" name="two"/>
+ <GlyphID id="4" name="three"/>
+ <GlyphID id="5" name="four"/>
+ <GlyphID id="6" name="five"/>
+ <GlyphID id="7" name="six"/>
+ <GlyphID id="8" name="seven"/>
+ <GlyphID id="9" name="eight"/>
+ <GlyphID id="10" name="nine"/>
+ <GlyphID id="11" name="A"/>
+ <GlyphID id="12" name="B"/>
+ <GlyphID id="13" name="C"/>
+ <GlyphID id="14" name="D"/>
+ <GlyphID id="15" name="E"/>
+ <GlyphID id="16" name="F"/>
+ </GlyphOrder>
+
+ <head>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x2d1b9ede"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Wed Jun 15 00:00:00 2022"/>
+ <modified value="Fri Jul 1 06:21:39 2022"/>
+ <xMin value="0"/>
+ <yMin value="0"/>
+ <xMax value="1000"/>
+ <yMax value="1000"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="6"/>
+ <fontDirectionHint value="2"/>
+ <indexToLocFormat value="0"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="0x00010000"/>
+ <ascent value="1000"/>
+ <descent value="0"/>
+ <lineGap value="200"/>
+ <advanceWidthMax value="1100"/>
+ <minLeftSideBearing value="0"/>
+ <minRightSideBearing value="100"/>
+ <xMaxExtent value="1000"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ <numberOfHMetrics value="1"/>
+ </hhea>
+
+ <maxp>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="0x10000"/>
+ <numGlyphs value="17"/>
+ <maxPoints value="4"/>
+ <maxContours value="1"/>
+ <maxCompositePoints value="0"/>
+ <maxCompositeContours value="0"/>
+ <maxZones value="1"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="256"/>
+ <maxSizeOfInstructions value="1"/>
+ <maxComponentElements value="0"/>
+ <maxComponentDepth value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="1000"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00000001"/>
+ <ySubscriptXSize value="600"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="600"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="300"/>
+ <yStrikeoutSize value="0"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="0"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="djr "/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="48"/>
+ <usLastCharIndex value="70"/>
+ <sTypoAscender value="1000"/>
+ <sTypoDescender value="0"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="300"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="720"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="3"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="1100" lsb="0"/>
+ <mtx name="A" width="1100" lsb="0"/>
+ <mtx name="B" width="1100" lsb="0"/>
+ <mtx name="C" width="1100" lsb="0"/>
+ <mtx name="D" width="1100" lsb="0"/>
+ <mtx name="E" width="1100" lsb="0"/>
+ <mtx name="F" width="1100" lsb="0"/>
+ <mtx name="eight" width="1100" lsb="0"/>
+ <mtx name="five" width="1100" lsb="0"/>
+ <mtx name="four" width="1100" lsb="0"/>
+ <mtx name="nine" width="1100" lsb="0"/>
+ <mtx name="one" width="1100" lsb="0"/>
+ <mtx name="seven" width="1100" lsb="0"/>
+ <mtx name="six" width="1100" lsb="0"/>
+ <mtx name="three" width="1100" lsb="0"/>
+ <mtx name="two" width="1100" lsb="0"/>
+ <mtx name="zero" width="1100" lsb="0"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="0" platEncID="3" language="0">
+ <map code="0x30" name="zero"/><!-- DIGIT ZERO -->
+ <map code="0x31" name="one"/><!-- DIGIT ONE -->
+ <map code="0x32" name="two"/><!-- DIGIT TWO -->
+ <map code="0x33" name="three"/><!-- DIGIT THREE -->
+ <map code="0x34" name="four"/><!-- DIGIT FOUR -->
+ <map code="0x35" name="five"/><!-- DIGIT FIVE -->
+ <map code="0x36" name="six"/><!-- DIGIT SIX -->
+ <map code="0x37" name="seven"/><!-- DIGIT SEVEN -->
+ <map code="0x38" name="eight"/><!-- DIGIT EIGHT -->
+ <map code="0x39" name="nine"/><!-- DIGIT NINE -->
+ <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
+ <map code="0x42" name="B"/><!-- LATIN CAPITAL LETTER B -->
+ <map code="0x43" name="C"/><!-- LATIN CAPITAL LETTER C -->
+ <map code="0x44" name="D"/><!-- LATIN CAPITAL LETTER D -->
+ <map code="0x45" name="E"/><!-- LATIN CAPITAL LETTER E -->
+ <map code="0x46" name="F"/><!-- LATIN CAPITAL LETTER F -->
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+
+ <!-- The xMin, yMin, xMax and yMax values
+ will be recalculated by the compiler. -->
+
+ <TTGlyph name=".notdef"/><!-- contains no outline data -->
+
+ <TTGlyph name="A" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="B" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="C" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="D" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="E" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="F" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="eight" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="five" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="four" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="nine" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="one" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="seven" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="six" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="three" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="two" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="zero" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Cairo Svg Test Stroke
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Cairo Svg Test Stroke Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="0"/>
+ <underlineThickness value="0"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+ <CPAL>
+ <version value="0"/>
+ <numPaletteEntries value="2"/>
+ <palette index="0">
+ <color index="0" value="#C5A1D7FF"/>
+ <color index="1" value="#80DFC8FF"/>
+ </palette>
+ <palette index="1">
+ <color index="0" value="#6392A9FF"/>
+ <color index="1" value="#7896B3FF"/>
+ </palette>
+ </CPAL>
+
+ <SVG>
+
+ <svgDoc endGlyphID="0" startGlyphID="0">
+ <![CDATA[<svg xmlns="http://www.w3.org/2000/svg"></svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="1" startGlyphID="1">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-500" x2="900" y2="-500"
+ fill="none"
+ stroke-width="100"
+ stroke="indigo" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="2" startGlyphID="2">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-500" x2="900" y2="-500"
+ fill="none"
+ stroke-width="100"
+ stroke="#AA55AA" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="3" startGlyphID="3">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-500" x2="900" y2="-500"
+ fill="none"
+ stroke-width="100"
+ stroke="#A5A" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="4" startGlyphID="4">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-500" x2="900" y2="-500"
+ fill="none"
+ stroke-width="100"
+ stroke="rgb(75,0,130)" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="5" startGlyphID="5">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-500" x2="900" y2="-500"
+ fill="none"
+ stroke-width="100"
+ stroke="currentColor" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="6" startGlyphID="6">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-500" x2="900" y2="-500"
+ fill="none"
+ stroke-width="100"
+ stroke="var(--color1, red)" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="7" startGlyphID="7">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-500" x2="900" y2="-500"
+ fill="none"
+ stroke-width="100"
+ stroke="magenta" stroke-opacity="0.5" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="8" startGlyphID="8">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ color="green" >
+ <line x1="100" y1="-500" x2="900" y2="-500"
+ fill="none"
+ stroke-width="100"
+ stroke="currentColor" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="9" startGlyphID="9">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-900" x2="900" y2="-900"
+ fill="none"
+ stroke-width="100"
+ stroke="black" />
+ <line x1="100" y1="-500" x2="900" y2="-500"
+ fill="none"
+ stroke-width="200"
+ stroke="black" />
+ <line x1="100" y1="-100" x2="900" y2="-100"
+ fill="none"
+ stroke-width="300"
+ stroke="black" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="10" startGlyphID="10">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-900" x2="900" y2="-900"
+ fill="none"
+ stroke-width="200"
+ stroke-linecap="butt"
+ stroke="black" />
+ <line x1="100" y1="-500" x2="900" y2="-500"
+ fill="none"
+ stroke-width="200"
+ stroke-linecap="round"
+ stroke="black" />
+ <line x1="100" y1="-100" x2="900" y2="-100"
+ fill="none"
+ stroke-width="200"
+ stroke-linecap="square"
+ stroke="black" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="11" startGlyphID="11">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-950" x2="900" y2="-950"
+ fill="none"
+ stroke-width="100"
+ stroke-dasharray="none"
+ stroke="black" />
+ <line x1="100" y1="-750" x2="900" y2="-750"
+ fill="none"
+ stroke-width="100"
+ stroke-dasharray="200"
+ stroke="black" />
+ <line x1="100" y1="-550" x2="900" y2="-550"
+ fill="none"
+ stroke-width="100"
+ stroke-dasharray="200 50"
+ stroke="black" />
+ <line x1="100" y1="-350" x2="900" y2="-350"
+ fill="none"
+ stroke-width="100"
+ stroke-dasharray="200 50 100"
+ stroke="black" />
+ <line x1="100" y1="-150" x2="900" y2="-150"
+ fill="none"
+ stroke-width="100"
+ stroke-dasharray="200 50 100 150"
+ stroke="black" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="12" startGlyphID="12">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-950" x2="900" y2="-950"
+ fill="none"
+ stroke-width="100"
+ stroke-dasharray="none"
+ stroke="black" />
+ <line x1="100" y1="-750" x2="900" y2="-750"
+ fill="none"
+ stroke-width="100"
+ stroke-dasharray="200"
+ stroke-dashoffset="100"
+ stroke="black" />
+ <line x1="100" y1="-550" x2="900" y2="-550"
+ fill="none"
+ stroke-width="100"
+ stroke-dasharray="200 50"
+ stroke-dashoffset="100"
+ stroke="black" />
+ <line x1="100" y1="-350" x2="900" y2="-350"
+ fill="none"
+ stroke-width="100"
+ stroke-dasharray="200 50 100"
+ stroke-dashoffset="100"
+ stroke="black" />
+ <line x1="100" y1="-150" x2="900" y2="-150"
+ fill="none"
+ stroke-width="100"
+ stroke-dasharray="200 50 100 150"
+ stroke-dashoffset="100"
+ stroke="black" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="13" startGlyphID="13">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <polyline
+ points="100, -200
+ 900, -400
+ 100, -700"
+ fill="none"
+ stroke-width="200"
+ stroke-linejoin="miter"
+ stroke="black" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="14" startGlyphID="14">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <polyline
+ points="100, -200
+ 900, -400
+ 100, -700"
+ fill="none"
+ stroke-width="200"
+ stroke-linejoin="round"
+ stroke="black" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="15" startGlyphID="15">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <polyline
+ points="100, -200
+ 900, -400
+ 100, -700"
+ fill="none"
+ stroke-width="200"
+ stroke-linejoin="bevel"
+ stroke="black" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="16" startGlyphID="16">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <polyline
+ points="100, -200
+ 900, -400
+ 100, -700"
+ fill="none"
+ stroke-width="200"
+ stroke-linejoin="miter"
+ stroke-miterlimit="2"
+ stroke="black" />
+</svg>]]>
+ </svgDoc>
+ </SVG>
+
+</ttFont>
diff --git a/test/cairo-svg-test-transform.ttx b/test/cairo-svg-test-transform.ttx
new file mode 100644
index 000000000..1f07c05ad
--- /dev/null
+++ b/test/cairo-svg-test-transform.ttx
@@ -0,0 +1,403 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.19">
+
+ <GlyphOrder>
+ <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="zero"/>
+ <GlyphID id="2" name="one"/>
+ <GlyphID id="3" name="two"/>
+ <GlyphID id="4" name="three"/>
+ <GlyphID id="5" name="four"/>
+ <GlyphID id="6" name="five"/>
+ <GlyphID id="7" name="six"/>
+ <GlyphID id="8" name="seven"/>
+ </GlyphOrder>
+
+ <head>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x970fff1"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Wed Jun 15 00:00:00 2022"/>
+ <modified value="Fri Jul 1 06:21:39 2022"/>
+ <xMin value="0"/>
+ <yMin value="0"/>
+ <xMax value="1000"/>
+ <yMax value="1000"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="6"/>
+ <fontDirectionHint value="2"/>
+ <indexToLocFormat value="0"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="0x00010000"/>
+ <ascent value="1000"/>
+ <descent value="0"/>
+ <lineGap value="200"/>
+ <advanceWidthMax value="1100"/>
+ <minLeftSideBearing value="0"/>
+ <minRightSideBearing value="100"/>
+ <xMaxExtent value="1000"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ <numberOfHMetrics value="1"/>
+ </hhea>
+
+ <maxp>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="0x10000"/>
+ <numGlyphs value="9"/>
+ <maxPoints value="4"/>
+ <maxContours value="1"/>
+ <maxCompositePoints value="0"/>
+ <maxCompositeContours value="0"/>
+ <maxZones value="1"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="256"/>
+ <maxSizeOfInstructions value="1"/>
+ <maxComponentElements value="0"/>
+ <maxComponentDepth value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="1000"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00000001"/>
+ <ySubscriptXSize value="600"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="600"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="300"/>
+ <yStrikeoutSize value="0"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="0"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="djr "/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="48"/>
+ <usLastCharIndex value="55"/>
+ <sTypoAscender value="1000"/>
+ <sTypoDescender value="0"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="300"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="720"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="3"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="1100" lsb="0"/>
+ <mtx name="five" width="1100" lsb="0"/>
+ <mtx name="four" width="1100" lsb="0"/>
+ <mtx name="one" width="1100" lsb="0"/>
+ <mtx name="seven" width="1100" lsb="0"/>
+ <mtx name="six" width="1100" lsb="0"/>
+ <mtx name="three" width="1100" lsb="0"/>
+ <mtx name="two" width="1100" lsb="0"/>
+ <mtx name="zero" width="1100" lsb="0"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="0" platEncID="3" language="0">
+ <map code="0x30" name="zero"/><!-- DIGIT ZERO -->
+ <map code="0x31" name="one"/><!-- DIGIT ONE -->
+ <map code="0x32" name="two"/><!-- DIGIT TWO -->
+ <map code="0x33" name="three"/><!-- DIGIT THREE -->
+ <map code="0x34" name="four"/><!-- DIGIT FOUR -->
+ <map code="0x35" name="five"/><!-- DIGIT FIVE -->
+ <map code="0x36" name="six"/><!-- DIGIT SIX -->
+ <map code="0x37" name="seven"/><!-- DIGIT SEVEN -->
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+
+ <!-- The xMin, yMin, xMax and yMax values
+ will be recalculated by the compiler. -->
+
+ <TTGlyph name=".notdef"/><!-- contains no outline data -->
+
+ <TTGlyph name="five" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="four" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="one" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="seven" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="six" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="three" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="two" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ <TTGlyph name="zero" xMin="0" yMin="0" xMax="1000" yMax="1000">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="1000" on="1"/>
+ <pt x="1000" y="1000" on="1"/>
+ <pt x="1000" y="0" on="1"/>
+ </contour>
+ <instructions/>
+ </TTGlyph>
+
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Cairo Svg Test Transform
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Cairo Svg Test Transform Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="0"/>
+ <underlineThickness value="0"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+ <CPAL>
+ <version value="0"/>
+ <numPaletteEntries value="2"/>
+ <palette index="0">
+ <color index="0" value="#C5A1D7FF"/>
+ <color index="1" value="#80DFC8FF"/>
+ </palette>
+ <palette index="1">
+ <color index="0" value="#6392A9FF"/>
+ <color index="1" value="#7896B3FF"/>
+ </palette>
+ </CPAL>
+
+ <SVG>
+
+ <svgDoc endGlyphID="0" startGlyphID="0">
+ <![CDATA[<svg xmlns="http://www.w3.org/2000/svg"></svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="1" startGlyphID="1">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <rect id="square" width="300" height="300"/>
+ </defs>
+ <use xlink:href="#square" transform="translate(100, -900)"/>
+ <use xlink:href="#square" transform="translate(600, -400)"/>
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="2" startGlyphID="2">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <rect id="square" width="300" height="300"/>
+ </defs>
+ <use xlink:href="#square" transform="translate(100, -900)"/>
+ <g transform="translate(400, -400)">
+ <use xlink:href="#square" transform="scale(1.5, 0.5)"/>
+ </g>
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="3" startGlyphID="3">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <rect id="square" width="300" height="300"/>
+ </defs>
+ <use xlink:href="#square" transform="translate(100, -900)"/>
+ <g transform="translate(600, -600)">
+ <use xlink:href="#square" transform="rotate(30)"/>
+ </g>
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="4" startGlyphID="4">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <rect id="square" width="300" height="300"/>
+ </defs>
+ <use xlink:href="#square" transform="translate(100, -900)"/>
+ <g transform="translate(400, -400)">
+ <use xlink:href="#square" transform="skewX(30)"/>
+ </g>
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="5" startGlyphID="5">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <rect id="square" width="300" height="300"/>
+ </defs>
+ <use xlink:href="#square" transform="translate(100, -900)"/>
+ <g transform="translate(400, -500)">
+ <use xlink:href="#square" transform="skewY(30)"/>
+ </g>
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="6" startGlyphID="6">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <rect id="square" width="300" height="300"/>
+ </defs>
+ <use xlink:href="#square" transform="translate(100, -900)"/>
+ <g transform="translate(600, -600)">
+ <use xlink:href="#square" transform="matrix(1, 0.4, -0.6, 1.1, 50, -70)"/>
+ </g>
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="7" startGlyphID="7">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <path id="heart" d="M 10,30 A 20,20 0,0,1 50,30 A 20,20 0,0,1 90,30 Q 90,60 50,90 Q 10,60 10,30 z" />
+ </defs>
+ <use xlink:href="#heart"
+ transform="translate(10, -650)
+ rotate(-10 50 100)
+ translate(-166 125.5)
+ skewX(40)
+ scale(1 0.5),scale(8, 8)"
+ fill="grey"/>
+ <use xlink:href="#heart"
+ transform="translate(300, -800),scale(6, 6)"
+ fill="none" stroke="red" />
+</svg>]]>
+ </svgDoc>
+ <svgDoc endGlyphID="8" startGlyphID="8">
+ <![CDATA[<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <circle id="c1"
+ cx="100" cy="100" r="80"
+ fill="none"
+ stroke="black"
+ stroke-width="20" />
+ <circle id="c2"
+ cx="100" cy="100" r="80"
+ fill="none"
+ stroke="black"
+ stroke-width="20"
+ transform="scale(3,3)" />
+ </defs>
+
+ <use xlink:href="#c1" x="100" y="-900"/>
+ <use xlink:href="#c2" x="300" y="-700"/>
+
+</svg>]]>
+ </svgDoc>
+ </SVG>
+
+</ttFont>
diff --git a/test/cairo-test-runner.c b/test/cairo-test-runner.c
index 05d04b78e..72aa1ff9b 100644
--- a/test/cairo-test-runner.c
+++ b/test/cairo-test-runner.c
@@ -726,42 +726,6 @@ _has_required_cairo_version (const char *str)
CAIRO_VERSION_ENCODE (major, minor, micro));
}
-static cairo_bool_t
-_has_required_ghostscript_version (const char *str)
-{
-#if ! CAIRO_CAN_TEST_PS_SURFACE
- return TRUE;
-#endif
-
- str += 2; /* advance over "gs" */
-
- return TRUE;
-}
-
-static cairo_bool_t
-_has_required_poppler_version (const char *str)
-{
-#if ! CAIRO_CAN_TEST_PDF_SURFACE
- return TRUE;
-#endif
-
- str += 7; /* advance over "poppler" */
-
- return TRUE;
-}
-
-static cairo_bool_t
-_has_required_rsvg_version (const char *str)
-{
-#if ! CAIRO_CAN_TEST_SVG_SURFACE
- return TRUE;
-#endif
-
- str += 4; /* advance over "rsvg" */
-
- return TRUE;
-}
-
#define TEST_SIMILAR 0x1
#define TEST_OFFSET 0x2
#define TEST_SCALE 0x4
@@ -905,30 +869,6 @@ main (int argc, char **argv)
else
goto TEST_SKIPPED;
}
-
- str = strstr (requirements, "gs");
- if (str != NULL && ! _has_required_ghostscript_version (str)) {
- if (runner.list_only)
- goto TEST_NEXT;
- else
- goto TEST_SKIPPED;
- }
-
- str = strstr (requirements, "poppler");
- if (str != NULL && ! _has_required_poppler_version (str)) {
- if (runner.list_only)
- goto TEST_NEXT;
- else
- goto TEST_SKIPPED;
- }
-
- str = strstr (requirements, "rsvg");
- if (str != NULL && ! _has_required_rsvg_version (str)) {
- if (runner.list_only)
- goto TEST_NEXT;
- else
- goto TEST_SKIPPED;
- }
}
if (runner.list_only) {
@@ -942,6 +882,20 @@ main (int argc, char **argv)
if (ctx.test->preamble != NULL) {
status = _cairo_test_runner_preamble (&runner, &ctx);
+ if (getenv ("CAIRO_TEST_UGLY_HACK_TO_IGNORE_PS_FAILURES")) {
+ if (strcmp (ctx.test_name, "ps-eps") == 0 || strcmp (ctx.test_name, "fallback-resolution") == 0) {
+ if (status == CAIRO_TEST_FAILURE) {
+ cairo_test_log (&ctx, "Turning FAIL into XFAIL due to env\n");
+ fprintf (stderr, "Turning FAIL into XFAIL due to env\n");
+ runner.num_ignored_via_env++;
+ status = CAIRO_TEST_XFAILURE;
+ } else {
+ fprintf (stderr, "Test was expected to fail due to an environment variable, but did not!\n");
+ fprintf (stderr, "Please update the corresponding CAIRO_TEST_IGNORE_* variable.\n");
+ status = CAIRO_TEST_ERROR;
+ }
+ }
+ }
switch (status) {
case CAIRO_TEST_SUCCESS:
in_preamble = TRUE;
diff --git a/test/cairo-test.c b/test/cairo-test.c
index cbd4fb1ab..5a2cf1a74 100644
--- a/test/cairo-test.c
+++ b/test/cairo-test.c
@@ -1825,3 +1825,70 @@ cairo_test_status_from_status (const cairo_test_context_t *ctx,
return CAIRO_TEST_FAILURE;
}
+
+#if CAIRO_HAS_FT_FONT
+
+#include "cairo-ft.h"
+
+static void
+_free_face (void *face)
+{
+ FT_Done_Face ((FT_Face) face);
+}
+
+static FT_Library ft_library = NULL;
+
+#endif
+
+static const cairo_user_data_key_t ft_font_key;
+
+cairo_test_status_t
+cairo_test_ft_select_font_from_file (cairo_t *cr,
+ const char *filename)
+{
+ const cairo_test_context_t *ctx = cairo_test_get_context (cr);
+#if CAIRO_HAS_FT_FONT
+ FT_Face face;
+ cairo_font_face_t *font_face;
+ char *srcdir_filename = NULL;
+
+ if (access (filename, F_OK) != 0) {
+ if (ctx->srcdir) {
+ xasprintf (&srcdir_filename, "%s/%s", ctx->srcdir, filename);
+ filename = srcdir_filename;
+ }
+ }
+
+ if (access (filename, F_OK) != 0) {
+ cairo_test_log (ctx, "Could not find font file: %s\n", filename);
+ return CAIRO_TEST_FAILURE;
+ }
+
+ if (!ft_library) {
+ if (FT_Init_FreeType (&ft_library))
+ return CAIRO_TEST_FAILURE;
+ }
+
+ if (FT_New_Face (ft_library, filename, 0, &face)) {
+ cairo_test_log (ctx, "FT_New_Face failed loading font file: %s\n", filename);
+ return CAIRO_TEST_FAILURE;
+ }
+
+ free (srcdir_filename);
+ font_face = cairo_ft_font_face_create_for_ft_face (face, 0);
+ if (cairo_font_face_status (font_face))
+ return CAIRO_TEST_FAILURE;
+
+ cairo_font_face_set_user_data (font_face, &ft_font_key, face, _free_face);
+ cairo_set_font_face (cr, font_face);
+ if (cairo_status (cr))
+ return CAIRO_TEST_FAILURE;
+
+ cairo_font_face_destroy (font_face);
+
+ return CAIRO_TEST_SUCCESS;
+#else
+ cairo_test_log (ctx, "cairo_test_ft_select_font_from_file() requires the FreeType backend\n");
+ return CAIRO_TEST_FAILURE;
+#endif
+}
diff --git a/test/cairo-test.h b/test/cairo-test.h
index 6169c5371..adff2583c 100644
--- a/test/cairo-test.h
+++ b/test/cairo-test.h
@@ -323,6 +323,11 @@ cairo_t *
cairo_test_create (cairo_surface_t *surface,
const cairo_test_context_t *ctx);
+/* Set font face from a font file in build or src dir, using the FT backend. */
+cairo_test_status_t
+cairo_test_ft_select_font_from_file (cairo_t *cr,
+ const char *filename);
+
CAIRO_END_DECLS
#endif
diff --git a/test/check-refs.sh b/test/check-refs.sh
index 81ef81b35..e2e8a1a2a 100755
--- a/test/check-refs.sh
+++ b/test/check-refs.sh
@@ -9,6 +9,8 @@ if [ ! -e "${pdiff}" ]; then
exit 128
fi
+exit_code=0
+
for file in *.ref.png; do
test=$(echo $file | cut -d'.' -f1)
target=$(echo $file | cut -d'.' -f2)
@@ -48,6 +50,7 @@ for file in *.ref.png; do
if [ -e $ref ]; then
if cmp --silent "$ref" "$file" ; then
printf "redundant: %s and %s are byte-by-byte identical files\n" $file $ref
+ exit_code=1
else
# Run perceptualdiff with minimum threshold
pdiff_output=$($pdiff $ref $file -threshold 1)
@@ -55,9 +58,12 @@ for file in *.ref.png; do
notes=$(echo "${pdiff_output#*: }" | tail -n 1)
if [ "$result" = "PASS" ] && [ "$notes" = "Images are binary identical" ]; then
printf "redundant: %s and %s are pixel equivalent images\n" $file $ref
+ exit_code=1
notes=""
fi
fi
fi
done
+
+exit $exit_code
diff --git a/test/completion.bash b/test/completion.bash
new file mode 100644
index 000000000..6942ea867
--- /dev/null
+++ b/test/completion.bash
@@ -0,0 +1 @@
+complete -W "$(./cairo-test-suite -l)" cairo-test-suite
diff --git a/test/coverage.c b/test/coverage.c
index 86216df31..0749fa22a 100644
--- a/test/coverage.c
+++ b/test/coverage.c
@@ -50,9 +50,9 @@ hars_petruska_f54_1_random (void)
}
static double
-random_offset (int range, int precise)
+random_offset (int range, int precise, int width)
{
- double x = hars_petruska_f54_1_random() / (double) UINT32_MAX * range / WIDTH;
+ double x = hars_petruska_f54_1_random() / (double) UINT32_MAX * range / width;
if (precise)
x = floor (x * PRECISION) / PRECISION;
return x;
@@ -69,9 +69,9 @@ rectangles (cairo_t *cr, int width, int height)
cairo_paint (cr);
#if GENERATE_REFERENCE
- for (x = 0; x < WIDTH; x++) {
- cairo_set_source_rgba (cr, 1, 1, 1, x * x * 1.0 / (WIDTH * WIDTH));
- cairo_rectangle (cr, x, 0, 1, HEIGHT);
+ for (x = 0; x < width; x++) {
+ cairo_set_source_rgba (cr, 1, 1, 1, x * x * 1.0 / (width * width));
+ cairo_rectangle (cr, x, 0, 1, height);
cairo_fill (cr);
}
#else
@@ -84,11 +84,11 @@ rectangles (cairo_t *cr, int width, int height)
case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
}
- for (x = 0; x < WIDTH; x++) {
- for (y = 0; y < HEIGHT; y++) {
- double dx = random_offset (WIDTH - x, TRUE);
- double dy = random_offset (WIDTH - x, TRUE);
- cairo_rectangle (cr, x + dx, y + dy, x / (double) WIDTH, x / (double) WIDTH);
+ for (x = 0; x < width; x++) {
+ for (y = 0; y < height; y++) {
+ double dx = random_offset (width - x, TRUE, width);
+ double dy = random_offset (width - x, TRUE, width);
+ cairo_rectangle (cr, x + dx, y + dy, x / (double) width, x / (double) width);
}
}
cairo_fill (cr);
@@ -102,15 +102,16 @@ static cairo_test_status_t
rhombus (cairo_t *cr, int width, int height)
{
int x, y;
+ int internal_size = width / 2;
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
cairo_paint (cr);
#if GENERATE_REFERENCE
- for (y = 0; y < WIDTH; y++) {
- for (x = 0; x < WIDTH; x++) {
+ for (y = 0; y < internal_size; y++) {
+ for (x = 0; x < internal_size; x++) {
cairo_set_source_rgba (cr, 1, 1, 1,
- x * y / (2. * WIDTH * WIDTH));
+ x * y / (2. * internal_size * internal_size));
cairo_rectangle (cr, 2*x, 2*y, 2, 2);
cairo_fill (cr);
}
@@ -119,10 +120,10 @@ rhombus (cairo_t *cr, int width, int height)
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgb (cr, 1, 1, 1);
- for (y = 0; y < WIDTH; y++) {
- double yf = y / (double) WIDTH;
- for (x = 0; x < WIDTH; x++) {
- double xf = x / (double) WIDTH;
+ for (y = 0; y < internal_size; y++) {
+ double yf = y / (double) internal_size;
+ for (x = 0; x < internal_size; x++) {
+ double xf = x / (double) internal_size;
cairo_move_to (cr,
2*x + 1 - xf,
@@ -157,9 +158,9 @@ intersecting_quads (cairo_t *cr, int width, int height)
cairo_paint (cr);
#if GENERATE_REFERENCE
- for (x = 0; x < WIDTH; x++) {
- cairo_set_source_rgba (cr, 1, 1, 1, x * x * 0.5 / (WIDTH * WIDTH));
- cairo_rectangle (cr, x, 0, 1, HEIGHT);
+ for (x = 0; x < width; x++) {
+ cairo_set_source_rgba (cr, 1, 1, 1, x * x * 0.5 / (width * width));
+ cairo_rectangle (cr, x, 0, 1, height);
cairo_fill (cr);
}
#else
@@ -172,11 +173,11 @@ intersecting_quads (cairo_t *cr, int width, int height)
case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
}
- for (x = 0; x < WIDTH; x++) {
- double step = x / (double) WIDTH;
- for (y = 0; y < HEIGHT; y++) {
- double dx = random_offset (WIDTH - x, TRUE);
- double dy = random_offset (WIDTH - x, TRUE);
+ for (x = 0; x < width; x++) {
+ double step = x / (double) width;
+ for (y = 0; y < height; y++) {
+ double dx = random_offset (width - x, TRUE, width);
+ double dy = random_offset (width - x, TRUE, width);
cairo_move_to (cr, x + dx, y + dy);
cairo_rel_line_to (cr, step, step);
cairo_rel_line_to (cr, 0, -step);
@@ -202,9 +203,9 @@ intersecting_triangles (cairo_t *cr, int width, int height)
cairo_paint (cr);
#if GENERATE_REFERENCE
- for (x = 0; x < WIDTH; x++) {
- cairo_set_source_rgba (cr, 1, 1, 1, x * x * 0.75 / (WIDTH * WIDTH));
- cairo_rectangle (cr, x, 0, 1, HEIGHT);
+ for (x = 0; x < width; x++) {
+ cairo_set_source_rgba (cr, 1, 1, 1, x * x * 0.75 / (width * width));
+ cairo_rectangle (cr, x, 0, 1, height);
cairo_fill (cr);
}
#else
@@ -217,11 +218,11 @@ intersecting_triangles (cairo_t *cr, int width, int height)
case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
}
- for (x = 0; x < WIDTH; x++) {
- double step = x / (double) WIDTH;
- for (y = 0; y < HEIGHT; y++) {
- double dx = random_offset (WIDTH - x, TRUE);
- double dy = random_offset (WIDTH - x, TRUE);
+ for (x = 0; x < width; x++) {
+ double step = x / (double) width;
+ for (y = 0; y < height; y++) {
+ double dx = random_offset (width - x, TRUE, width);
+ double dy = random_offset (width - x, TRUE, width);
/* left */
cairo_move_to (cr, x + dx, y + dy);
@@ -254,9 +255,9 @@ triangles (cairo_t *cr, int width, int height)
cairo_paint (cr);
#if GENERATE_REFERENCE
- for (x = 0; x < WIDTH; x++) {
- cairo_set_source_rgba (cr, 1, 1, 1, x * x * 0.5 / (WIDTH * WIDTH));
- cairo_rectangle (cr, x, 0, 1, HEIGHT);
+ for (x = 0; x < width; x++) {
+ cairo_set_source_rgba (cr, 1, 1, 1, x * x * 0.5 / (width * width));
+ cairo_rectangle (cr, x, 0, 1, height);
cairo_fill (cr);
}
#else
@@ -269,13 +270,13 @@ triangles (cairo_t *cr, int width, int height)
case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
}
- for (x = 0; x < WIDTH; x++) {
- for (y = 0; y < HEIGHT; y++) {
- double dx = random_offset (WIDTH - x, TRUE);
- double dy = random_offset (WIDTH - x, TRUE);
+ for (x = 0; x < width; x++) {
+ for (y = 0; y < height; y++) {
+ double dx = random_offset (width - x, TRUE, width);
+ double dy = random_offset (width - x, TRUE, width);
cairo_move_to (cr, x + dx, y + dy);
- cairo_rel_line_to (cr, x / (double) WIDTH, 0);
- cairo_rel_line_to (cr, 0, x / (double) WIDTH);
+ cairo_rel_line_to (cr, x / (double) width, 0);
+ cairo_rel_line_to (cr, 0, x / (double) width);
cairo_close_path (cr);
}
}
@@ -344,9 +345,9 @@ column_triangles (cairo_t *cr, int width, int height)
cairo_paint (cr);
#if GENERATE_REFERENCE
- for (x = 0; x < WIDTH; x++) {
- cairo_set_source_rgba (cr, 1, 1, 1, x * 0.5 / WIDTH);
- cairo_rectangle (cr, x, 0, 1, HEIGHT);
+ for (x = 0; x < width; x++) {
+ cairo_set_source_rgba (cr, 1, 1, 1, x * 0.5 / width);
+ cairo_rectangle (cr, x, 0, 1, height);
cairo_fill (cr);
}
#else
@@ -359,11 +360,11 @@ column_triangles (cairo_t *cr, int width, int height)
case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
}
- for (x = 0; x < WIDTH; x++) {
- double step = x / (double) (2 * WIDTH);
- for (y = 0; y < HEIGHT; y++) {
+ for (x = 0; x < width; x++) {
+ double step = x / (double) (2 * width);
+ for (y = 0; y < height; y++) {
for (i = 0; i < PRECISION; i++) {
- double dy = random_offset (WIDTH - x, FALSE);
+ double dy = random_offset (width - x, FALSE, width);
/*
* We want to test some sharing of edges to further
@@ -375,7 +376,7 @@ column_triangles (cairo_t *cr, int width, int height)
* s --- . ---
* t | |\ |
* e | | \ |
- * p --- .... | 2 * step = x / WIDTH
+ * p --- .... | 2 * step = x / width
* \ | |
* \| |
* . ---
@@ -383,8 +384,8 @@ column_triangles (cairo_t *cr, int width, int height)
* 1 / PRECISION
*
* Each column contains two triangles of width one quantum and
- * total height of (x / WIDTH), thus the total area covered by all
- * columns in each pixel is .5 * (x / WIDTH).
+ * total height of (x / width), thus the total area covered by all
+ * columns in each pixel is .5 * (x / width).
*/
cairo_move_to (cr, x + i / (double) PRECISION, y + dy);
@@ -413,9 +414,9 @@ row_triangles (cairo_t *cr, int width, int height)
cairo_paint (cr);
#if GENERATE_REFERENCE
- for (x = 0; x < WIDTH; x++) {
- cairo_set_source_rgba (cr, 1, 1, 1, x * 0.5 / WIDTH);
- cairo_rectangle (cr, x, 0, 1, HEIGHT);
+ for (x = 0; x < width; x++) {
+ cairo_set_source_rgba (cr, 1, 1, 1, x * 0.5 / width);
+ cairo_rectangle (cr, x, 0, 1, height);
cairo_fill (cr);
}
#else
@@ -428,11 +429,11 @@ row_triangles (cairo_t *cr, int width, int height)
case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break;
}
- for (x = 0; x < WIDTH; x++) {
- double step = x / (double) (2 * WIDTH);
- for (y = 0; y < HEIGHT; y++) {
+ for (x = 0; x < width; x++) {
+ double step = x / (double) (2 * width);
+ for (y = 0; y < height; y++) {
for (i = 0; i < PRECISION; i++) {
- double dx = random_offset (WIDTH - x, FALSE);
+ double dx = random_offset (width - x, FALSE, width);
/* See column_triangles() for a transposed description
* of this geometry.
@@ -490,7 +491,8 @@ CAIRO_TEST (coverage_column_triangles,
"Check the fidelity of the rasterisation.",
NULL, /* keywords */
"target=raster", /* requirements */
- WIDTH, HEIGHT,
+ /* Smaller height since this test does not vary by y-coordinate */
+ WIDTH, 4,
NULL, column_triangles)
CAIRO_TEST (coverage_triangles,
"Check the fidelity of the rasterisation.",
diff --git a/test/create-from-png-16bit.c b/test/create-from-png-16bit.c
new file mode 100644
index 000000000..71c13ecd3
--- /dev/null
+++ b/test/create-from-png-16bit.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2005 Red Hat, Inc.
+ * Copyright © 2021 Manuel Stoeckl
+ *
+ * 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 Worth <cworth@cworth.org>
+ * Author: Manuel Stoeckl <code@mstoeckl.com>
+ */
+
+#include "cairo-test.h"
+
+#include <stdlib.h>
+
+#define WIDTH 2
+#define HEIGHT 2
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ const cairo_test_context_t *ctx = cairo_test_get_context (cr);
+ char *filename;
+ cairo_surface_t *surface;
+
+ xasprintf (&filename, "%s/reference/%s",
+ ctx->srcdir, "create-from-png-16bit.base.png");
+
+ surface = cairo_image_surface_create_from_png (filename);
+ if (cairo_surface_status (surface)) {
+ cairo_test_status_t result;
+
+ result = cairo_test_status_from_status (ctx,
+ cairo_surface_status (surface));
+ if (result == CAIRO_TEST_FAILURE) {
+ cairo_test_log (ctx, "Error reading PNG image %s: %s\n",
+ filename,
+ cairo_status_to_string (cairo_surface_status (surface)));
+ }
+
+ free (filename);
+ return result;
+ }
+
+ /* Pretend we modify the surface data (which detaches the PNG mime data) */
+ cairo_surface_flush (surface);
+ cairo_surface_mark_dirty (surface);
+
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST);
+ cairo_paint (cr);
+
+ cairo_surface_destroy (surface);
+
+ free (filename);
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (create_from_png_16bit,
+ "Tests the creation of an image surface from a 16 bit PNG file",
+ "png", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT,
+ NULL, draw)
diff --git a/test/create-regions.c b/test/create-regions.c
new file mode 100644
index 000000000..749595a44
--- /dev/null
+++ b/test/create-regions.c
@@ -0,0 +1,435 @@
+/*
+ * Copyright © 2023 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 "config.h"
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <cairo.h>
+
+#if CAIRO_HAS_PDF_SURFACE && CAIRO_HAS_PS_SURFACE && CAIRO_HAS_SVG_SURFACE
+
+#include <cairo-pdf.h>
+#include <cairo-ps.h>
+#include <cairo-svg.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#include <errno.h>
+#endif
+
+#include "cairo-test.h"
+#include "buffer-diff.h"
+
+/* This test is to ensure that _cairo_recording_surface_replay_and_create_regions()
+ * works with a recording surface source re-used for multiple paginated surfaces.
+ * The prior use of the source with a paginated surface should not affect the region
+ * analysis on subsequent surfaces.
+ *
+ * If test output should only contain fallback images for unsupported
+ * operations. If the recording surface is incorrectly re-using the
+ * analysis from a different target, some operations may be missing
+ * from the ouput (recording surface marked the operation as supported
+ * when it is not) or some operations may be have fallbacks for
+ * natively suported opetions (recording surface marked a supported
+ * operation as unsupprted).
+ *
+ * To create ref images, run the test for one target at a time to
+ * prevent re-use of the recording surface for different targets.
+ */
+
+
+#define SIZE 40
+#define PAD 25
+#define PAGE_SIZE (SIZE*3 + PAD*4)
+
+/* Apply a slight rotation and use a very low fallback resolution to
+ * ensure fallback images are apparent in the output. */
+#define ROTATE 5
+#define FALLBACK_PPI 18
+
+static void
+create_recordings (cairo_operator_t op,
+ cairo_surface_t **recording,
+ cairo_surface_t **recording_group)
+{
+ *recording = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL);
+ cairo_t *cr = cairo_create (*recording);
+
+ cairo_rotate (cr, ROTATE*M_PI/180.0);
+
+ cairo_rectangle (cr, 0, 0, SIZE*3.0/4.0, SIZE*3.0/4.0);
+ cairo_set_source_rgb (cr, 1, 0, 0);
+ cairo_fill (cr);
+
+ cairo_set_operator (cr, op);
+
+ cairo_rectangle (cr, SIZE/4.0, SIZE/4.0, SIZE*3.0/4.0, SIZE*3.0/4.0);
+ cairo_set_source_rgb (cr, 0, 1, 0);
+ cairo_fill (cr);
+
+ cairo_destroy (cr);
+
+ *recording_group = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL);
+ cr = cairo_create (*recording_group);
+
+ cairo_set_source_surface (cr, *recording, 0, 0);
+ cairo_paint (cr);
+
+ cairo_destroy (cr);
+}
+
+static void
+_xunlink (const cairo_test_context_t *ctx, const char *pathname)
+{
+ if (unlink (pathname) < 0 && errno != ENOENT) {
+ cairo_test_log (ctx, "Error: Cannot remove %s: %s\n",
+ pathname, strerror (errno));
+ exit (1);
+ }
+}
+
+static cairo_bool_t
+check_result (cairo_test_context_t *ctx,
+ const cairo_boilerplate_target_t *target,
+ const char *test_name,
+ const char *base_name,
+ cairo_surface_t *surface)
+{
+ const char *format;
+ char *ref_name;
+ char *png_name;
+ char *diff_name;
+ cairo_surface_t *test_image, *ref_image, *diff_image;
+ buffer_diff_result_t result;
+ cairo_status_t status;
+ cairo_bool_t ret;
+
+ if (target->finish_surface != NULL) {
+ status = target->finish_surface (surface);
+ if (status) {
+ cairo_test_log (ctx, "Error: Failed to finish surface: %s\n",
+ cairo_status_to_string (status));
+ cairo_surface_destroy (surface);
+ return FALSE;
+ }
+ }
+
+ xasprintf (&png_name, "%s.out.png", base_name);
+ xasprintf (&diff_name, "%s.diff.png", base_name);
+
+ test_image = target->get_image_surface (surface, 0, PAGE_SIZE, PAGE_SIZE);
+ if (cairo_surface_status (test_image)) {
+ cairo_test_log (ctx, "Error: Failed to extract page: %s\n",
+ cairo_status_to_string (cairo_surface_status (test_image)));
+ cairo_surface_destroy (test_image);
+ free (png_name);
+ free (diff_name);
+ return FALSE;
+ }
+
+ _xunlink (ctx, png_name);
+ status = cairo_surface_write_to_png (test_image, png_name);
+ if (status) {
+ cairo_test_log (ctx, "Error: Failed to write output image: %s\n",
+ cairo_status_to_string (status));
+ cairo_surface_destroy (test_image);
+ free (png_name);
+ free (diff_name);
+ return FALSE;
+ }
+
+ format = cairo_boilerplate_content_name (target->content);
+ ref_name = cairo_test_reference_filename (ctx,
+ base_name,
+ test_name,
+ target->name,
+ target->basename,
+ format,
+ CAIRO_TEST_REF_SUFFIX,
+ CAIRO_TEST_PNG_EXTENSION);
+ if (ref_name == NULL) {
+ cairo_test_log (ctx, "Error: Cannot find reference image for %s\n",
+ base_name);
+ cairo_surface_destroy (test_image);
+ free (png_name);
+ free (diff_name);
+ return FALSE;
+ }
+
+ ref_image = cairo_test_get_reference_image (ctx, ref_name,
+ target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED);
+ if (cairo_surface_status (ref_image)) {
+ cairo_test_log (ctx, "Error: Cannot open reference image for %s: %s\n",
+ ref_name,
+ cairo_status_to_string (cairo_surface_status (ref_image)));
+ cairo_surface_destroy (ref_image);
+ cairo_surface_destroy (test_image);
+ free (png_name);
+ free (diff_name);
+ free (ref_name);
+ return FALSE;
+ }
+
+ diff_image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ PAGE_SIZE, PAGE_SIZE);
+
+ ret = TRUE;
+ status = image_diff (ctx,
+ test_image, ref_image, diff_image,
+ &result);
+ _xunlink (ctx, diff_name);
+ if (status) {
+ cairo_test_log (ctx, "Error: Failed to compare images: %s\n",
+ cairo_status_to_string (status));
+ ret = FALSE;
+ } else if (image_diff_is_failure (&result, target->error_tolerance))
+ {
+ ret = FALSE;
+
+ status = cairo_surface_write_to_png (diff_image, diff_name);
+ if (status) {
+ cairo_test_log (ctx, "Error: Failed to write differences image: %s\n",
+ cairo_status_to_string (status));
+ }
+ }
+
+ cairo_surface_destroy (test_image);
+ cairo_surface_destroy (diff_image);
+ free (png_name);
+ free (diff_name);
+ free (ref_name);
+
+ return ret;
+}
+
+#define TEST_ROWS 2
+#define TEST_COLS 3
+
+static void
+draw (cairo_t *cr, cairo_surface_t *recordings[TEST_ROWS][TEST_COLS])
+{
+ cairo_translate (cr, PAD, PAD);
+ for (int row = 0; row < TEST_ROWS; row++) {
+ cairo_save (cr);
+ for (int col = 0; col < TEST_COLS; col++) {
+ cairo_save (cr);
+ cairo_set_source_surface (cr, recordings[row][col], 0, 0);
+ cairo_paint (cr);
+ cairo_restore (cr);
+ cairo_translate (cr, SIZE + PAD, 0);
+ }
+ cairo_restore (cr);
+ cairo_translate (cr, 0, SIZE + PAD);
+ }
+}
+
+#define NUM_TEST_SURFACES 3
+
+typedef struct _test_surface {
+ const cairo_boilerplate_target_t *target;
+ cairo_surface_t *surface;
+ char *base_name;
+ void *closure;
+} test_surface_t;
+
+static test_surface_t test_surfaces[NUM_TEST_SURFACES];
+
+static void
+init_test_surfaces()
+{
+ memset (test_surfaces, 0, sizeof (*test_surfaces));
+ test_surfaces[0].surface = cairo_pdf_surface_create_for_stream (NULL, NULL, PAGE_SIZE, PAGE_SIZE);
+ test_surfaces[1].surface = cairo_ps_surface_create_for_stream (NULL, NULL, PAGE_SIZE, PAGE_SIZE);
+ test_surfaces[2].surface = cairo_svg_surface_create_for_stream (NULL, NULL, PAGE_SIZE, PAGE_SIZE);
+}
+
+static void
+add_test_surface (const cairo_boilerplate_target_t *target,
+ cairo_surface_t *surface,
+ char *base_name,
+ void *closure)
+{
+ for (int i = 0; i < NUM_TEST_SURFACES; i++) {
+ if (cairo_surface_get_type (test_surfaces[i].surface) == cairo_surface_get_type (surface)) {
+ cairo_surface_destroy (test_surfaces[i].surface);
+ test_surfaces[i].target = target;
+ test_surfaces[i].surface = surface;
+ test_surfaces[i].base_name = base_name;
+ test_surfaces[i].closure = closure;
+ break;
+ }
+ }
+}
+
+static void
+destroy_test_surfaces()
+{
+ for (int i = 0; i < NUM_TEST_SURFACES; i++) {
+ cairo_surface_destroy (test_surfaces[i].surface);
+ if (test_surfaces[i].target && test_surfaces[i].target->cleanup)
+ test_surfaces[i].target->cleanup (test_surfaces[i].closure);
+ if (test_surfaces[i].base_name)
+ free (test_surfaces[i].base_name);
+ }
+}
+
+
+static cairo_test_status_t
+preamble (cairo_test_context_t *ctx)
+{
+ cairo_t *cr;
+ cairo_test_status_t ret = CAIRO_TEST_UNTESTED;
+ unsigned int i;
+ const char *path = cairo_test_mkdir (CAIRO_TEST_OUTPUT_DIR) ? CAIRO_TEST_OUTPUT_DIR : ".";
+ cairo_surface_t *recordings[TEST_ROWS][TEST_COLS];
+ const char *test_name = "create-regions";
+ char *base_name;
+
+ /* Each row displays three recordings. One with operations
+ * supported by all paginated surfaces (OVER), one with operations
+ * supported by PDF but not PS or SVG surfaces (DIFFERENCE), and
+ * one with operations supported by SVG but not PDF or PS
+ * (DEST_XOR).
+ *
+ * The recordings for the first row is a single recording. The
+ * recordings for the second row contains the first row recording
+ * inside another recording to test the use of cloned recording
+ * surfaces.
+ *
+ * We are looking to see that fallback images are only used for
+ * unsupported operations.
+ */
+ create_recordings (CAIRO_OPERATOR_OVER, &recordings[0][0], &recordings[1][0]);
+ create_recordings (CAIRO_OPERATOR_DIFFERENCE, &recordings[0][1], &recordings[1][1]);
+ create_recordings (CAIRO_OPERATOR_XOR, &recordings[0][2], &recordings[1][2]);
+
+ init_test_surfaces();
+ for (i = 0; i < ctx->num_targets; i++) {
+ const cairo_boilerplate_target_t *target = ctx->targets_to_test[i];
+ cairo_surface_t *surface = NULL;
+ void *closure;
+ const char *format;
+
+ /* This test only works on surfaces that support fine grained fallbacks */
+ if (! (target->expected_type == CAIRO_SURFACE_TYPE_PDF ||
+ target->expected_type == CAIRO_SURFACE_TYPE_PS ||
+ target->expected_type ==CAIRO_SURFACE_TYPE_SVG))
+ continue;
+
+ if (! cairo_test_is_target_enabled (ctx, target->name))
+ continue;
+
+ if (ret == CAIRO_TEST_UNTESTED)
+ ret = CAIRO_TEST_SUCCESS;
+
+ format = cairo_boilerplate_content_name (target->content);
+ base_name = NULL;
+ xasprintf (&base_name, "%s/%s.%s.%s",
+ path, test_name,
+ target->name,
+ format);
+
+ surface = (target->create_surface) (base_name,
+ target->content,
+ PAGE_SIZE, PAGE_SIZE,
+ PAGE_SIZE, PAGE_SIZE,
+ CAIRO_BOILERPLATE_MODE_TEST,
+ &closure);
+ if (surface == NULL || cairo_surface_status (surface)) {
+ cairo_test_log (ctx, "Failed to generate surface: %s.%s\n",
+ target->name,
+ format);
+ ret = CAIRO_TEST_FAILURE;
+ break;
+ }
+
+ cairo_surface_set_fallback_resolution (surface, FALLBACK_PPI, FALLBACK_PPI);
+ add_test_surface (target, surface, base_name, closure);
+ }
+
+ for (int i = 0; i < NUM_TEST_SURFACES; i++) {
+ cairo_status_t status;
+
+ if (test_surfaces[i].target != NULL) {
+ cairo_test_log (ctx,
+ "Testing create-regions with %s target\n",
+ test_surfaces[i].target->name);
+ printf ("%s:\t", test_surfaces[i].base_name);
+ fflush (stdout);
+ }
+
+ cr = cairo_create (test_surfaces[i].surface);
+
+ draw (cr, recordings);
+
+ status = cairo_status (cr);
+ cairo_destroy (cr);
+ cairo_surface_finish (test_surfaces[i].surface);
+
+ if (test_surfaces[i].target) {
+ cairo_bool_t pass = FALSE;
+ if (status) {
+ cairo_test_log (ctx, "Error: Failed to create target surface: %s\n",
+ cairo_status_to_string (status));
+ ret = CAIRO_TEST_FAILURE;
+ } else {
+ /* extract the image and compare it to our reference */
+ if (! check_result (ctx, test_surfaces[i].target, test_name, test_surfaces[i].base_name, test_surfaces[i].surface))
+ ret = CAIRO_TEST_FAILURE;
+ else
+ pass = TRUE;
+ }
+
+ if (pass) {
+ printf ("PASS\n");
+ } else {
+ printf ("FAIL\n");
+ }
+ fflush (stdout);
+ }
+ }
+
+ destroy_test_surfaces();
+
+ for (int row = 0; row < TEST_ROWS; row++) {
+ for (int col = 0; col < TEST_COLS; col++) {
+ cairo_surface_destroy (recordings[row][col]);
+ }
+ }
+
+ return ret;
+}
+
+CAIRO_TEST (create_regions,
+ "Check region analysis when re-used with different surfaces",
+ "fallback", /* keywords */
+ NULL, /* requirements */
+ 0, 0,
+ preamble, NULL)
+
+#endif /* CAIRO_HAS_PDF_SURFACE && CAIRO_HAS_PS_SURFACE && CAIRO_HAS_SVG_SURFACE */
diff --git a/test/egl-oversized-surface.c b/test/egl-oversized-surface.c
deleted file mode 100644
index cb85a628d..000000000
--- a/test/egl-oversized-surface.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright © 2014 Samsung Electronics
- *
- * 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: Ravi Nanjundappa <nravi.n@samsung.com>
- */
-
-/*
- * This test exercises error scenario for over sized egl surface
- *
- */
-
-#include "cairo-test.h"
-#include <cairo-gl.h>
-#include <assert.h>
-#include <limits.h>
-
-static cairo_test_status_t
-preamble (cairo_test_context_t *test_ctx)
-{
- EGLint rgba_attribs[] = {
- EGL_RED_SIZE, 8,
- EGL_GREEN_SIZE, 8,
- EGL_BLUE_SIZE, 8,
- EGL_ALPHA_SIZE, 8,
- EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
-#if CAIRO_HAS_GL_SURFACE
- EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
-#elif CAIRO_HAS_GLESV2_SURFACE
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-#endif
- EGL_NONE
- };
- const EGLint ctx_attribs[] = {
-#if CAIRO_HAS_GLESV2_SURFACE
- EGL_CONTEXT_CLIENT_VERSION, 2,
-#endif
- EGL_NONE
- };
-
- EGLDisplay dpy;
- EGLContext ctx;
- EGLConfig config;
- EGLint numConfigs;
- int major, minor;
- cairo_device_t *device;
- cairo_surface_t *oversized_surface;
- cairo_test_status_t test_status = CAIRO_TEST_SUCCESS;
-
- dpy = eglGetDisplay (EGL_DEFAULT_DISPLAY);
- if (! eglInitialize (dpy, &major, &minor)) {
- test_status = CAIRO_TEST_UNTESTED;
- goto CLEANUP_1;
- }
-
- eglChooseConfig (dpy, rgba_attribs, &config, 1, &numConfigs);
- if (numConfigs == 0) {
- test_status = CAIRO_TEST_UNTESTED;
- goto CLEANUP_1;
- }
-
-#if CAIRO_HAS_GL_SURFACE
- eglBindAPI (EGL_OPENGL_API);
-#elif CAIRO_HAS_GLESV2_SURFACE
- eglBindAPI (EGL_OPENGL_ES_API);
-#endif
-
- ctx = eglCreateContext (dpy, config, EGL_NO_CONTEXT,
- ctx_attribs);
- if (ctx == EGL_NO_CONTEXT) {
- test_status = CAIRO_TEST_UNTESTED;
- goto CLEANUP_2;
- }
-
- device = cairo_egl_device_create (dpy, ctx);
-
- oversized_surface = cairo_gl_surface_create (device, CAIRO_CONTENT_COLOR_ALPHA, INT_MAX, INT_MAX);
- if (cairo_surface_status (oversized_surface) != CAIRO_STATUS_INVALID_SIZE)
- test_status = CAIRO_TEST_FAILURE;
-
- cairo_device_destroy (device);
- eglDestroyContext (dpy, ctx);
- eglMakeCurrent (dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- ctx = EGL_NO_CONTEXT;
-
-CLEANUP_2:
- eglTerminate (dpy);
-
-CLEANUP_1:
- return test_status;
-}
-
-CAIRO_TEST (egl_oversized_surface,
- "Test that creating a surface beyond texture limits results in an error surface",
- "egl", /* keywords */
- NULL, /* requirements */
- 0, 0,
- preamble, NULL)
diff --git a/test/egl-surface-source.c b/test/egl-surface-source.c
deleted file mode 100644
index 4a84d7042..000000000
--- a/test/egl-surface-source.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright © 2014 Samsung Electronics
- *
- * 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: Ravi Nanjundappa <nravi.n@samsung.com>
- */
-
-/*
- * This case tests using a EGL surface as the source
- *
- */
-
-#include "cairo-test.h"
-#include <cairo-gl.h>
-
-#include "surface-source.c"
-
-struct closure {
- EGLDisplay dpy;
- EGLContext ctx;
-};
-
-static void
-cleanup (void *data)
-{
- struct closure *arg = data;
-
- eglDestroyContext (arg->dpy, arg->ctx);
- eglMakeCurrent (arg->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- eglTerminate (arg->dpy);
-
- free (arg);
-}
-
-static cairo_surface_t *
-create_source_surface (int size)
-{
- EGLint config_attribs[] = {
- EGL_RED_SIZE, 8,
- EGL_GREEN_SIZE, 8,
- EGL_BLUE_SIZE, 8,
- EGL_ALPHA_SIZE, 8,
- EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
-#if CAIRO_HAS_GL_SURFACE
- EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
-#elif CAIRO_HAS_GLESV2_SURFACE
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-#endif
- EGL_NONE
- };
- const EGLint ctx_attribs[] = {
-#if CAIRO_HAS_GLESV2_SURFACE
- EGL_CONTEXT_CLIENT_VERSION, 2,
-#endif
- EGL_NONE
- };
-
- struct closure *arg;
- cairo_device_t *device;
- cairo_surface_t *surface;
- EGLConfig config;
- EGLint numConfigs;
- EGLDisplay dpy;
- EGLContext ctx;
- int major, minor;
-
- dpy = eglGetDisplay (EGL_DEFAULT_DISPLAY);
- if (! eglInitialize (dpy, &major, &minor)) {
- return NULL;
- }
-
- eglChooseConfig (dpy, config_attribs, &config, 1, &numConfigs);
- if (numConfigs == 0) {
- return NULL;
- }
-
-#if CAIRO_HAS_GL_SURFACE
- eglBindAPI (EGL_OPENGL_API);
-#elif CAIRO_HAS_GLESV2_SURFACE
- eglBindAPI (EGL_OPENGL_ES_API);
-#endif
-
- ctx = eglCreateContext (dpy, config, EGL_NO_CONTEXT,
- ctx_attribs);
- if (ctx == EGL_NO_CONTEXT) {
- eglTerminate (dpy);
- return NULL;
- }
-
- arg = xmalloc (sizeof (struct closure));
- arg->dpy = dpy;
- arg->ctx = ctx;
- device = cairo_egl_device_create (dpy, ctx);
- if (cairo_device_set_user_data (device,
- (cairo_user_data_key_t *) cleanup,
- arg,
- cleanup))
- {
- cleanup (arg);
- return NULL;
- }
-
- surface = cairo_gl_surface_create (device,
- CAIRO_CONTENT_COLOR_ALPHA,
- size, size);
- cairo_device_destroy (device);
-
- return surface;
-}
-
-CAIRO_TEST (egl_surface_source,
- "Test using a EGL surface as the source",
- "source", /* keywords */
- NULL, /* requirements */
- SIZE, SIZE,
- preamble, draw)
diff --git a/test/error-setters.c b/test/error-setters.c
index c69a6d89b..ecbb78fde 100644
--- a/test/error-setters.c
+++ b/test/error-setters.c
@@ -29,9 +29,6 @@
#include "cairo-test.h"
-#if CAIRO_HAS_GL_SURFACE
-#include <cairo-gl.h>
-#endif
#if CAIRO_HAS_PDF_SURFACE
#include <cairo-pdf.h>
#endif
@@ -53,11 +50,6 @@ preamble (cairo_test_context_t *ctx)
/* get the error surface */
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, INT_MAX, INT_MAX);
-#if CAIRO_HAS_GL_SURFACE
- cairo_gl_surface_set_size (surface, 0, 0);
- cairo_gl_surface_swapbuffers (surface);
-#endif
-
#if CAIRO_HAS_PDF_SURFACE
cairo_pdf_surface_restrict_to_version (surface, CAIRO_PDF_VERSION_1_4);
cairo_pdf_surface_set_size (surface, 0, 0);
diff --git a/test/ft-svg-cairo-logo.c b/test/ft-svg-cairo-logo.c
new file mode 100644
index 000000000..22fb25f23
--- /dev/null
+++ b/test/ft-svg-cairo-logo.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2022 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 <cairo-ft.h>
+
+#define FONT_SIZE 200
+#define MARGIN 5
+#define WIDTH (FONT_SIZE + MARGIN*2)
+#define HEIGHT (FONT_SIZE + MARGIN*2)
+
+#define FONT_FILE "cairo-logo-font.ttf"
+
+/* Character code in font of the logo */
+#define CAIRO_LOGO_CHAR "A"
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_test_status_t result;
+
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_paint (cr);
+ cairo_set_source_rgb (cr, 0, 0, 0);
+
+ result = cairo_test_ft_select_font_from_file (cr, FONT_FILE);
+ if (result)
+ return result;
+
+ cairo_set_font_size (cr, FONT_SIZE);
+ cairo_move_to (cr, MARGIN, FONT_SIZE + MARGIN);
+
+ cairo_show_text (cr, CAIRO_LOGO_CHAR);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (ft_svg_cairo_logo,
+ "Test cairo logo SVG font",
+ "svgrender", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT,
+ NULL, draw)
diff --git a/test/ft-svg-color-font.c b/test/ft-svg-color-font.c
new file mode 100644
index 000000000..56510feca
--- /dev/null
+++ b/test/ft-svg-color-font.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright © 2022 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 <cairo-ft.h>
+
+#define FONT_SIZE 50
+#define MARGIN 5
+#define WIDTH (FONT_SIZE*4 + MARGIN*2)
+#define HEIGHT (FONT_SIZE*3 + MARGIN*5)
+
+/* Check the full name to ensure we got an SVG font. */
+#define FONT_FAMILY "Twitter Color Emoji"
+#define FONT_FULLNAME "Twitter Color Emoji SVGinOT"
+
+static const char spade_utf8[] = { 0xe2, 0x99, 0xa0, 0x00 }; /* U+2660 glyph 87 */
+static const char club_utf8[] = { 0xe2, 0x99, 0xa3, 0x00 }; /* U+2663 glyph 88 */
+static const char heart_utf8[] = { 0xe2, 0x99, 0xa5, 0x00 }; /* U+2665 glyph 89 */
+static const char diamond_utf8[] = { 0xe2, 0x99, 0xa6, 0x00 }; /* U+2666 glyph 90 */
+
+static cairo_test_status_t
+set_color_emoji_font (cairo_t *cr)
+{
+ cairo_font_options_t *font_options;
+ cairo_font_face_t *font_face;
+ FcPattern *pattern;
+ FcPattern *resolved;
+ FcChar8 *font_name;
+ FcResult result;
+
+ pattern = FcPatternCreate ();
+ if (pattern == NULL)
+ return CAIRO_TEST_NO_MEMORY;
+
+ FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) FONT_FAMILY);
+ FcConfigSubstitute (NULL, pattern, FcMatchPattern);
+
+ font_options = cairo_font_options_create ();
+ cairo_get_font_options (cr, font_options);
+ cairo_ft_font_options_substitute (font_options, pattern);
+
+ FcDefaultSubstitute (pattern);
+ resolved = FcFontMatch (NULL, pattern, &result);
+ if (resolved == NULL) {
+ FcPatternDestroy (pattern);
+ return CAIRO_TEST_NO_MEMORY;
+ }
+
+ if (FcPatternGetString (resolved, FC_FULLNAME, 0, &font_name) == FcResultMatch) {
+ if (strcmp((char*)font_name, FONT_FULLNAME) != 0) {
+ const cairo_test_context_t *ctx = cairo_test_get_context (cr);
+ cairo_test_log (ctx, "Could not find %s font\n", FONT_FULLNAME);
+ return CAIRO_TEST_UNTESTED;
+ }
+ } else {
+ return CAIRO_TEST_FAILURE;
+ }
+
+ font_face = cairo_ft_font_face_create_for_pattern (resolved);
+ cairo_set_font_face (cr, font_face);
+
+ cairo_font_options_destroy (font_options);
+ cairo_font_face_destroy (font_face);
+ FcPatternDestroy (pattern);
+ FcPatternDestroy (resolved);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_font_options_t *font_options;
+ cairo_test_status_t result;
+
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_paint (cr);
+ cairo_set_source_rgb (cr, 0, 0, 0);
+
+ result = set_color_emoji_font (cr);
+ if (result != CAIRO_TEST_SUCCESS)
+ return result;
+
+ cairo_set_font_size (cr, FONT_SIZE);
+
+ /* Color glyphs */
+ cairo_move_to (cr, MARGIN, FONT_SIZE + MARGIN);
+ cairo_show_text (cr, diamond_utf8);
+ cairo_show_text (cr, club_utf8);
+ cairo_show_text (cr, heart_utf8);
+ cairo_show_text (cr, spade_utf8);
+
+ /* Non-color glyphs */
+ font_options = cairo_font_options_create ();
+ cairo_font_options_set_color_mode (font_options, CAIRO_COLOR_MODE_NO_COLOR);
+ cairo_set_font_options (cr, font_options);
+ cairo_move_to (cr, MARGIN, FONT_SIZE*2 + MARGIN*2);
+ cairo_show_text (cr, diamond_utf8);
+ cairo_show_text (cr, club_utf8);
+ cairo_show_text (cr, heart_utf8);
+ cairo_show_text (cr, spade_utf8);
+
+ /* Color glyph text path */
+ cairo_font_options_set_color_mode (font_options, CAIRO_COLOR_MODE_COLOR);
+ cairo_set_font_options (cr, font_options);
+ cairo_font_options_destroy (font_options);
+ cairo_move_to (cr, MARGIN, FONT_SIZE*3 + MARGIN*3);
+ cairo_text_path (cr, diamond_utf8);
+ cairo_text_path (cr, club_utf8);
+ cairo_text_path (cr, heart_utf8);
+ cairo_text_path (cr, spade_utf8);
+ cairo_set_line_width (cr, 1);
+ cairo_stroke (cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (ft_svg_color_font,
+ "Test color font",
+ "svgrender", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT,
+ NULL, draw)
diff --git a/test/ft-svg-render-color.c b/test/ft-svg-render-color.c
new file mode 100644
index 000000000..c7572d5b0
--- /dev/null
+++ b/test/ft-svg-render-color.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright © 2023 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 <cairo-ft.h>
+
+#define FONT_SIZE 50
+#define MARGIN 5
+#define WIDTH (FONT_SIZE*8 + MARGIN*9)
+#define HEIGHT (FONT_SIZE*2 + MARGIN*3)
+
+#define FONT_FILE "cairo-svg-test-color.ttf"
+
+#define PALETTE_TEXT "01"
+#define FOREGROUND_TEXT "234567"
+
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_test_status_t result;
+ cairo_font_options_t *font_options;
+
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_paint (cr);
+ cairo_set_source_rgb (cr, 0, 0, 0);
+
+ result = cairo_test_ft_select_font_from_file (cr, FONT_FILE);
+ if (result)
+ return result;
+
+ cairo_set_font_size (cr, FONT_SIZE);
+
+ cairo_save (cr);
+ cairo_move_to (cr, MARGIN, FONT_SIZE + MARGIN);
+ font_options = cairo_font_options_create ();
+
+ /* Default palette */
+ cairo_show_text (cr, PALETTE_TEXT);
+
+ /* Palette 1 */
+ cairo_font_options_set_color_palette (font_options, 1);
+ cairo_set_font_options (cr, font_options);
+ cairo_show_text (cr, PALETTE_TEXT);
+
+ /* Palette 0, override color 0 */
+ cairo_font_options_set_color_palette (font_options, 0);
+ cairo_font_options_set_custom_palette_color (font_options, 0, 1, 0, 1, 0.5);
+ cairo_set_font_options (cr, font_options);
+ cairo_show_text (cr, PALETTE_TEXT);
+
+ /* Palette 1, override color 1 */
+ cairo_font_options_set_color_palette (font_options, 1);
+ cairo_font_options_set_custom_palette_color (font_options, 1, 0, 1, 1, 0.5);
+ cairo_set_font_options (cr, font_options);
+ cairo_show_text (cr, PALETTE_TEXT);
+
+ cairo_font_options_destroy (font_options);
+ cairo_restore (cr);
+
+ cairo_move_to (cr, MARGIN, FONT_SIZE*2 + MARGIN*2);
+
+ cairo_set_source_rgb (cr, 0, 1, 0);
+ cairo_show_text (cr, FOREGROUND_TEXT);
+
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (ft_svg_render_color,
+ "Test cairo SVG font colors",
+ "svgrender", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT,
+ NULL, draw)
diff --git a/test/ft-svg-render.c b/test/ft-svg-render.c
new file mode 100644
index 000000000..9b0351b10
--- /dev/null
+++ b/test/ft-svg-render.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright © 2022 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 <cairo-ft.h>
+
+#define GLYPH_SIZE 50
+#define PAD 5
+#define WIDTH (4*(GLYPH_SIZE + PAD) + PAD)
+#define HEIGHT WIDTH
+
+//#define CLIP 1
+#define LOG_EXTENTS 1
+
+static cairo_test_status_t
+draw_font (cairo_t *cr, int width, int height, const char *font_file)
+{
+ cairo_test_status_t result;
+ char buf[10];
+ cairo_text_extents_t extents;
+ cairo_font_options_t *font_options;
+
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_paint (cr);
+ cairo_set_source_rgb (cr, 0, 0, 0);
+
+ result = cairo_test_ft_select_font_from_file (cr, font_file);
+ if (result)
+ return result;
+
+ font_options = cairo_font_options_create ();
+ cairo_font_options_set_color_mode (font_options, CAIRO_COLOR_MODE_NO_COLOR);
+// cairo_set_font_options (cr, font_options);
+ cairo_font_options_destroy (font_options);
+
+ cairo_set_font_size (cr, GLYPH_SIZE);
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ int x = j * (GLYPH_SIZE + PAD) + PAD;
+ int y = i * (GLYPH_SIZE + PAD) + PAD;
+ int glyph_number = 4*i + j;
+ buf[0] = glyph_number < 10 ? '0' + glyph_number : 'A' + glyph_number - 10;
+ buf[1] = 0;
+ cairo_save (cr);
+ cairo_text_extents (cr, buf, &extents);
+#if LOG_EXTENTS
+ cairo_test_log (cairo_test_get_context (cr),
+ "Char '%c' extents: x_bearing: %f y_bearing: %f width: %f height: %f x_advance: %f y_advance: %f\n",
+ buf[0],
+ extents.x_bearing,
+ extents.y_bearing,
+ extents.width,
+ extents.height,
+ extents.x_advance,
+ extents.y_advance);
+#endif
+#if CLIP
+ cairo_rectangle (cr, x, y, GLYPH_SIZE, GLYPH_SIZE);
+ cairo_clip (cr);
+#endif
+ cairo_move_to (cr, x, y + GLYPH_SIZE);
+ cairo_show_text (cr, buf);
+ cairo_restore (cr);
+ if (cairo_status (cr)) {
+ cairo_test_log (cairo_test_get_context (cr),
+ "cairo_show_text() failed with \"%s\"\n",
+ buf);
+ return CAIRO_TEST_FAILURE;
+ }
+ }
+ }
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+#define DRAW_FUNC(name) \
+static cairo_test_status_t \
+draw_##name (cairo_t *cr, int width, int height) { \
+ return draw_font (cr, width, height, "cairo-svg-test-" #name ".ttf"); \
+}
+
+DRAW_FUNC(doc)
+CAIRO_TEST (ft_svg_render_doc,
+ "Test SVG glyph render",
+ "svgrender", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT,
+ NULL, draw_doc)
+
+DRAW_FUNC(fill)
+CAIRO_TEST (ft_svg_render_fill,
+ "Test SVG glyph render",
+ "svgrender", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT,
+ NULL, draw_fill)
+
+DRAW_FUNC(gradient)
+CAIRO_TEST (ft_svg_render_gradient,
+ "Test SVG glyph render",
+ "svgrender", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT,
+ NULL, draw_gradient)
+
+DRAW_FUNC(path)
+CAIRO_TEST (ft_svg_render_path,
+ "Test SVG glyph render",
+ "svgrender", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT,
+ NULL, draw_path)
+
+DRAW_FUNC(shapes)
+CAIRO_TEST (ft_svg_render_shapes,
+ "Test SVG glyph render",
+ "svgrender", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT,
+ NULL, draw_shapes)
+
+DRAW_FUNC(stroke)
+CAIRO_TEST (ft_svg_render_stroke,
+ "Test SVG glyph render",
+ "svgrender", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT,
+ NULL, draw_stroke)
+
+DRAW_FUNC(transform)
+CAIRO_TEST (ft_svg_render_transform,
+ "Test SVG glyph render",
+ "svgrender", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT,
+ NULL, draw_transform)
diff --git a/test/gl-device-release.c b/test/gl-device-release.c
deleted file mode 100644
index 7f554be30..000000000
--- a/test/gl-device-release.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright © 2012 Igalia S.L.
- * Copyright © 2009 Eric Anholt
- * Copyright © 2009 Chris Wilson
- * Copyright © 2005 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
- * 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.
- *
- * IGALIA S.L. 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: Martin Robinson <mrobinson@igalia.com>
- */
-
-#include "cairo-test.h"
-#include <cairo-gl.h>
-#include <assert.h>
-
-static Window
-create_test_window (Display *display,
- GLXContext glx_context,
- XVisualInfo *visual_info)
-{
- Colormap colormap;
- XSetWindowAttributes window_attributes;
- Window window = None;
-
- colormap = XCreateColormap (display,
- RootWindow (display, visual_info->screen),
- visual_info->visual,
- AllocNone);
- window_attributes.colormap = colormap;
- window_attributes.border_pixel = 0;
- window = XCreateWindow (display, RootWindow (display, visual_info->screen),
- -1, -1, 1, 1, 0,
- visual_info->depth,
- InputOutput,
- visual_info->visual,
- CWBorderPixel | CWColormap, &window_attributes);
- XFreeColormap (display, colormap);
-
- XFlush (display);
- return window;
-}
-
-static cairo_bool_t
-multithread_makecurrent_available (Display *display)
-{
- const char *extensions = glXQueryExtensionsString (display,
- DefaultScreen (display));
- return !! strstr(extensions, "GLX_MESA_multithread_makecurrent");
-}
-
-static void
-draw_to_surface (cairo_surface_t *surface)
-{
- cairo_t *cr = cairo_create (surface);
- cairo_paint (cr);
- cairo_destroy (cr);
-}
-
-static cairo_test_status_t
-preamble (cairo_test_context_t *test_ctx)
-{
- int rgba_attribs[] = {
- GLX_RGBA,
- GLX_RED_SIZE, 1,
- GLX_GREEN_SIZE, 1,
- GLX_BLUE_SIZE, 1,
- GLX_ALPHA_SIZE, 1,
- GLX_DOUBLEBUFFER,
- None
- };
-
- XVisualInfo *visual_info;
- GLXContext glx_context;
- cairo_device_t *device;
- Display *display;
- Window test_window;
- cairo_surface_t *window_surface;
- cairo_bool_t has_multithread_makecurrent;
-
- display = XOpenDisplay (NULL);
- if (display == NULL)
- return CAIRO_TEST_UNTESTED;
-
- visual_info = glXChooseVisual (display, DefaultScreen (display), rgba_attribs);
- if (visual_info == NULL) {
- XCloseDisplay (display);
- return CAIRO_TEST_UNTESTED;
- }
-
- glx_context = glXCreateContext (display, visual_info, NULL, True);
- if (glx_context == NULL) {
- XCloseDisplay (display);
- return CAIRO_TEST_UNTESTED;
- }
-
- test_window = create_test_window (display, glx_context, visual_info);
- XFree (visual_info);
- if (test_window == None) {
- XCloseDisplay (display);
- return CAIRO_TEST_UNTESTED;
- }
-
- has_multithread_makecurrent = multithread_makecurrent_available (display);
-
- glXMakeCurrent (display, None, None);
-
- /* Creating the device should actually change the GL context, because of
- * the creation/activation of a dummy window used for texture surfaces. */
- device = cairo_glx_device_create (display, glx_context);
-
- /* It's important that when multithread_makecurrent isn't available the
- * Cairo backend clears the current context, so that the dummy texture
- * window is not active while the device is unlocked. */
- if (has_multithread_makecurrent) {
- assert (None != glXGetCurrentDrawable ());
- assert (display == glXGetCurrentDisplay ());
- assert (glx_context == glXGetCurrentContext ());
- } else {
- assert (None == glXGetCurrentDrawable ());
- assert (None == glXGetCurrentDisplay ());
- assert (None == glXGetCurrentContext ());
- }
-
- window_surface = cairo_gl_surface_create_for_window (device, test_window,
- 1, 1);
- assert (cairo_surface_status (window_surface) == CAIRO_STATUS_SUCCESS);
-
- draw_to_surface (window_surface);
- if (has_multithread_makecurrent) {
- assert (test_window == glXGetCurrentDrawable ());
- assert (display == glXGetCurrentDisplay ());
- assert (glx_context == glXGetCurrentContext ());
- } else {
- assert (None == glXGetCurrentDrawable ());
- assert (None == glXGetCurrentDisplay ());
- assert (None == glXGetCurrentContext ());
- }
-
- /* In this case, drawing to the window surface will not change the current
- * GL context, so Cairo setting the current surface and context to none. */
- glXMakeCurrent (display, test_window, glx_context);
- draw_to_surface (window_surface);
- assert (test_window == glXGetCurrentDrawable ());
- assert (display == glXGetCurrentDisplay ());
- assert (glx_context == glXGetCurrentContext ());
-
- /* There should be no context change when destroying the device. */
- cairo_device_destroy (device);
- assert (test_window == glXGetCurrentDrawable ());
- assert (display == glXGetCurrentDisplay ());
- assert (glx_context == glXGetCurrentContext ());
-
- glXDestroyContext(display, glx_context);
- XDestroyWindow (display, test_window);
- XCloseDisplay (display);
-
- return CAIRO_TEST_SUCCESS;
-}
-
-CAIRO_TEST (gl_device_creation_changes_context,
- "Test that using the Cairo GL backend leaves the current GL context in the appropriate state",
- "gl", /* keywords */
- NULL, /* requirements */
- 0, 0,
- preamble, NULL)
diff --git a/test/gl-oversized-surface.c b/test/gl-oversized-surface.c
deleted file mode 100644
index 4c46efd80..000000000
--- a/test/gl-oversized-surface.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright © 2012 Igalia S.L.
- * Copyright © 2009 Eric Anholt
- * Copyright © 2009 Chris Wilson
- * Copyright © 2005 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
- * 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.
- *
- * IGALIA S.L. 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: Martin Robinson <mrobinson@igalia.com>
- */
-
-#include "cairo-test.h"
-#include <cairo-gl.h>
-#include <assert.h>
-#include <limits.h>
-
-static cairo_test_status_t
-preamble (cairo_test_context_t *test_ctx)
-{
- int rgba_attribs[] = {
- GLX_RGBA,
- GLX_RED_SIZE, 1,
- GLX_GREEN_SIZE, 1,
- GLX_BLUE_SIZE, 1,
- GLX_ALPHA_SIZE, 1,
- GLX_DOUBLEBUFFER,
- None
- };
-
- Display *display;
- XVisualInfo *visual_info;
- GLXContext glx_context;
- cairo_device_t *device;
- cairo_surface_t *oversized_surface;
- cairo_test_status_t test_status = CAIRO_TEST_SUCCESS;
-
- display = XOpenDisplay (NULL);
- if (display == NULL)
- return CAIRO_TEST_UNTESTED;
-
- visual_info = glXChooseVisual (display, DefaultScreen (display), rgba_attribs);
- if (visual_info == NULL) {
- XCloseDisplay (display);
- return CAIRO_TEST_UNTESTED;
- }
-
- glx_context = glXCreateContext (display, visual_info, NULL, True);
- if (glx_context == NULL) {
- XCloseDisplay (display);
- return CAIRO_TEST_UNTESTED;
- }
-
- device = cairo_glx_device_create (display, glx_context);
-
- oversized_surface = cairo_gl_surface_create (device, CAIRO_CONTENT_COLOR_ALPHA, INT_MAX, INT_MAX);
- if (cairo_surface_status (oversized_surface) != CAIRO_STATUS_INVALID_SIZE)
- test_status = CAIRO_TEST_FAILURE;
-
- cairo_device_destroy (device);
- glXDestroyContext(display, glx_context);
- XCloseDisplay (display);
-
- return test_status;
-}
-
-CAIRO_TEST (gl_oversized_surface,
- "Test that creating a surface beyond texture limits results in an error surface",
- "gl", /* keywords */
- NULL, /* requirements */
- 0, 0,
- preamble, NULL)
diff --git a/test/gl-surface-source.c b/test/gl-surface-source.c
deleted file mode 100644
index 09d4d9c47..000000000
--- a/test/gl-surface-source.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright © 2008 Chris Wilson
- * Copyright © 2010 Intel Corporation
- *
- * 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-gl.h>
-
-#include "surface-source.c"
-
-struct closure {
- Display *dpy;
- GLXContext ctx;
-};
-
-static void
-cleanup (void *data)
-{
- struct closure *arg = data;
-
- glXDestroyContext (arg->dpy, arg->ctx);
- XCloseDisplay (arg->dpy);
-
- free (arg);
-}
-
-static cairo_surface_t *
-create_source_surface (int size)
-{
- int rgba_attribs[] = {
- GLX_RGBA,
- GLX_RED_SIZE, 1,
- GLX_GREEN_SIZE, 1,
- GLX_BLUE_SIZE, 1,
- GLX_ALPHA_SIZE, 1,
- GLX_DOUBLEBUFFER,
- None
- };
- XVisualInfo *visinfo;
- GLXContext ctx;
- struct closure *arg;
- cairo_device_t *device;
- cairo_surface_t *surface;
- Display *dpy;
-
- dpy = XOpenDisplay (NULL);
- if (dpy == NULL)
- return NULL;
-
- visinfo = glXChooseVisual (dpy, DefaultScreen (dpy), rgba_attribs);
- if (visinfo == NULL) {
- XCloseDisplay (dpy);
- return NULL;
- }
-
- ctx = glXCreateContext (dpy, visinfo, NULL, True);
- XFree (visinfo);
-
- if (ctx == NULL) {
- XCloseDisplay (dpy);
- return NULL;
- }
-
- arg = xmalloc (sizeof (struct closure));
- arg->dpy = dpy;
- arg->ctx = ctx;
- device = cairo_glx_device_create (dpy, ctx);
- if (cairo_device_set_user_data (device,
- (cairo_user_data_key_t *) cleanup,
- arg,
- cleanup))
- {
- cleanup (arg);
- return NULL;
- }
-
- surface = cairo_gl_surface_create (device,
- CAIRO_CONTENT_COLOR_ALPHA,
- size, size);
- cairo_device_destroy (device);
-
- return surface;
-}
-
-CAIRO_TEST (gl_surface_source,
- "Test using a GL surface as the source",
- "source", /* keywords */
- NULL, /* requirements */
- SIZE, SIZE,
- preamble, draw)
diff --git a/test/meson.build b/test/meson.build
index 47d590690..548e25b4d 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -24,10 +24,12 @@ test_sources = [
'bug-spline.c',
'big-trap.c',
'bilevel-image.c',
- 'bug-40410.c',
+ 'bug-277.c',
'bug-361.c',
+ 'bug-40410.c',
'bug-431.c',
'bug-448.c',
+ 'bug-535.c',
'bug-51910.c',
'bug-75705.c',
'bug-84115.c',
@@ -94,6 +96,7 @@ test_sources = [
'create-for-stream.c',
'create-from-broken-png-stream.c',
'create-from-png.c',
+ 'create-from-png-16bit.c',
'create-from-png-stream.c',
'culled-glyphs.c',
'curve-to-as-line-to.c',
@@ -304,6 +307,7 @@ test_sources = [
'rotated-clip.c',
'rounded-rectangle-fill.c',
'rounded-rectangle-stroke.c',
+ 'round-join-bug-520.c',
'sample.c',
'scale-down-source-surface-paint.c',
'scale-offset-image.c',
@@ -425,15 +429,14 @@ test_ft_font_sources = [
'ft-text-antialias-none.c',
]
-test_gl_sources = [
- 'gl-device-release.c',
- 'gl-oversized-surface.c',
- 'gl-surface-source.c',
+test_ft_svg_font_sources = [
+ 'ft-svg-color-font.c',
]
-test_egl_sources = [
- 'egl-oversized-surface.c',
- 'egl-surface-source.c',
+test_ft_svg_ttx_font_sources = [
+ 'ft-svg-cairo-logo.c',
+ 'ft-svg-render.c',
+ 'ft-svg-render-color.c'
]
test_quartz_sources = [
@@ -480,6 +483,7 @@ test_multi_page_sources = [
]
test_fallback_resolution_sources = [
+ 'create-regions.c',
'fallback-resolution.c',
]
@@ -515,6 +519,18 @@ ps2png_sources = [
'ps2png.c',
]
+test_ttx_fonts = [
+ 'cairo-logo-font.ttx',
+ 'cairo-svg-test-color.ttx',
+ 'cairo-svg-test-doc.ttx',
+ 'cairo-svg-test-fill.ttx',
+ 'cairo-svg-test-gradient.ttx',
+ 'cairo-svg-test-path.ttx',
+ 'cairo-svg-test-shapes.ttx',
+ 'cairo-svg-test-stroke.ttx',
+ 'cairo-svg-test-transform.ttx',
+]
+
build_any2ppm = false
has_multipage_surfaces = false
add_fallback_resolution = false
@@ -525,6 +541,12 @@ endif
if feature_conf.get('CAIRO_HAS_FT_FONT', 0) == 1 and feature_conf.get('CAIRO_HAS_FC_FONT', 0) == 1
test_sources += test_ft_font_sources
+ if conf.get('HAVE_FT_SVG_DOCUMENT', 0) == 1
+ test_sources += test_ft_svg_font_sources
+ if conf.get('CAIRO_CAN_TEST_TTX_FONT', 0) == 1
+ test_sources += test_ft_svg_ttx_font_sources
+ endif
+ endif
endif
if feature_conf.get('CAIRO_HAS_QUARTZ_SURFACE', 0) == 1
@@ -563,10 +585,6 @@ if feature_conf.get('CAIRO_HAS_XLIB_XRENDER_SURFACE', 0) == 1
test_sources += test_xlib_xrender_sources
endif
-if feature_conf.get('CAIRO_HAS_EGL_FUNCTIONS', 0) == 1
- test_sources += test_egl_sources
-endif
-
if has_multipage_surfaces
test_sources += test_multi_page_sources
endif
@@ -629,18 +647,30 @@ exe = executable('cairo-test-suite', [cairo_test_suite_sources, test_sources, ca
libpdiff_dep],
)
-html_files = ['index.html', 'testtable.js', 'view-test-results.py']
-foreach file : html_files
+build_dir_files = ['completion.bash', 'index.html', 'testtable.js', 'view-test-results.py']
+foreach file : build_dir_files
configure_file(input: file, output : file, copy: true)
endforeach
if build_machine.system() != 'windows'
- run_command('ln', '-sf',
+ run_command('ln', '-sfn',
meson.current_source_dir(),
- join_paths(meson.current_build_dir(), 'srcdir'),
+ meson.current_build_dir() / 'srcdir',
check: true)
endif
+if ttx.found()
+ # By default, if the output file exists, ttx creates a new name. We specify the full
+ # output name to make ttx overwrite the existing file instead of creating a new file.
+ foreach ttx_font : test_ttx_fonts
+ custom_target(ttx_font,
+ input: ttx_font,
+ command: [ ttx, '-q', '-o', '@OUTDIR@' / '@BASENAME@.ttf', '@INPUT@' ],
+ output: '@BASENAME@.ttf',
+ build_by_default: true)
+ endforeach
+endif
+
env = environment()
env.set('srcdir', meson.current_source_dir())
@@ -651,3 +681,9 @@ test('cairo', exe,
suite: ['cairo-test-suite', 'slow'],
workdir: meson.current_build_dir(),
depends: test_depends)
+
+# The SVG renderer debug tools can only be built if the _cairo_debug_svg_render()
+# function has been exposed by defining DEBUG_SVG_RENDER
+if conf.get('HAVE_FT_SVG_DOCUMENT', 0) == 1 and cc.get_define('DEBUG_SVG_RENDER') != ''
+ subdir('svg')
+endif
diff --git a/test/pattern-getters.c b/test/pattern-getters.c
index e0ece398f..49027e913 100644
--- a/test/pattern-getters.c
+++ b/test/pattern-getters.c
@@ -151,7 +151,7 @@ draw (cairo_t *cr, int width, int height)
}
if (!double_buf_equal (ctx, new_buf, expected_values,
- ARRAY_LENGTH (expected_values)) != 0)
+ ARRAY_LENGTH (expected_values)))
{
cairo_pattern_destroy (pat);
return CAIRO_TEST_FAILURE;
diff --git a/test/pdf-operators-text.c b/test/pdf-operators-text.c
index 556b9d7d8..6d654d115 100644
--- a/test/pdf-operators-text.c
+++ b/test/pdf-operators-text.c
@@ -127,6 +127,7 @@ draw (cairo_t *cr, int width, int height)
cairo_set_font_size (cr, FONT_SIZE);
text = malloc (strlen(WORD) * NUM_WORDS + 1);
+ text[0] = '\0';
for (i = 0; i < NUM_WORDS; i++)
strcat (text, WORD);
diff --git a/test/pdf-tagged-text.c b/test/pdf-tagged-text.c
index 378e6a920..1a2f62dac 100644
--- a/test/pdf-tagged-text.c
+++ b/test/pdf-tagged-text.c
@@ -42,6 +42,9 @@
#endif
#include <cairo.h>
+
+#if CAIRO_HAS_PDF_SURFACE
+
#include <cairo-pdf.h>
/* This test checks PDF with
@@ -604,3 +607,5 @@ CAIRO_TEST (pdf_tagged_text,
NULL, /* requirements */
0, 0,
preamble, NULL)
+
+#endif /* CAIRO_HAS_PDF_SURFACE */
diff --git a/test/pdiff/CMakeLists.txt b/test/pdiff/CMakeLists.txt
deleted file mode 100644
index 6e4fa7a8a..000000000
--- a/test/pdiff/CMakeLists.txt
+++ /dev/null
@@ -1,55 +0,0 @@
-PROJECT (PerceptualDiff)
-SET(DIFF_SRC PerceptualDiff.cpp LPyramid.cpp RGBAImage.cpp
-CompareArgs.cpp Metric.cpp)
-
-ADD_EXECUTABLE (perceptualdiff ${DIFF_SRC})
-
-# look for libtiff
-FIND_PATH(TIFF_INCLUDE_DIR tiff.h
- /usr/local/include
- /usr/include
- /opt/local/include
-)
-
-FIND_LIBRARY(TIFF_LIBRARY tiff
- /usr/lib
- /usr/local/lib
- /opt/local/lib
-)
-
-IF(TIFF_INCLUDE_DIR)
- IF(TIFF_LIBRARY)
- SET( TIFF_FOUND "YES" )
- SET( TIFF_LIBRARIES ${TIFF_LIBRARY} )
- ENDIF(TIFF_LIBRARY)
-ENDIF(TIFF_INCLUDE_DIR)
-
-IF(TIFF_FOUND)
- INCLUDE_DIRECTORIES(${TIFF_INCLUDE_DIR})
- TARGET_LINK_LIBRARIES(perceptualdiff ${TIFF_LIBRARY})
-ENDIF(TIFF_FOUND)
-
-# look for libpng
-FIND_PATH(PNG_INCLUDE_DIR png.h
- /usr/local/include
- /usr/include
- /opt/local/include
-)
-
-FIND_LIBRARY(PNG_LIBRARY png
- /usr/lib
- /usr/local/lib
- /opt/local/lib
-)
-
-IF(PNG_INCLUDE_DIR)
- IF(PNG_LIBRARY)
- SET( PNG_FOUND "YES" )
- SET( PNG_LIBRARIES ${PNG_LIBRARY} )
- ENDIF(PNG_LIBRARY)
-ENDIF(PNG_INCLUDE_DIR)
-
-IF(PNG_FOUND)
- INCLUDE_DIRECTORIES(${PNG_INCLUDE_DIR})
- TARGET_LINK_LIBRARIES(perceptualdiff ${PNG_LIBRARY})
-ENDIF(PNG_FOUND) \ No newline at end of file
diff --git a/test/pdiff/Makefile.am b/test/pdiff/Makefile.am
deleted file mode 100644
index 73098da78..000000000
--- a/test/pdiff/Makefile.am
+++ /dev/null
@@ -1,19 +0,0 @@
-include $(top_srcdir)/build/Makefile.am.common
-
-EXTRA_PROGRAMS += perceptualdiff
-EXTRA_DIST += gpl.txt
-
-noinst_LTLIBRARIES = libpdiff.la
-libpdiff_la_SOURCES = \
- pdiff.h \
- lpyramid.c \
- lpyramid.h \
- pdiff.c
-
-perceptualdiff_SOURCES = \
- args.c \
- args.h \
- perceptualdiff.c
-
-AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src $(CAIRO_CFLAGS)
-LDADD = libpdiff.la $(top_builddir)/src/libcairo.la
diff --git a/test/pdiff/Makefile.win32 b/test/pdiff/Makefile.win32
deleted file mode 100644
index 3d64676da..000000000
--- a/test/pdiff/Makefile.win32
+++ /dev/null
@@ -1,14 +0,0 @@
-top_srcdir = ../..
-include $(top_srcdir)/build/Makefile.win32.common
-
-SOURCES = \
- lpyramid.c \
- pdiff.c \
- $(NULL)
-
-OBJECTS = $(patsubst %.c, $(CFG)/%-static.obj, $(SOURCES))
-
-all: $(CFG)/pdiff.lib
-
-$(CFG)/pdiff.lib: $(OBJECTS)
- @$(AR) $(CAIRO_ARFLAGS) -OUT:$@ $(OBJECTS)
diff --git a/test/reference/arc-direction.pdf.ref.png b/test/reference/arc-direction.pdf.ref.png
deleted file mode 100644
index 7b14d71a2..000000000
--- a/test/reference/arc-direction.pdf.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/big-little-triangle.traps.argb32.ref.png b/test/reference/big-little-triangle.traps.argb32.ref.png
deleted file mode 100644
index 5308ccedb..000000000
--- a/test/reference/big-little-triangle.traps.argb32.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/big-little-triangle.traps.rgb24.ref.png b/test/reference/big-little-triangle.traps.rgb24.ref.png
deleted file mode 100644
index 9e4773b2d..000000000
--- a/test/reference/big-little-triangle.traps.rgb24.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/bug-535.ref.png b/test/reference/bug-535.ref.png
new file mode 100644
index 000000000..7d5589c1d
--- /dev/null
+++ b/test/reference/bug-535.ref.png
Binary files differ
diff --git a/test/reference/clip-fill-rule.pdf.rgb24.ref.png b/test/reference/clip-fill-rule.pdf.rgb24.ref.png
deleted file mode 100644
index a7acc4fa4..000000000
--- a/test/reference/clip-fill-rule.pdf.rgb24.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/coverage-column-triangles.ref.png b/test/reference/coverage-column-triangles.ref.png
index aa61031b7..24ccc9f2a 100644
--- a/test/reference/coverage-column-triangles.ref.png
+++ b/test/reference/coverage-column-triangles.ref.png
Binary files differ
diff --git a/test/reference/coverage-column-triangles.xfail.png b/test/reference/coverage-column-triangles.xfail.png
index 566b41544..9af5253c5 100644
--- a/test/reference/coverage-column-triangles.xfail.png
+++ b/test/reference/coverage-column-triangles.xfail.png
Binary files differ
diff --git a/test/reference/coverage-column-triangles.xlib.xfail.png b/test/reference/coverage-column-triangles.xlib.xfail.png
index f433b7a84..18e4af2da 100644
--- a/test/reference/coverage-column-triangles.xlib.xfail.png
+++ b/test/reference/coverage-column-triangles.xlib.xfail.png
Binary files differ
diff --git a/test/reference/create-from-png-16bit.base.png b/test/reference/create-from-png-16bit.base.png
new file mode 100644
index 000000000..7e0f00e33
--- /dev/null
+++ b/test/reference/create-from-png-16bit.base.png
Binary files differ
diff --git a/test/reference/create-from-png-16bit.image16.ref.png b/test/reference/create-from-png-16bit.image16.ref.png
new file mode 100644
index 000000000..9591a12dd
--- /dev/null
+++ b/test/reference/create-from-png-16bit.image16.ref.png
Binary files differ
diff --git a/test/reference/create-from-png-16bit.ref.png b/test/reference/create-from-png-16bit.ref.png
new file mode 100644
index 000000000..296c559bc
--- /dev/null
+++ b/test/reference/create-from-png-16bit.ref.png
Binary files differ
diff --git a/test/reference/create-regions.pdf.ref.png b/test/reference/create-regions.pdf.ref.png
new file mode 100644
index 000000000..5762fbbc7
--- /dev/null
+++ b/test/reference/create-regions.pdf.ref.png
Binary files differ
diff --git a/test/reference/create-regions.ps.ref.png b/test/reference/create-regions.ps.ref.png
new file mode 100644
index 000000000..0478e249d
--- /dev/null
+++ b/test/reference/create-regions.ps.ref.png
Binary files differ
diff --git a/test/reference/create-regions.svg.ref.png b/test/reference/create-regions.svg.ref.png
new file mode 100644
index 000000000..a89dfb044
--- /dev/null
+++ b/test/reference/create-regions.svg.ref.png
Binary files differ
diff --git a/test/reference/dash-offset-negative.pdf.ref.png b/test/reference/dash-offset-negative.pdf.ref.png
deleted file mode 100644
index df22d08b2..000000000
--- a/test/reference/dash-offset-negative.pdf.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/font-matrix-translation.traps.ref.png b/test/reference/font-matrix-translation.traps.ref.png
deleted file mode 100644
index a4a108206..000000000
--- a/test/reference/font-matrix-translation.traps.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/ft-color-font.pdf.ref.png b/test/reference/ft-color-font.pdf.ref.png
deleted file mode 100644
index 3ea9e7850..000000000
--- a/test/reference/ft-color-font.pdf.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/ft-color-font.pdf.xfail.png b/test/reference/ft-color-font.pdf.xfail.png
new file mode 100644
index 000000000..5832a3464
--- /dev/null
+++ b/test/reference/ft-color-font.pdf.xfail.png
Binary files differ
diff --git a/test/reference/ft-show-glyphs-positioning.traps.ref.png b/test/reference/ft-show-glyphs-positioning.traps.ref.png
deleted file mode 100644
index af6dcaf95..000000000
--- a/test/reference/ft-show-glyphs-positioning.traps.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/ft-show-glyphs-table.traps.ref.png b/test/reference/ft-show-glyphs-table.traps.ref.png
deleted file mode 100644
index ed6912489..000000000
--- a/test/reference/ft-show-glyphs-table.traps.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/ft-svg-cairo-logo.ref.png b/test/reference/ft-svg-cairo-logo.ref.png
new file mode 100644
index 000000000..0c92934d6
--- /dev/null
+++ b/test/reference/ft-svg-cairo-logo.ref.png
Binary files differ
diff --git a/test/reference/ft-svg-color-font.ref.png b/test/reference/ft-svg-color-font.ref.png
new file mode 100644
index 000000000..22bafde03
--- /dev/null
+++ b/test/reference/ft-svg-color-font.ref.png
Binary files differ
diff --git a/test/reference/ft-svg-render-color.ref.png b/test/reference/ft-svg-render-color.ref.png
new file mode 100644
index 000000000..d688c378c
--- /dev/null
+++ b/test/reference/ft-svg-render-color.ref.png
Binary files differ
diff --git a/test/reference/ft-svg-render-doc.ref.png b/test/reference/ft-svg-render-doc.ref.png
new file mode 100644
index 000000000..e7ecf7f1a
--- /dev/null
+++ b/test/reference/ft-svg-render-doc.ref.png
Binary files differ
diff --git a/test/reference/ft-svg-render-fill.ref.png b/test/reference/ft-svg-render-fill.ref.png
new file mode 100644
index 000000000..a72cdd1f2
--- /dev/null
+++ b/test/reference/ft-svg-render-fill.ref.png
Binary files differ
diff --git a/test/reference/ft-svg-render-gradient.ref.png b/test/reference/ft-svg-render-gradient.ref.png
new file mode 100644
index 000000000..d647dc06a
--- /dev/null
+++ b/test/reference/ft-svg-render-gradient.ref.png
Binary files differ
diff --git a/test/reference/ft-svg-render-path.ref.png b/test/reference/ft-svg-render-path.ref.png
new file mode 100644
index 000000000..2667059cc
--- /dev/null
+++ b/test/reference/ft-svg-render-path.ref.png
Binary files differ
diff --git a/test/reference/ft-svg-render-shapes.ref.png b/test/reference/ft-svg-render-shapes.ref.png
new file mode 100644
index 000000000..209e0ddb3
--- /dev/null
+++ b/test/reference/ft-svg-render-shapes.ref.png
Binary files differ
diff --git a/test/reference/ft-svg-render-stroke.ref.png b/test/reference/ft-svg-render-stroke.ref.png
new file mode 100644
index 000000000..86f1ab9b6
--- /dev/null
+++ b/test/reference/ft-svg-render-stroke.ref.png
Binary files differ
diff --git a/test/reference/ft-svg-render-transform.ref.png b/test/reference/ft-svg-render-transform.ref.png
new file mode 100644
index 000000000..dcc372aac
--- /dev/null
+++ b/test/reference/ft-svg-render-transform.ref.png
Binary files differ
diff --git a/test/reference/glyph-cache-pressure.traps.ref.png b/test/reference/glyph-cache-pressure.traps.ref.png
deleted file mode 100644
index a6e1b061f..000000000
--- a/test/reference/glyph-cache-pressure.traps.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/inverse-text.traps.ref.png b/test/reference/inverse-text.traps.ref.png
deleted file mode 100644
index b7bbb972f..000000000
--- a/test/reference/inverse-text.traps.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/line-width-large-overlap-offset.ps.ref.png b/test/reference/line-width-large-overlap-offset.ps.ref.png
deleted file mode 100644
index 3c3464bed..000000000
--- a/test/reference/line-width-large-overlap-offset.ps.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/partial-clip-text-right.traps.ref.png b/test/reference/partial-clip-text-right.traps.ref.png
deleted file mode 100644
index 2fbdca038..000000000
--- a/test/reference/partial-clip-text-right.traps.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/partial-clip-text-top.traps.ref.png b/test/reference/partial-clip-text-top.traps.ref.png
deleted file mode 100644
index d18475be3..000000000
--- a/test/reference/partial-clip-text-top.traps.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/quartz-color-font.ref.png b/test/reference/quartz-color-font.ref.png
index e52674ba0..0c185ae1b 100644
--- a/test/reference/quartz-color-font.ref.png
+++ b/test/reference/quartz-color-font.ref.png
Binary files differ
diff --git a/test/reference/record-fill-alpha.pdf.ref.png b/test/reference/record-fill-alpha.pdf.ref.png
deleted file mode 100644
index 8f72f68f4..000000000
--- a/test/reference/record-fill-alpha.pdf.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/record-mesh.ps.ref.png b/test/reference/record-mesh.ps.ref.png
deleted file mode 100644
index 015553650..000000000
--- a/test/reference/record-mesh.ps.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/record90-fill-alpha.pdf.ref.png b/test/reference/record90-fill-alpha.pdf.ref.png
deleted file mode 100644
index 167d7be65..000000000
--- a/test/reference/record90-fill-alpha.pdf.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/record90-paint-alpha-clip.quartz.ref.png b/test/reference/record90-paint-alpha-clip.quartz.ref.png
deleted file mode 100644
index b7703d47d..000000000
--- a/test/reference/record90-paint-alpha-clip.quartz.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/recordflip-whole-fill-alpha.quartz.ref.png b/test/reference/recordflip-whole-fill-alpha.quartz.ref.png
deleted file mode 100644
index 69035ef5f..000000000
--- a/test/reference/recordflip-whole-fill-alpha.quartz.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/recordflip-whole-paint-alpha-clip-mask.quartz.ref.png b/test/reference/recordflip-whole-paint-alpha-clip-mask.quartz.ref.png
deleted file mode 100644
index 6f14ad3b4..000000000
--- a/test/reference/recordflip-whole-paint-alpha-clip-mask.quartz.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/round-join-bug-520-bevel.pdf.ref.png b/test/reference/round-join-bug-520-bevel.pdf.ref.png
new file mode 100644
index 000000000..b1a38e12f
--- /dev/null
+++ b/test/reference/round-join-bug-520-bevel.pdf.ref.png
Binary files differ
diff --git a/test/reference/round-join-bug-520-bevel.quartz.ref.png b/test/reference/round-join-bug-520-bevel.quartz.ref.png
new file mode 100644
index 000000000..b8796ff1e
--- /dev/null
+++ b/test/reference/round-join-bug-520-bevel.quartz.ref.png
Binary files differ
diff --git a/test/reference/round-join-bug-520-bevel.ref.png b/test/reference/round-join-bug-520-bevel.ref.png
new file mode 100644
index 000000000..b888f9ba9
--- /dev/null
+++ b/test/reference/round-join-bug-520-bevel.ref.png
Binary files differ
diff --git a/test/reference/round-join-bug-520-bevel.svg.ref.png b/test/reference/round-join-bug-520-bevel.svg.ref.png
new file mode 100644
index 000000000..b1a38e12f
--- /dev/null
+++ b/test/reference/round-join-bug-520-bevel.svg.ref.png
Binary files differ
diff --git a/test/reference/round-join-bug-520-round.ref.png b/test/reference/round-join-bug-520-round.ref.png
new file mode 100644
index 000000000..b1a38e12f
--- /dev/null
+++ b/test/reference/round-join-bug-520-round.ref.png
Binary files differ
diff --git a/test/reference/round-join-bug-520-round.xlib-window.ref.png b/test/reference/round-join-bug-520-round.xlib-window.ref.png
new file mode 100644
index 000000000..14ed9cbfe
--- /dev/null
+++ b/test/reference/round-join-bug-520-round.xlib-window.ref.png
Binary files differ
diff --git a/test/reference/round-join-bug-520-round.xlib.ref.png b/test/reference/round-join-bug-520-round.xlib.ref.png
new file mode 100644
index 000000000..14ed9cbfe
--- /dev/null
+++ b/test/reference/round-join-bug-520-round.xlib.ref.png
Binary files differ
diff --git a/test/reference/select-font-face.traps.ref.png b/test/reference/select-font-face.traps.ref.png
deleted file mode 100644
index 1334a9a01..000000000
--- a/test/reference/select-font-face.traps.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/show-glyphs-advance.traps.ref.png b/test/reference/show-glyphs-advance.traps.ref.png
deleted file mode 100644
index e65ad05d5..000000000
--- a/test/reference/show-glyphs-advance.traps.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/show-text-current-point.traps.ref.png b/test/reference/show-text-current-point.traps.ref.png
deleted file mode 100644
index d60d4ac01..000000000
--- a/test/reference/show-text-current-point.traps.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/surface-pattern.quartz.xfail.png b/test/reference/surface-pattern.quartz.xfail.png
index 4ac47de5e..42938f026 100644
--- a/test/reference/surface-pattern.quartz.xfail.png
+++ b/test/reference/surface-pattern.quartz.xfail.png
Binary files differ
diff --git a/test/reference/text-antialias-gray.traps.ref.png b/test/reference/text-antialias-gray.traps.ref.png
deleted file mode 100644
index 06b805eaa..000000000
--- a/test/reference/text-antialias-gray.traps.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/user-font-color.image16.ref.png b/test/reference/user-font-color.image16.ref.png
index 404fbf948..b3721daf5 100644
--- a/test/reference/user-font-color.image16.ref.png
+++ b/test/reference/user-font-color.image16.ref.png
Binary files differ
diff --git a/test/reference/user-font-color.pdf.ref.png b/test/reference/user-font-color.pdf.ref.png
index 674d1a4d6..bc14795ca 100644
--- a/test/reference/user-font-color.pdf.ref.png
+++ b/test/reference/user-font-color.pdf.ref.png
Binary files differ
diff --git a/test/reference/user-font-color.ps.ref.png b/test/reference/user-font-color.ps.ref.png
index 36c5c84a7..59932e64e 100644
--- a/test/reference/user-font-color.ps.ref.png
+++ b/test/reference/user-font-color.ps.ref.png
Binary files differ
diff --git a/test/reference/user-font-color.quartz.ref.png b/test/reference/user-font-color.quartz.ref.png
index fc976e8ea..b7c484647 100644
--- a/test/reference/user-font-color.quartz.ref.png
+++ b/test/reference/user-font-color.quartz.ref.png
Binary files differ
diff --git a/test/reference/user-font-color.recording.ref.png b/test/reference/user-font-color.recording.ref.png
index 0b4cb06f5..e6f9f389e 100644
--- a/test/reference/user-font-color.recording.ref.png
+++ b/test/reference/user-font-color.recording.ref.png
Binary files differ
diff --git a/test/reference/user-font-color.ref.png b/test/reference/user-font-color.ref.png
index c4294c5f7..3986f10a7 100644
--- a/test/reference/user-font-color.ref.png
+++ b/test/reference/user-font-color.ref.png
Binary files differ
diff --git a/test/reference/user-font-color.script.xfail.png b/test/reference/user-font-color.script.xfail.png
index e268cdc03..c74331eaf 100644
--- a/test/reference/user-font-color.script.xfail.png
+++ b/test/reference/user-font-color.script.xfail.png
Binary files differ
diff --git a/test/reference/user-font-color.svg.ref.png b/test/reference/user-font-color.svg.ref.png
deleted file mode 100644
index 4ce8882f8..000000000
--- a/test/reference/user-font-color.svg.ref.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/user-font-color.svg.rgb24.xfail.png b/test/reference/user-font-color.svg.rgb24.xfail.png
deleted file mode 100644
index 37b8aaa1e..000000000
--- a/test/reference/user-font-color.svg.rgb24.xfail.png
+++ /dev/null
Binary files differ
diff --git a/test/reference/user-font-color.xcb.ref.png b/test/reference/user-font-color.xcb.ref.png
new file mode 100644
index 000000000..c3ec667b7
--- /dev/null
+++ b/test/reference/user-font-color.xcb.ref.png
Binary files differ
diff --git a/test/reference/user-font-color.xlib.ref.png b/test/reference/user-font-color.xlib.ref.png
new file mode 100644
index 000000000..c3ec667b7
--- /dev/null
+++ b/test/reference/user-font-color.xlib.ref.png
Binary files differ
diff --git a/test/reference/user-font-proxy.pdf.argb32.ref.png b/test/reference/user-font-proxy.pdf.argb32.ref.png
index 9d61720e7..bda5eec9d 100644
--- a/test/reference/user-font-proxy.pdf.argb32.ref.png
+++ b/test/reference/user-font-proxy.pdf.argb32.ref.png
Binary files differ
diff --git a/test/reference/user-font-proxy.pdf.rgb24.ref.png b/test/reference/user-font-proxy.pdf.rgb24.ref.png
index cffa9edb7..bda5eec9d 100644
--- a/test/reference/user-font-proxy.pdf.rgb24.ref.png
+++ b/test/reference/user-font-proxy.pdf.rgb24.ref.png
Binary files differ
diff --git a/test/reference/user-font-proxy.quartz.ref.png b/test/reference/user-font-proxy.quartz.ref.png
index f7b1163be..710f58a92 100644
--- a/test/reference/user-font-proxy.quartz.ref.png
+++ b/test/reference/user-font-proxy.quartz.ref.png
Binary files differ
diff --git a/test/reference/user-font-proxy.ref.png b/test/reference/user-font-proxy.ref.png
index 95c04633f..65014847a 100644
--- a/test/reference/user-font-proxy.ref.png
+++ b/test/reference/user-font-proxy.ref.png
Binary files differ
diff --git a/test/reference/user-font-proxy.svg.ref.png b/test/reference/user-font-proxy.svg.ref.png
index 106583e0f..7a083e6d8 100644
--- a/test/reference/user-font-proxy.svg.ref.png
+++ b/test/reference/user-font-proxy.svg.ref.png
Binary files differ
diff --git a/test/reference/user-font.pdf.xfail.png b/test/reference/user-font.pdf.xfail.png
new file mode 100644
index 000000000..b5145aed6
--- /dev/null
+++ b/test/reference/user-font.pdf.xfail.png
Binary files differ
diff --git a/test/reference/user-font.quartz.ref.png b/test/reference/user-font.quartz.ref.png
index f1a8d5752..665801d37 100644
--- a/test/reference/user-font.quartz.ref.png
+++ b/test/reference/user-font.quartz.ref.png
Binary files differ
diff --git a/test/reference/user-font.recording.ref.png b/test/reference/user-font.recording.ref.png
index aefe4c9fe..c1cb2bbc3 100644
--- a/test/reference/user-font.recording.ref.png
+++ b/test/reference/user-font.recording.ref.png
Binary files differ
diff --git a/test/reference/user-font.ref.png b/test/reference/user-font.ref.png
index 87a3f68e3..5a6af5490 100644
--- a/test/reference/user-font.ref.png
+++ b/test/reference/user-font.ref.png
Binary files differ
diff --git a/test/reference/user-font.svg.argb32.ref.png b/test/reference/user-font.svg.argb32.ref.png
new file mode 100644
index 000000000..e14924e9a
--- /dev/null
+++ b/test/reference/user-font.svg.argb32.ref.png
Binary files differ
diff --git a/test/reference/user-font.svg.rgb24.ref.png b/test/reference/user-font.svg.rgb24.ref.png
new file mode 100644
index 000000000..c534efcfe
--- /dev/null
+++ b/test/reference/user-font.svg.rgb24.ref.png
Binary files differ
diff --git a/test/round-join-bug-520.c b/test/round-join-bug-520.c
new file mode 100644
index 000000000..be2b5aa0d
--- /dev/null
+++ b/test/round-join-bug-520.c
@@ -0,0 +1,109 @@
+/*
+ * Author: Christian Rohlfs, 2022
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "cairo-test.h"
+
+#define WIDTH 100
+#define HEIGHT WIDTH
+
+static cairo_test_status_t
+draw_round(cairo_t *cr, int width, int height)
+{
+ /* Fail condition:
+ 0 >= 2 * ( 1 - tolerance / (line_width / 2) )^2 - 1,
+ with the default tolerance of 0.1, `failing_line_width` is in
+ [0.117157287525381; 0.682842712474619]
+ range.
+ */
+
+ double failing_line_width = 0.3;
+
+ cairo_set_tolerance(cr, 0.1);
+ cairo_scale(cr, width, height);
+
+ cairo_set_source_rgb(cr, 1, 1, 1);
+ cairo_paint(cr);
+
+ cairo_move_to(cr, 0.2, 0.2);
+ cairo_line_to(cr, 0.8, 0.2);
+ cairo_line_to(cr, 0.8, 0.8);
+ cairo_line_to(cr, 0.2, 0.8);
+ cairo_close_path(cr);
+
+ cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
+ cairo_set_source_rgb(cr, 0, 0, 0);
+ cairo_set_line_width(cr, failing_line_width);
+ cairo_stroke(cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+static cairo_test_status_t
+draw_bevel(cairo_t *cr, int width, int height)
+{
+ /* Fail condition:
+ arc_height < tolerance
+ For 90° join `arc_height` is equal to
+ line_width / 2 * (1 - sqrt(1/2))
+ which is 0.1464466094067262 of a `line_width`.
+ */
+
+ double line_width = 0.3;
+ double failing_tolerance = 0.3 * line_width;
+
+ cairo_set_tolerance(cr, width * failing_tolerance);
+ cairo_scale(cr, width, height);
+
+ cairo_set_source_rgb(cr, 1, 1, 1);
+ cairo_paint(cr);
+
+ cairo_move_to(cr, 0.2, 0.2);
+ cairo_line_to(cr, 0.8, 0.2);
+ cairo_line_to(cr, 0.8, 0.8);
+ cairo_line_to(cr, 0.2, 0.8);
+ cairo_close_path(cr);
+
+ cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
+ cairo_set_source_rgb(cr, 0, 0, 0);
+ cairo_set_line_width(cr, line_width);
+ cairo_stroke(cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+
+CAIRO_TEST (round_join_bug_520_round,
+ "Tests round joins within tolerance",
+ "stroke, cap, join", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT,
+ NULL, draw_round)
+
+CAIRO_TEST (round_join_bug_520_bevel,
+ "Tests round joins omission when `arc_height < tolerance`",
+ "stroke, cap, join", /* keywords */
+ NULL, /* requirements */
+ WIDTH, HEIGHT,
+ NULL, draw_bevel)
+
diff --git a/test/svg/README b/test/svg/README
new file mode 100644
index 000000000..c4504dc9b
--- /dev/null
+++ b/test/svg/README
@@ -0,0 +1,22 @@
+build_ttx_fonts.py
+==================
+Is used to create the test/*.ttx files used for testing the SVG glyph renderer.
+
+build_ttx_fonts.py will look for files of the form
+
+<font-name>.<char>.<test-name>.svg
+
+in the input directory, and using svg-font-template.ttx, create <font-name>.ttx
+files that contain one glyph for each svg file. Each <font-name>.ttx will contain
+a glyph for each svg with the matching <font-name> prefix. Each glyphs will be mapped
+to the <char> i nthe svg filename. The <char> must be one of 0-9,A-F.
+
+svg-render.c
+============
+svg-render renders SVG files using both librsvg and cairo-svg-glyph-render.c.
+It is used for testing cairo-svg-glyph-render.c during development.
+
+To use svg-render, cairo must be built with CFLAGS="-DDEBUG_SVG_RENDER" to enable the
+_cairo_debug_svg_render() function.
+
+
diff --git a/test/svg/build_ttx_fonts.py b/test/svg/build_ttx_fonts.py
new file mode 100755
index 000000000..d7e7f5b8f
--- /dev/null
+++ b/test/svg/build_ttx_fonts.py
@@ -0,0 +1,161 @@
+#!/usr/bin/env python3
+
+# Build the ttx cairo svg test fonts from svg files
+# The svg files use the naming convention
+# <font-name>.<char>.<test-name>.svg
+# eg "circle.A.cx_cy_r.svg"
+#
+# <font-name> is use to create the name of the ttx font.
+# <char> is a ascii hex character (uppercase) that the font fill map to the SVG description.
+# <test-name> is a descriptive name of the SVG file and is not used to build the font…
+#
+# This script looks for all files matching the above pattern and
+# creates one ttx font for each unique <font-name>. Each font will
+# contain up to 16 characters. The SVG description of each character
+# and the character that maps to the SVG description is obtained from
+# the SVG file beginning with <font-name>.<char>.
+
+import argparse
+import os
+import re
+import sys
+import xml.dom.minidom
+
+TEMPLATE_FILE="svg-font-template.ttx"
+
+glyph_names = {
+ '0': 'zero',
+ '1': 'one',
+ '2': 'two',
+ '3': 'three',
+ '4': 'four',
+ '5': 'five',
+ '6': 'six',
+ '7': 'seven',
+ '8': 'eight',
+ '9': 'nine',
+ 'A': 'A',
+ 'B': 'B',
+ 'C': 'C',
+ 'D': 'D',
+ 'E': 'E',
+ 'F': 'F'
+}
+
+# files is list of (char, filename)
+def build_font(font_name, files, in_dir, out_dir, no_reformat):
+ name = "cairo-svg-test-" + font_name
+ doc = xml.dom.minidom.parse(os.path.join(in_dir, TEMPLATE_FILE))
+ glyph_id = 1
+ text_nl = doc.createTextNode('\n\n')
+ for f in sorted(files):
+ glyph_name = glyph_names[f[0]]
+
+ glyph_order = doc.getElementsByTagName('GlyphOrder')[0]
+ glyph_id_elem = doc.createElement('GlyphID')
+ glyph_id_elem.setAttribute('id', str(glyph_id))
+ glyph_id_elem.setAttribute('name', glyph_name)
+ glyph_order.appendChild(glyph_id_elem)
+ glyph_order.appendChild(text_nl)
+
+ hmtx = doc.getElementsByTagName('hmtx')[0]
+ mtx = doc.createElement('mtx')
+ mtx.setAttribute('name', glyph_name)
+ mtx.setAttribute('width', '1100')
+ mtx.setAttribute('lsb', '0')
+ hmtx.appendChild(mtx)
+
+ cmap_format = doc.getElementsByTagName('cmap_format_4')[0]
+ map = doc.createElement('map')
+ map.setAttribute('code', hex(ord(f[0])))
+ map.setAttribute('name', glyph_name)
+ cmap_format.appendChild(map)
+
+ glyf = doc.getElementsByTagName('glyf')[0]
+ tt_glyph = doc.createElement('TTGlyph')
+ tt_glyph.setAttribute('name', glyph_name)
+ glyf.appendChild(tt_glyph)
+ contour = doc.createElement('contour')
+ tt_glyph.appendChild(contour)
+ pt = doc.createElement('pt')
+ pt.setAttribute('x', "0")
+ pt.setAttribute('y', "0")
+ pt.setAttribute('on', "1")
+ contour.appendChild(pt)
+ pt = doc.createElement('pt')
+ pt.setAttribute('x', "0")
+ pt.setAttribute('y', "1000")
+ pt.setAttribute('on', "1")
+ contour.appendChild(pt)
+ pt = doc.createElement('pt')
+ pt.setAttribute('x', "1000")
+ pt.setAttribute('y', "1000")
+ pt.setAttribute('on', "1")
+ contour.appendChild(pt)
+ pt = doc.createElement('pt')
+ pt.setAttribute('x', "1000")
+ pt.setAttribute('y', "0")
+ pt.setAttribute('on', "1")
+ contour.appendChild(pt)
+ instructions = doc.createElement('instructions')
+ tt_glyph.appendChild(instructions)
+
+ svg = doc.getElementsByTagName('SVG')[0]
+ svgdoc = doc.createElement('svgDoc')
+ svgdoc.setAttribute('startGlyphID', str(glyph_id))
+ svgdoc.setAttribute('endGlyphID', str(glyph_id))
+ with open(os.path.join(in_dir, f[1]), 'r') as svg_file:
+ svg_data = svg_file.read()
+ cdata = doc.createCDATASection(svg_data)
+ svgdoc.appendChild(cdata)
+ svg.appendChild(svgdoc)
+ glyph_id += 1
+
+ name_record = doc.getElementsByTagName('namerecord')[0]
+ name_record.firstChild.replaceWholeText(name.replace("-", " ").title())
+ name_record = doc.getElementsByTagName('namerecord')[2]
+ name_record.firstChild.replaceWholeText(name.replace("-", " ").title() + " Regular")
+
+ ttx_filename = os.path.join(out_dir, name + '.ttx')
+ ttf_filename = os.path.join(out_dir, name + '.ttf')
+ with open(ttx_filename, 'w') as ttx_file:
+ doc.writexml(ttx_file)
+
+ if not no_reformat:
+ # Convert to ttf and back to ttx. This reformats the ttx file
+ # which allows better quality diffs.
+ if os.path.exists(ttf_filename):
+ os.remove(ttf_filename)
+ os.system("ttx " + ttx_filename)
+ os.remove(ttx_filename)
+ os.system("ttx " + ttf_filename)
+ os.remove(ttf_filename)
+
+def build_file_list(in_dir):
+ dict = {}
+ regex_prog = re.compile(r"([^\.]+)\.(.)\.[^\.]+\.svg", re.ASCII)
+ files = os.listdir(in_dir)
+ for f in files:
+ match = regex_prog.fullmatch(f)
+ if match:
+ fontname = match.group(1)
+ character = match.group(2)
+ if (fontname not in dict):
+ dict[fontname] = [(character, f)];
+ else:
+ dict[fontname].append((character, f))
+ return dict
+
+if __name__=='__main__':
+ parser = argparse.ArgumentParser(description='Build ttx fonts.')
+ parser.add_argument("-i", nargs=1, metavar="indir", default=["."], help="Input directory")
+ parser.add_argument("-o", nargs=1, metavar="outdir", default=["."], help="Output directory")
+ parser.add_argument("-n", action='store_true', help="Don't reformat the output.")
+ args = parser.parse_args()
+ in_dir = args.i[0]
+ out_dir = args.o[0]
+ no_reformat = args.n
+ file_list = build_file_list(in_dir)
+ font_name = None
+ for key, value in file_list.items():
+ build_font(key, value, in_dir, out_dir, no_reformat)
diff --git a/test/svg/color.0.color0.svg b/test/svg/color.0.color0.svg
new file mode 100644
index 000000000..650dca898
--- /dev/null
+++ b/test/svg/color.0.color0.svg
@@ -0,0 +1,4 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="var(--color0, red)" />
+</svg>
diff --git a/test/svg/color.1.color1.svg b/test/svg/color.1.color1.svg
new file mode 100644
index 000000000..2858b35ca
--- /dev/null
+++ b/test/svg/color.1.color1.svg
@@ -0,0 +1,4 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="var(--color1, blue)" />
+</svg>
diff --git a/test/svg/color.2.foreground-solid.svg b/test/svg/color.2.foreground-solid.svg
new file mode 100644
index 000000000..cf77d65a6
--- /dev/null
+++ b/test/svg/color.2.foreground-solid.svg
@@ -0,0 +1,4 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="currentColor" />
+</svg>
diff --git a/test/svg/color.3.foreground-alpha.svg b/test/svg/color.3.foreground-alpha.svg
new file mode 100644
index 000000000..fa67d4929
--- /dev/null
+++ b/test/svg/color.3.foreground-alpha.svg
@@ -0,0 +1,4 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="currentColor" fill-opacity="0.5" />
+</svg>
diff --git a/test/svg/color.4.foreground-linear.svg b/test/svg/color.4.foreground-linear.svg
new file mode 100644
index 000000000..d2f8816c6
--- /dev/null
+++ b/test/svg/color.4.foreground-linear.svg
@@ -0,0 +1,10 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <linearGradient id="grad" x1="33%" x21="66%">
+ <stop offset="0%" stop-color="currentColor" stop-opacity="1" />
+ <stop offset="100%" stop-color="red" stop-opacity="1" />
+ </linearGradient>
+ </defs>
+ <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" />
+</svg>
+
diff --git a/test/svg/color.5.foreground-linear-alpha.svg b/test/svg/color.5.foreground-linear-alpha.svg
new file mode 100644
index 000000000..a3c453ad3
--- /dev/null
+++ b/test/svg/color.5.foreground-linear-alpha.svg
@@ -0,0 +1,10 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <linearGradient id="grad" x1="33%" x21="66%">
+ <stop offset="0%" stop-color="currentColor" stop-opacity="0.3" />
+ <stop offset="100%" stop-color="red" stop-opacity="0.3" />
+ </linearGradient>
+ </defs>
+ <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" />
+</svg>
+
diff --git a/test/svg/color.6.foreground-radial.svg b/test/svg/color.6.foreground-radial.svg
new file mode 100644
index 000000000..97622c2b4
--- /dev/null
+++ b/test/svg/color.6.foreground-radial.svg
@@ -0,0 +1,10 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <radialGradient id="grad" cx="50%" cy="50%"
+ fx="0.75" fy="0.35" r="0.5">
+ <stop offset="0%" stop-color="currentColor" stop-opacity="1" />
+ <stop offset="100%" stop-color="blue" stop-opacity="1" />
+ </radialGradient>
+ </defs>
+ <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" />
+</svg>
diff --git a/test/svg/color.7.foreground-radial-alpha.svg b/test/svg/color.7.foreground-radial-alpha.svg
new file mode 100644
index 000000000..76d6628e0
--- /dev/null
+++ b/test/svg/color.7.foreground-radial-alpha.svg
@@ -0,0 +1,10 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <radialGradient id="grad" cx="50%" cy="50%"
+ fx="0.75" fy="0.35" r="0.5">
+ <stop offset="0%" stop-color="currentColor" stop-opacity="0.5" />
+ <stop offset="100%" stop-color="blue" stop-opacity="0.5" />
+ </radialGradient>
+ </defs>
+ <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" />
+</svg>
diff --git a/test/svg/doc.0.viewBox1.svg b/test/svg/doc.0.viewBox1.svg
new file mode 100644
index 000000000..c1f55a4eb
--- /dev/null
+++ b/test/svg/doc.0.viewBox1.svg
@@ -0,0 +1,4 @@
+<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
+ <rect x="10" y="-90" width="80" height="80"
+ fill="none" stroke="black" stroke-width="10"/>
+</svg>
diff --git a/test/svg/doc.1.viewBox2.svg b/test/svg/doc.1.viewBox2.svg
new file mode 100644
index 000000000..b8f976ba9
--- /dev/null
+++ b/test/svg/doc.1.viewBox2.svg
@@ -0,0 +1,4 @@
+<svg viewBox="-5 -5 10 10" xmlns="http://www.w3.org/2000/svg">
+ <rect x="-4" y="-14" width="8" height="8"
+ fill="none" stroke="black" stroke-width="1"/>
+</svg>
diff --git a/test/svg/doc.2.image.svg b/test/svg/doc.2.image.svg
new file mode 100644
index 000000000..1d03842a9
--- /dev/null
+++ b/test/svg/doc.2.image.svg
@@ -0,0 +1,121 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <image x="0" y="-1000" width="1000" height="1000"
+ xlink:href="data:image/png;base64,
+iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9
+kT1Iw0AYht+m1opUHOwgopChOlkQFXXUKhShQqkVWnUwufQPmjQkKS6OgmvBwZ/FqoOLs64OroIg
++APi6OSk6CIlfpcUWsR4x3EP733vy913gFAvM9XsGANUzTJS8ZiYya6KwVd0YggBmtMSM/W5ZDIB
+z/F1Dx/f76I8y7vuz9Gj5EwG+ETiWaYbFvEG8dSmpXPeJw6zoqQQnxOPGnRB4keuyy6/cS44LPDM
+sJFOzROHicVCG8ttzIqGSjxJHFFUjfKFjMsK5y3OarnKmvfkLwzltJVlrtMaRByLWEISImRUUUIZ
+FqK0a6SYSNF5zMM/4PiT5JLJVQIjxwIqUCE5fvA/+N1bMz8x7iaFYkDgxbY/hoHgLtCo2fb3sW03
+TgD/M3CltfyVOjDzSXqtpUWOgN5t4OK6pcl7wOUO0P+kS4bkSH5aQj4PvJ/RN2WBvluge83tW/Mc
+pw9AmnqVuAEODoGRAmWve7y7q71v/9Y0+/cDaP1yo4gSHTAAAAAGYktHRAD/AP8A/6C9p5MAAAAJ
+cEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfmBh0FBzE5rnzLAAAAGXRFWHRDb21tZW50AENyZWF0
+ZWQgd2l0aCBHSU1QV4EOFwAAF45JREFUaN5NmnmPZOd13n/vdrdau6p6X2cjw5FIarMjAYmDwP7H
+Buz4K/ib8IMFQaAgtiVLoRRSociZIWc4Pb1Xda237vIu+eNWD91AoYHuu9R7luc85zlHfPyzvwxC
+CJRSzUdKpJAIKVBSIZVESoGUGqkkQggIASkE2miMiTGRQWmNkAqlNVobBMDmPgApwVmHrWu894QQ
+CCHgvcMHh6stdVVh6xpra5xzeO/xLry/NtBcj5AIIRFSEbzFe49+OIQQAgDnPSiBbL4KUki0Nmhj
+EFIhmz8jCGhtMFHzP6kNSjbPkVJuDNC88OGLSCnRujlYAELwBB/w3uOURWlFXSlUrTYHCVhrsdbi
+nYMQmpcTCMGDbyxklELnqxVZlhEnMe00RmtNXlT4zT1CiM2XUkitUUo1X5RAYwSNVM0hpJSNR1Tj
+GQDvHMH7H7wYxSitQIBznrquCD6g/A/etNbi6sYrVVUhpaSuKpxrjOGdJwgAj6Ixnp7f3xOcY7uX
+koiSSHq2tmIqJ5nmDgSEjSWEEO89h5CNbRrT/uAJuTm0kCBEY3sB3nmEkGjTeLDxkCd4R+0tbO5H
+GYRonqOsbV4QAhiNEDThJj3Ob8LNe4IQ6LquSSJBMb+DJEbLDqv5HEFgf2vAfSFwm9AQgBQCAc0D
+mtMhnGvCSza5JVXjPSEEMki8dwQNUor3BxZC4JxDSYXXAS003nlq6sZwm+u0VoSgYRMB3nu89yjv
+sbbJI2stuixLYi2JtCB4j/OerNXG2pp8MeNkZ4/7UlA4scmaTXw/eEgqpNKbsFIo80P4KaXe3+G9
+33jQN/GNQAiIohgjIkIIOGubCPAe4SRBBqTSGEBKiXNNoldVSV1VgMOHJo908BatBFpKUAofwPqA
+1IY4Sbi6vODw6JhZrcitINBY6n1ia4UypvGA1Jtc2RxISgQNmDjnmuOH5lCB0ACB0htLO5QySKUJ
+/gHRNogZNO1EESlQQuCQfPXqbYN4zuKcQ7MJF6M1QRkCAakU7U6XVtYijlMuLy94/PgJN+tAXoEy
+5j3SSalQ2qB0hNIKIR5gXDWhhAAhiIxBCEHw7j38eu+xwRMCTV7JxstJ6pBCYG1NL1KIakm5XiDi
+mKJyWA9pnJDna4Jv7tEASkmM1mBiRJSCVAQfEErT7Q+RAi4vLzk9OeWm1NRe8IDDSjfJ+YDryugm
+R4RAbpI2iAYctNIELwnBbzzUWDiEJokfwjGKElItSOqcYrHAC0Wr08V7qOoCrSDa1C4fAjiHbGqC
+IIkNWRqhdESSddAmoi4rAoJWp4fSEefn33O8FZHGGi3VxitgjEZrjRQCfIMkG5gjCFBKNcWMQBAC
+ROO5wMYAQqC1xhiDkpJRS7DFgipfESUt+oMRUZxS1RZb1yhtqF1A6wit9cPHgJBEJiJNIlZWEJuI
+yGjanS7tdpe6LljM5tzf3fP2u1f86NOf8tXFErEpeloJpGxCFATOe0QIiOAJtoFv5wLONcgFzWGt
+d3jvfvCcr9lSBevxFfm6Imv1iJIMtKGoAx5JCJbaB1br4n2RDSGgIxNTWY8yMVJKtjoJ66pExm28
+k2iTEJAcnD4ijiPOv39D+vVXPPvwYy6XnkBjTUkDpw+1QkqBtxYTxzjvCIALHufY5IoHIQk4rHfs
+dWKicsLlu7fErT7HHzwj7XSxtSXPS2qviPMlaE0R9HvkZINoWinF/XxJGhuEaSGATqqxviROeoQQ
+iGNDvfaYTTH7/uKSk0dPuL+eouOMdqeLtTVCgKstaZq8x3wdpyRJRgAm9xOyrIVUEhU30FyVOU92
+2qwuX3F3fU2vNyLt9DFCUeUlJmkTqIi1opUYpG8xWVmUVCA9nuY5WghBWVm8MqRJipMGIQVtbTDU
+xKJiPZ8xn9xxP5kwnU4pqpKXL1+xv3vI9WxJvbQkaUZQEYaAK0ustSzXOXHWwtY1rU6HNElZLleb
+QgrClfzouM/tyy8Zj8cMBiN2Dk+R0lB7CEGwXMyJsERRwBkJnR7VbIzRDe+rbQM6OooilFJcXFxx
+cBhhIkeBwtUOQk2IPMFbnHWUZUlVV3gfuLy+JW31SJUgVoJgK7TSIAVKR9wsl0Qm4ur8Lds7O8zr
+mrqucOucxbrEuprjYZtqUvLq5UtGox2ybg+TtUmzLs5DsVqQhhVSwMpKtDLkziCFRKkG/bRSeEB1
+Or3PlJJ0OxmDwQC3nFBbx83tFdI7itJSV5YgoaprDo+PMUazWq+pqpp22iJKE9I0Y11WGAkhOG5u
+b2lnGb1uC7xltcxZr5cc7QwZdlv0WgnVcsLk8px3Fxc8OjxEKUmcthju7KKlJNaANORlwNclJoq4
+mJcUVUUIDoJAiA2r9iFQWUdZOySO8WxJ4RaUZcVUgI5bmCxj2O3SHu7g6wrrHM55ptN7autpLZc4
+F9je2WXQHTCezEhjTb5eEBvJ6ekJ08USgsOohnvNbs4RtmBrsMUTLSmqnJ7uIao1dr0k6/YpdMTa
+KtK0xlaeiY02sKtwLsKHGuEE4NFFsabVarNcLvAIFkVBXlr29w4Y7WwTxTHWVSgpGN/cYG2FkIok
+a1FaT1Hm6EJTVo502aKqSlpJhNYSay11XXBzfc79dMn29pDx7B5XFWhfo2NDnKT84oMPmU/GCJ2Q
+z2csxzcgFT4I2tqx9BXnF+dcsEUAlIkxG1JceY+UBm1tTVmWFDZjPJujTIJdTFgs7jk6O6XdH7Cc
+jnn93bfkec5ytaSqa7r9PtoYBr0+Uilmy5wojhhu9XF1TUdq4iRBiYaEvru44uZyTRJFrFZLcCW9
+TpvgPOvlmuNnz6nLgmK+YD65Z7UsSA3IakUlYF44fGbQRqG02iBohSkjnKtRaZp99sBiy9rSymKq
+suTkyTP6gyHju1tmiyXOeW5ubwhAK2sgd3s0xDpHu92h1e5SVTVb3TbgWeRrILAzGpDnBWkSs9Vt
+s7e7w93dLVtbA2bTOVoKiqpECkEaa/qDIc7VrGdTyvUauxxj6zU+2yIn2XSfDTnVWiOlIASPare7
+nyVZhlaGTq+D95bKOgajHebzBXd3dzhXM53OqF2g3+txdnKM957T00ebqhozGu3gPThviYxmvV6j
+pWBvMCBqtYmiiEgrdGTYHY3w3lFXFVVVNdcK6G0N6Q62aPeGvLt4y+W7c/Ki4ODpc+5KSWFBbIio
+EHLDrmn6JJMkRElKlCbsbG/T7XTZPzxECFiuc4IUSKVBabZ3dzg+OsQGSZS2yIuSbn9IXVmGwx5P
+Hh1T1Y40S7m5uWY2ueObV9/y5ZdfIkTARDE+NN5vt9t89NGHZO02zjUE9Ysvv+Ty4gohAov5HCEV
+O8enTArPJK9/0BWspSwLrK0b5m4MstPpkmUtojgmzVJMknF0ckbtAsZE5HlBkIr9/X263S5eaNZF
+xf7+EU+fPuN+MmU8mbAzHNLLYqy1dNKMrW6XTq9HnMScHu3x6GiP5WKOdZ4oikizDneTGds7O7R7
+PfJ1gVaal6++ZTqbk3b7YAwrJ3l5s8CHhik4a7GuJnjXkM2HRi6K40ZiAawXDHf2sNbhbM1qtaLT
+6zEajUizlE6nizYR1lqKokAISVXkeG/xdUmxXnJ7e0O+XJKvC+I44c33b3BViatL5vMZL168Ynt3
+j9HuPt2tEVmnx8nJKTpJGe3to6RmOp1ikgQrJPOiJjIxQj60uQ42bLmRsDTKGLSta6q6ot3ukLZb
+dHpdrs/PcR463S7tTgcQZGnGzu4OSimODvaZzqbYOqfMFzw63CXSithEHIz6VFXByeE+OjKkUUwW
+KSIJ88kdKsroDwacX92ymM0xCsqypNVqcXV923AoJNu7e0ynC7q9PlcFSCdxoekilWp0MqObFpsK
+tHOOJIpx1pLECYvplFanRxtPVVbsbO8RfM1oNOLo6AgtYTmd0sliBr0OnVZCGmuKfM79dMwnHz1D
+6ojz80t6/S6nhzsIW6OVRMnAwc4A7xzfvXjBsN+j085wzrNeF3RpxIbZdMZZf8Dh8SnLdUmgBOFR
+SiLUxhNCoFQjFnqt0UI0SBBFjToopcboCGMUjx7v0e20ubg4Zzq+RVRrXr/6LWmy4os/X/Hhk0/4
++PlHDIcj7u6nvP7+nJ9+8hPSNKXX67EzHDRs4eaK1XJBEhsePz4CV/Hk9IDeYEQSRdxcXbHK16Ak
+dW0J3jOe3NHK2lzOVljnUdIgRGi4nFJoJRAhNAVSKdT27t5nAogjw2g0QiIpigJrLVGSkOc5q+k9
+j/e3+OJ3v+Vv/lPCzWSKefZjnjx9gp19QXvwjJNHH/DyxUuGo20CgeFwQDttMZ1O6PW7fPrpx+wP
+O9ze3fL5//0NxfI1l2+vyVpdnPfMZ3MGo22q2tJptdC60bEupjlq0wlKKfEERAhoJTfXNH2QfIAv
+V1u8tUgpKMuCyeSOf/vNv/DqxZ/5+U8/4Wd/8R/Z2TmmOxiSxA3XYfUVx/spn//bb1kUFqTi8uoa
+KTXdThcdR8RxzLOPfkTtIK+/ZpG9pvXjH/PX/+UJP3oy5nf/+hu0EkRJgrUehcRvZM77+YLKBYRq
+FEylFMIHQnCb6GlUmqZTFBJvLSF4rq6vWa6WpGnC3e01MlhOjo/wCFaV5We//Av+9E3Ojz95znH9
+Lfu7I5ZrwcvzObUXdPtbxGlCUa6Z3t/j6oqqsgx3D7k8/4aTk4R8PMZe/G9qVqTdbc4eP+H08WOU
+gHfnbxnfXHH+/Rtm0ynzvMR5j3WNfPSgkTVCh9wIhs3fVK/X/0wpiRABrRSj7R0m41v6vQ5PHj9i
+sViQr5ZU64LHHzxDygFvvr+hnQlurhf8+ncVl1c3fPyTT7k4/55ev4+taiIpMFGE94Hto2P+z7/+
+gZ09wVYn4Xh/i6S1x6//+2v+89/8A8YY0sjQ63RYrXLa7RadTod5aVk7gZCNpEQIKCXRSqE3B7G2
+xvmADsFD8EihKaoSISVFkXN48IgkTWi125y/u+T65o6vX7zi5z/5hJ//4u9YlTV//uYlMvwzs/mM
+u6tLkiQjzws0gdIYTBTT6kjy2ZRvX7/mxZuc58+7BCJqb/nrf/wn4jTi3ZvXVEWJc56j0xMuzs9Z
+LJa4oBGqoSONZB1QUqKVRCIJwRGC+He61kZSCc4RxRFPHp8RxxF7e3sEPLfXl1gXcM7xzavvOH93
+yUcf/5hPfvIxq7ImGR0ymy+5v5/T73fo9PtUtmKd50ghuXz3jmxrl6dnR3z46ackWcLNxQXfvXrF
+1cUllXXsDgc8+w8fkSQR88ktN+N76mxIFBncpv8RG91ZblRO7wJBuAbVet3+Z0IEyrJECMn+4RFn
+Z8csp2PiNGV7e4dBv88f/vA51zfXGK0RSuGC4upmzHg65+76mtV8yt7+AdujEaPBFrvbA9ZFRVVW
+XF9eUaA5e3TG3s6Ir776E19/+Sdurm/QStGKIp48e8bR6Qm2rpHB4XXE3Kn3Cv+DOmm0QiuJ2IjZ
+1jnqukInaUK318X7RiVZTO9ZzLpYH4iNYb1aoaKYf/jH/8YfP/+c8XiMMobHaUpeW6qywkSaODFs
+7++TKEkaa5TUdDpdhFTc3N0xnc1YLNd8/vvPeX1+zv3tDVIKep02R4f7HB4fsVrMqYqCTneLarwm
+ULyfADTyKygpwHmss43M5DzBe1S/3/vMe0ddlmgJVVXQ7/e5H485f/ManOPq6pLF7J7BcMTN7d2G
+ERumk3t6W0Nur67I87zRiyNDN0tot7usiop35++4ur7Z9Cwd2qkh2BKjFc+envH4yRO2Bn20aurG
+anbP/XTBi8tGO5Abyi5EIDbNEOlBuHbObaZeHrV/ePhZbCK0bhqUOIp+GKAEy2q15OzxI7Z3hjx9
++hQhIF/l1NY2Ek8cc3p2wu3NNUJp+r0erazFfD7j5nbMYj7F1o7jsxOkaITtar1CS8FgOKCVRiym
+93zxxy+Yjm9YLuZc3M6ZrJvZoPUO5y1aSiJj0FJhbd2M47x/fyAdRQajDc5BZAxGKxaLBUfHh1y+
+fc3Hz59zdnZGq52hpGRvf588X5NXnjgyPHp8hneOJ49OubtfcPntKxa3V9TWQoBur8tf/vJXKK1Z
+zCYs7u85ODig3+tw+uQxs8kYt7VFVRaslguKouY2t7iHISgerRWYhkI9iN1CiM1wtMkVaXREp9sh
+jhPanTZJHINzWOs4ODjg6xcv+d3vf0++LqitByHobg1ZFyWrPOf25oadnW3OTo+5f/eKePySX23V
+/LJToe6+w5YF7W6HLEtIohjrPL1ej0cffIiR4n3NODl7RJpmZN0t8spuBPJmSqaEBNcMiKT8gcI3
+478GftXJ6elnSknW+Yq6rOj1+qzzFdZ7nK3ZHvRYTO+pqpI46+AC9HoDDvZ2kcEzm004PNhn5/CY
+k8dP+dPXrxFVSStOWe8+47/+3d/T63W5fvuWm5s78vUaISVZq0UUZ6yLNbfv3vLm9UuMifnucsLa
+gVSNOK2UQmvZKIuyGaIGAt55bO3eq5bq8eMnn9m62kyTPHe3N0RRBELSbreROuLs7BGd7oDVaoXz
+8MEHTynWCyKt2R5uoZUhTlNaWYuqrPgfv/4XcpHwq7/9ew729xChJk2a4dDh/jZbo23m8zlVsWI+
+uSafT7BVxar03C1LShcQUv4wVRYCrQ1s2G7wnrq2m6ruEYAOeKRUuFDhnKPVbuGcY2d/n939fYSz
+TOcL3nz7DfvHZ5w83uZufM9gMMTVNdY6TJKwWMwp8jX9wRbBRIyefYi3FdZVYD1vX7/BRDFJp0Or
+04Zqyer+gmpd4p2nN9xneTenqCZIodHGUJZlM3uUBu9BCI9sxi5oJfFaI72nrmt0CAJJM7fwQJRm
+nD56RL5cYmtLGhmyWNLfek6VL1iMr5lNbhlujzBa0e1uka/XBO+ZTWfc3tyg45i6toxvr8niBjK7
+w22wBUorFtNbynyBy+e0sgyRDKhEyvLdmEgrPArBhpV7h4p0M9YDlHgYk0ucD+ACwjnUzu7OZ943
+o6v21hbBB6hrBtu7fP2nP5K1OxweHWNEYDgaUeVLWt0es8mEqizJ12u8h/HknqqquHz7lt3hgKIq
+sSE0CocQ4GuSLGG9mGPLHOMK2qMDkt4eXqcsCsd3r99Q1jUog6dpgR+2JYw2TY5s9i6stbjNFNpa
+i272TmC0vcvt1SXaaOh2eP3i//Hs+SeMhkMWyzXbwz62XLF3csZqsaDXbqG0Il8tGK8WoGOG2/v8
+6q/+CrynnWUgAnVdcXf9PVmkWY0d2/tHFIslRC2K2pFkEeuipKwdelO1MXKjmDSVW0uJ180YPNCI
+ELXzVPUPhVEmSUwcxVycv6VYr6mrmqoseP7JT7Flwbu355R1zbffvUHomLIsieMILQWtWHOwM+J4
+u88gctjVlPl8jtQKExsIjvViiqtKymJN1t3CASbbwqkEGyR5UZF1+iAVi/EYpTVJ2oJN57dpmpol
+hc0GxkPteJjdCwK6KBqpppVlrJYrnK3ZPzri/O05CDg6Pubi7ffs7x9QW0d+e0cnizGy2R+x64Jg
+SzpZRtbrsrawXkwpVjNsXSG8RzbbL1TFGiEVrd4QW1ekWZegYmrrWS3mrNc5cdqC4DcTY0WSpiht
+QP6wnPPweb+AAOj5bEaaxqxWK+LY0N3q8+LrF0Ra8+jJI6aTCe1WxjpfkqZHpFpT5Qv6wz5VndNO
+U0wWEyUt4labWDQvtc7jfcDXFVKAwqG0bnRbExGlbWSUEIKgrNbcXl7Q6XbJPWBrImMgTZteXan3
+7e/Dz4PqGAL4EJp+xDmPNhqtIxbTBd5Zkm6LgODq4pzR7gGtVsY//6//yc9+8ilGSWrv6PSGSKVI
+kpg0zVBJRqpjXAhUdY0gEKxGbQQ1rTVJ1kLHMVIn1M7hPdzfj6mLHCEF1joiqXDOvl9KeL/+sYFe
+ABFoFnLqBr61c5bgJQhDZWvy5ZI0idneO+D1qxfsHx5z/uY7fvqLX9BODJfv3rG3PYTQwkQpcWQQ
+WmPiDGUSlNZY7xuq4z1qM3qWWiHY/JYaKSTW1qzzkuVsSl0WdLp98Ip8k8RShPdKifeBsBEa2Czd
+BNcsrHnv+f9Qc51Rfhz5VAAAAABJRU5ErkJggg=="/>
+</svg>
diff --git a/test/svg/doc.3.image-transform.svg b/test/svg/doc.3.image-transform.svg
new file mode 100644
index 000000000..90e5ecb1a
--- /dev/null
+++ b/test/svg/doc.3.image-transform.svg
@@ -0,0 +1,122 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <image x="0" y="-1000" width="1000" height="1000"
+ transform="scale(0.5) rotate(-45),translate(800,500)"
+ xlink:href="data:image/png;base64,
+iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9
+kT1Iw0AYht+m1opUHOwgopChOlkQFXXUKhShQqkVWnUwufQPmjQkKS6OgmvBwZ/FqoOLs64OroIg
++APi6OSk6CIlfpcUWsR4x3EP733vy913gFAvM9XsGANUzTJS8ZiYya6KwVd0YggBmtMSM/W5ZDIB
+z/F1Dx/f76I8y7vuz9Gj5EwG+ETiWaYbFvEG8dSmpXPeJw6zoqQQnxOPGnRB4keuyy6/cS44LPDM
+sJFOzROHicVCG8ttzIqGSjxJHFFUjfKFjMsK5y3OarnKmvfkLwzltJVlrtMaRByLWEISImRUUUIZ
+FqK0a6SYSNF5zMM/4PiT5JLJVQIjxwIqUCE5fvA/+N1bMz8x7iaFYkDgxbY/hoHgLtCo2fb3sW03
+TgD/M3CltfyVOjDzSXqtpUWOgN5t4OK6pcl7wOUO0P+kS4bkSH5aQj4PvJ/RN2WBvluge83tW/Mc
+pw9AmnqVuAEODoGRAmWve7y7q71v/9Y0+/cDaP1yo4gSHTAAAAAGYktHRAD/AP8A/6C9p5MAAAAJ
+cEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfmBh0FBzE5rnzLAAAAGXRFWHRDb21tZW50AENyZWF0
+ZWQgd2l0aCBHSU1QV4EOFwAAF45JREFUaN5NmnmPZOd13n/vdrdau6p6X2cjw5FIarMjAYmDwP7H
+Buz4K/ib8IMFQaAgtiVLoRRSociZIWc4Pb1Xda237vIu+eNWD91AoYHuu9R7luc85zlHfPyzvwxC
+CJRSzUdKpJAIKVBSIZVESoGUGqkkQggIASkE2miMiTGRQWmNkAqlNVobBMDmPgApwVmHrWu894QQ
+CCHgvcMHh6stdVVh6xpra5xzeO/xLry/NtBcj5AIIRFSEbzFe49+OIQQAgDnPSiBbL4KUki0Nmhj
+EFIhmz8jCGhtMFHzP6kNSjbPkVJuDNC88OGLSCnRujlYAELwBB/w3uOURWlFXSlUrTYHCVhrsdbi
+nYMQmpcTCMGDbyxklELnqxVZlhEnMe00RmtNXlT4zT1CiM2XUkitUUo1X5RAYwSNVM0hpJSNR1Tj
+GQDvHMH7H7wYxSitQIBznrquCD6g/A/etNbi6sYrVVUhpaSuKpxrjOGdJwgAj6Ixnp7f3xOcY7uX
+koiSSHq2tmIqJ5nmDgSEjSWEEO89h5CNbRrT/uAJuTm0kCBEY3sB3nmEkGjTeLDxkCd4R+0tbO5H
+GYRonqOsbV4QAhiNEDThJj3Ob8LNe4IQ6LquSSJBMb+DJEbLDqv5HEFgf2vAfSFwm9AQgBQCAc0D
+mtMhnGvCSza5JVXjPSEEMki8dwQNUor3BxZC4JxDSYXXAS003nlq6sZwm+u0VoSgYRMB3nu89yjv
+sbbJI2stuixLYi2JtCB4j/OerNXG2pp8MeNkZ4/7UlA4scmaTXw/eEgqpNKbsFIo80P4KaXe3+G9
+33jQN/GNQAiIohgjIkIIOGubCPAe4SRBBqTSGEBKiXNNoldVSV1VgMOHJo908BatBFpKUAofwPqA
+1IY4Sbi6vODw6JhZrcitINBY6n1ia4UypvGA1Jtc2RxISgQNmDjnmuOH5lCB0ACB0htLO5QySKUJ
+/gHRNogZNO1EESlQQuCQfPXqbYN4zuKcQ7MJF6M1QRkCAakU7U6XVtYijlMuLy94/PgJN+tAXoEy
+5j3SSalQ2qB0hNIKIR5gXDWhhAAhiIxBCEHw7j38eu+xwRMCTV7JxstJ6pBCYG1NL1KIakm5XiDi
+mKJyWA9pnJDna4Jv7tEASkmM1mBiRJSCVAQfEErT7Q+RAi4vLzk9OeWm1NRe8IDDSjfJ+YDryugm
+R4RAbpI2iAYctNIELwnBbzzUWDiEJokfwjGKElItSOqcYrHAC0Wr08V7qOoCrSDa1C4fAjiHbGqC
+IIkNWRqhdESSddAmoi4rAoJWp4fSEefn33O8FZHGGi3VxitgjEZrjRQCfIMkG5gjCFBKNcWMQBAC
+ROO5wMYAQqC1xhiDkpJRS7DFgipfESUt+oMRUZxS1RZb1yhtqF1A6wit9cPHgJBEJiJNIlZWEJuI
+yGjanS7tdpe6LljM5tzf3fP2u1f86NOf8tXFErEpeloJpGxCFATOe0QIiOAJtoFv5wLONcgFzWGt
+d3jvfvCcr9lSBevxFfm6Imv1iJIMtKGoAx5JCJbaB1br4n2RDSGgIxNTWY8yMVJKtjoJ66pExm28
+k2iTEJAcnD4ijiPOv39D+vVXPPvwYy6XnkBjTUkDpw+1QkqBtxYTxzjvCIALHufY5IoHIQk4rHfs
+dWKicsLlu7fErT7HHzwj7XSxtSXPS2qviPMlaE0R9HvkZINoWinF/XxJGhuEaSGATqqxviROeoQQ
+iGNDvfaYTTH7/uKSk0dPuL+eouOMdqeLtTVCgKstaZq8x3wdpyRJRgAm9xOyrIVUEhU30FyVOU92
+2qwuX3F3fU2vNyLt9DFCUeUlJmkTqIi1opUYpG8xWVmUVCA9nuY5WghBWVm8MqRJipMGIQVtbTDU
+xKJiPZ8xn9xxP5kwnU4pqpKXL1+xv3vI9WxJvbQkaUZQEYaAK0ustSzXOXHWwtY1rU6HNElZLleb
+QgrClfzouM/tyy8Zj8cMBiN2Dk+R0lB7CEGwXMyJsERRwBkJnR7VbIzRDe+rbQM6OooilFJcXFxx
+cBhhIkeBwtUOQk2IPMFbnHWUZUlVV3gfuLy+JW31SJUgVoJgK7TSIAVKR9wsl0Qm4ur8Lds7O8zr
+mrqucOucxbrEuprjYZtqUvLq5UtGox2ybg+TtUmzLs5DsVqQhhVSwMpKtDLkziCFRKkG/bRSeEB1
+Or3PlJJ0OxmDwQC3nFBbx83tFdI7itJSV5YgoaprDo+PMUazWq+pqpp22iJKE9I0Y11WGAkhOG5u
+b2lnGb1uC7xltcxZr5cc7QwZdlv0WgnVcsLk8px3Fxc8OjxEKUmcthju7KKlJNaANORlwNclJoq4
+mJcUVUUIDoJAiA2r9iFQWUdZOySO8WxJ4RaUZcVUgI5bmCxj2O3SHu7g6wrrHM55ptN7autpLZc4
+F9je2WXQHTCezEhjTb5eEBvJ6ekJ08USgsOohnvNbs4RtmBrsMUTLSmqnJ7uIao1dr0k6/YpdMTa
+KtK0xlaeiY02sKtwLsKHGuEE4NFFsabVarNcLvAIFkVBXlr29w4Y7WwTxTHWVSgpGN/cYG2FkIok
+a1FaT1Hm6EJTVo502aKqSlpJhNYSay11XXBzfc79dMn29pDx7B5XFWhfo2NDnKT84oMPmU/GCJ2Q
+z2csxzcgFT4I2tqx9BXnF+dcsEUAlIkxG1JceY+UBm1tTVmWFDZjPJujTIJdTFgs7jk6O6XdH7Cc
+jnn93bfkec5ytaSqa7r9PtoYBr0+Uilmy5wojhhu9XF1TUdq4iRBiYaEvru44uZyTRJFrFZLcCW9
+TpvgPOvlmuNnz6nLgmK+YD65Z7UsSA3IakUlYF44fGbQRqG02iBohSkjnKtRaZp99sBiy9rSymKq
+suTkyTP6gyHju1tmiyXOeW5ubwhAK2sgd3s0xDpHu92h1e5SVTVb3TbgWeRrILAzGpDnBWkSs9Vt
+s7e7w93dLVtbA2bTOVoKiqpECkEaa/qDIc7VrGdTyvUauxxj6zU+2yIn2XSfDTnVWiOlIASPare7
+nyVZhlaGTq+D95bKOgajHebzBXd3dzhXM53OqF2g3+txdnKM957T00ebqhozGu3gPThviYxmvV6j
+pWBvMCBqtYmiiEgrdGTYHY3w3lFXFVVVNdcK6G0N6Q62aPeGvLt4y+W7c/Ki4ODpc+5KSWFBbIio
+EHLDrmn6JJMkRElKlCbsbG/T7XTZPzxECFiuc4IUSKVBabZ3dzg+OsQGSZS2yIuSbn9IXVmGwx5P
+Hh1T1Y40S7m5uWY2ueObV9/y5ZdfIkTARDE+NN5vt9t89NGHZO02zjUE9Ysvv+Ty4gohAov5HCEV
+O8enTArPJK9/0BWspSwLrK0b5m4MstPpkmUtojgmzVJMknF0ckbtAsZE5HlBkIr9/X263S5eaNZF
+xf7+EU+fPuN+MmU8mbAzHNLLYqy1dNKMrW6XTq9HnMScHu3x6GiP5WKOdZ4oikizDneTGds7O7R7
+PfJ1gVaal6++ZTqbk3b7YAwrJ3l5s8CHhik4a7GuJnjXkM2HRi6K40ZiAawXDHf2sNbhbM1qtaLT
+6zEajUizlE6nizYR1lqKokAISVXkeG/xdUmxXnJ7e0O+XJKvC+I44c33b3BViatL5vMZL168Ynt3
+j9HuPt2tEVmnx8nJKTpJGe3to6RmOp1ikgQrJPOiJjIxQj60uQ42bLmRsDTKGLSta6q6ot3ukLZb
+dHpdrs/PcR463S7tTgcQZGnGzu4OSimODvaZzqbYOqfMFzw63CXSithEHIz6VFXByeE+OjKkUUwW
+KSIJ88kdKsroDwacX92ymM0xCsqypNVqcXV923AoJNu7e0ynC7q9PlcFSCdxoekilWp0MqObFpsK
+tHOOJIpx1pLECYvplFanRxtPVVbsbO8RfM1oNOLo6AgtYTmd0sliBr0OnVZCGmuKfM79dMwnHz1D
+6ojz80t6/S6nhzsIW6OVRMnAwc4A7xzfvXjBsN+j085wzrNeF3RpxIbZdMZZf8Dh8SnLdUmgBOFR
+SiLUxhNCoFQjFnqt0UI0SBBFjToopcboCGMUjx7v0e20ubg4Zzq+RVRrXr/6LWmy4os/X/Hhk0/4
++PlHDIcj7u6nvP7+nJ9+8hPSNKXX67EzHDRs4eaK1XJBEhsePz4CV/Hk9IDeYEQSRdxcXbHK16Ak
+dW0J3jOe3NHK2lzOVljnUdIgRGi4nFJoJRAhNAVSKdT27t5nAogjw2g0QiIpigJrLVGSkOc5q+k9
+j/e3+OJ3v+Vv/lPCzWSKefZjnjx9gp19QXvwjJNHH/DyxUuGo20CgeFwQDttMZ1O6PW7fPrpx+wP
+O9ze3fL5//0NxfI1l2+vyVpdnPfMZ3MGo22q2tJptdC60bEupjlq0wlKKfEERAhoJTfXNH2QfIAv
+V1u8tUgpKMuCyeSOf/vNv/DqxZ/5+U8/4Wd/8R/Z2TmmOxiSxA3XYfUVx/spn//bb1kUFqTi8uoa
+KTXdThcdR8RxzLOPfkTtIK+/ZpG9pvXjH/PX/+UJP3oy5nf/+hu0EkRJgrUehcRvZM77+YLKBYRq
+FEylFMIHQnCb6GlUmqZTFBJvLSF4rq6vWa6WpGnC3e01MlhOjo/wCFaV5We//Av+9E3Ojz95znH9
+Lfu7I5ZrwcvzObUXdPtbxGlCUa6Z3t/j6oqqsgx3D7k8/4aTk4R8PMZe/G9qVqTdbc4eP+H08WOU
+gHfnbxnfXHH+/Rtm0ynzvMR5j3WNfPSgkTVCh9wIhs3fVK/X/0wpiRABrRSj7R0m41v6vQ5PHj9i
+sViQr5ZU64LHHzxDygFvvr+hnQlurhf8+ncVl1c3fPyTT7k4/55ev4+taiIpMFGE94Hto2P+z7/+
+gZ09wVYn4Xh/i6S1x6//+2v+89/8A8YY0sjQ63RYrXLa7RadTod5aVk7gZCNpEQIKCXRSqE3B7G2
+xvmADsFD8EihKaoSISVFkXN48IgkTWi125y/u+T65o6vX7zi5z/5hJ//4u9YlTV//uYlMvwzs/mM
+u6tLkiQjzws0gdIYTBTT6kjy2ZRvX7/mxZuc58+7BCJqb/nrf/wn4jTi3ZvXVEWJc56j0xMuzs9Z
+LJa4oBGqoSONZB1QUqKVRCIJwRGC+He61kZSCc4RxRFPHp8RxxF7e3sEPLfXl1gXcM7xzavvOH93
+yUcf/5hPfvIxq7ImGR0ymy+5v5/T73fo9PtUtmKd50ghuXz3jmxrl6dnR3z46ackWcLNxQXfvXrF
+1cUllXXsDgc8+w8fkSQR88ktN+N76mxIFBncpv8RG91ZblRO7wJBuAbVet3+Z0IEyrJECMn+4RFn
+Z8csp2PiNGV7e4dBv88f/vA51zfXGK0RSuGC4upmzHg65+76mtV8yt7+AdujEaPBFrvbA9ZFRVVW
+XF9eUaA5e3TG3s6Ir776E19/+Sdurm/QStGKIp48e8bR6Qm2rpHB4XXE3Kn3Cv+DOmm0QiuJ2IjZ
+1jnqukInaUK318X7RiVZTO9ZzLpYH4iNYb1aoaKYf/jH/8YfP/+c8XiMMobHaUpeW6qywkSaODFs
+7++TKEkaa5TUdDpdhFTc3N0xnc1YLNd8/vvPeX1+zv3tDVIKep02R4f7HB4fsVrMqYqCTneLarwm
+ULyfADTyKygpwHmss43M5DzBe1S/3/vMe0ddlmgJVVXQ7/e5H485f/ManOPq6pLF7J7BcMTN7d2G
+ERumk3t6W0Nur67I87zRiyNDN0tot7usiop35++4ur7Z9Cwd2qkh2BKjFc+envH4yRO2Bn20aurG
+anbP/XTBi8tGO5Abyi5EIDbNEOlBuHbObaZeHrV/ePhZbCK0bhqUOIp+GKAEy2q15OzxI7Z3hjx9
++hQhIF/l1NY2Ek8cc3p2wu3NNUJp+r0erazFfD7j5nbMYj7F1o7jsxOkaITtar1CS8FgOKCVRiym
+93zxxy+Yjm9YLuZc3M6ZrJvZoPUO5y1aSiJj0FJhbd2M47x/fyAdRQajDc5BZAxGKxaLBUfHh1y+
+fc3Hz59zdnZGq52hpGRvf588X5NXnjgyPHp8hneOJ49OubtfcPntKxa3V9TWQoBur8tf/vJXKK1Z
+zCYs7u85ODig3+tw+uQxs8kYt7VFVRaslguKouY2t7iHISgerRWYhkI9iN1CiM1wtMkVaXREp9sh
+jhPanTZJHINzWOs4ODjg6xcv+d3vf0++LqitByHobg1ZFyWrPOf25oadnW3OTo+5f/eKePySX23V
+/LJToe6+w5YF7W6HLEtIohjrPL1ej0cffIiR4n3NODl7RJpmZN0t8spuBPJmSqaEBNcMiKT8gcI3
+478GftXJ6elnSknW+Yq6rOj1+qzzFdZ7nK3ZHvRYTO+pqpI46+AC9HoDDvZ2kcEzm004PNhn5/CY
+k8dP+dPXrxFVSStOWe8+47/+3d/T63W5fvuWm5s78vUaISVZq0UUZ6yLNbfv3vLm9UuMifnucsLa
+gVSNOK2UQmvZKIuyGaIGAt55bO3eq5bq8eMnn9m62kyTPHe3N0RRBELSbreROuLs7BGd7oDVaoXz
+8MEHTynWCyKt2R5uoZUhTlNaWYuqrPgfv/4XcpHwq7/9ew729xChJk2a4dDh/jZbo23m8zlVsWI+
+uSafT7BVxar03C1LShcQUv4wVRYCrQ1s2G7wnrq2m6ruEYAOeKRUuFDhnKPVbuGcY2d/n939fYSz
+TOcL3nz7DfvHZ5w83uZufM9gMMTVNdY6TJKwWMwp8jX9wRbBRIyefYi3FdZVYD1vX7/BRDFJp0Or
+04Zqyer+gmpd4p2nN9xneTenqCZIodHGUJZlM3uUBu9BCI9sxi5oJfFaI72nrmt0CAJJM7fwQJRm
+nD56RL5cYmtLGhmyWNLfek6VL1iMr5lNbhlujzBa0e1uka/XBO+ZTWfc3tyg45i6toxvr8niBjK7
+w22wBUorFtNbynyBy+e0sgyRDKhEyvLdmEgrPArBhpV7h4p0M9YDlHgYk0ucD+ACwjnUzu7OZ943
+o6v21hbBB6hrBtu7fP2nP5K1OxweHWNEYDgaUeVLWt0es8mEqizJ12u8h/HknqqquHz7lt3hgKIq
+sSE0CocQ4GuSLGG9mGPLHOMK2qMDkt4eXqcsCsd3r99Q1jUog6dpgR+2JYw2TY5s9i6stbjNFNpa
+i272TmC0vcvt1SXaaOh2eP3i//Hs+SeMhkMWyzXbwz62XLF3csZqsaDXbqG0Il8tGK8WoGOG2/v8
+6q/+CrynnWUgAnVdcXf9PVmkWY0d2/tHFIslRC2K2pFkEeuipKwdelO1MXKjmDSVW0uJ180YPNCI
+ELXzVPUPhVEmSUwcxVycv6VYr6mrmqoseP7JT7Flwbu355R1zbffvUHomLIsieMILQWtWHOwM+J4
+u88gctjVlPl8jtQKExsIjvViiqtKymJN1t3CASbbwqkEGyR5UZF1+iAVi/EYpTVJ2oJN57dpmpol
+hc0GxkPteJjdCwK6KBqpppVlrJYrnK3ZPzri/O05CDg6Pubi7ffs7x9QW0d+e0cnizGy2R+x64Jg
+SzpZRtbrsrawXkwpVjNsXSG8RzbbL1TFGiEVrd4QW1ekWZegYmrrWS3mrNc5cdqC4DcTY0WSpiht
+QP6wnPPweb+AAOj5bEaaxqxWK+LY0N3q8+LrF0Ra8+jJI6aTCe1WxjpfkqZHpFpT5Qv6wz5VndNO
+U0wWEyUt4labWDQvtc7jfcDXFVKAwqG0bnRbExGlbWSUEIKgrNbcXl7Q6XbJPWBrImMgTZteXan3
+7e/Dz4PqGAL4EJp+xDmPNhqtIxbTBd5Zkm6LgODq4pzR7gGtVsY//6//yc9+8ilGSWrv6PSGSKVI
+kpg0zVBJRqpjXAhUdY0gEKxGbQQ1rTVJ1kLHMVIn1M7hPdzfj6mLHCEF1joiqXDOvl9KeL/+sYFe
+ABFoFnLqBr61c5bgJQhDZWvy5ZI0idneO+D1qxfsHx5z/uY7fvqLX9BODJfv3rG3PYTQwkQpcWQQ
+WmPiDGUSlNZY7xuq4z1qM3qWWiHY/JYaKSTW1qzzkuVsSl0WdLp98Ip8k8RShPdKifeBsBEa2Czd
+BNcsrHnv+f9Qc51Rfhz5VAAAAABJRU5ErkJggg=="/>
+</svg>
diff --git a/test/svg/doc.4.clip-user.svg b/test/svg/doc.4.clip-user.svg
new file mode 100644
index 000000000..26cdd818a
--- /dev/null
+++ b/test/svg/doc.4.clip-user.svg
@@ -0,0 +1,9 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1000" height="1000">
+ <clipPath id="clip" clipPathUnits="userSpaceOnUse" >
+ <circle cx="500" cy="-500" r="400" />
+ </clipPath>
+
+ <rect x="100" y="-900" width="800" height="800"
+ stroke="green" stroke-width="100"
+ clip-path="url(#clip)" />
+</svg>
diff --git a/test/svg/doc.5.clip-object.svg b/test/svg/doc.5.clip-object.svg
new file mode 100644
index 000000000..732911590
--- /dev/null
+++ b/test/svg/doc.5.clip-object.svg
@@ -0,0 +1,10 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000">
+ <clipPath id="clip" clipPathUnits="objectBoundingBox">
+ <circle cx=".5" cy=".5" r=".5" />
+ </clipPath>
+
+ <rect x="100" y="-900" width="800" height="800"
+ stroke="green" stroke-width="100"
+ clip-path="url(#clip)" />
+
+</svg>
diff --git a/test/svg/doc.6.clip-user2.svg b/test/svg/doc.6.clip-user2.svg
new file mode 100644
index 000000000..a68c1c42f
--- /dev/null
+++ b/test/svg/doc.6.clip-user2.svg
@@ -0,0 +1,10 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1000" height="1000">
+ <clipPath id="clip" clipPathUnits="userSpaceOnUse" >
+ <circle cx="500" cy="-500" r="400" />
+ <rect x="100" y="-900" width="800" height="400"/>
+ </clipPath>
+
+ <rect x="100" y="-900" width="800" height="800"
+ stroke="green" stroke-width="100"
+ clip-path="url(#clip)" />
+</svg>
diff --git a/test/svg/doc.7.clip-object2.svg b/test/svg/doc.7.clip-object2.svg
new file mode 100644
index 000000000..f5c153dd1
--- /dev/null
+++ b/test/svg/doc.7.clip-object2.svg
@@ -0,0 +1,11 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000">
+ <clipPath id="clip" clipPathUnits="objectBoundingBox">
+ <circle cx=".5" cy=".5" r=".5" />
+ <rect x="0" y="0" width="1" height="0.5"/>
+ </clipPath>
+
+ <rect x="100" y="-900" width="800" height="800"
+ stroke="green" stroke-width="100"
+ clip-path="url(#clip)" />
+
+</svg>
diff --git a/test/svg/doc.8.clip-user3.svg b/test/svg/doc.8.clip-user3.svg
new file mode 100644
index 000000000..8ff61d593
--- /dev/null
+++ b/test/svg/doc.8.clip-user3.svg
@@ -0,0 +1,15 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="1000" height="1000">
+ <clipPath id="clip" clipPathUnits="userSpaceOnUse" >
+ <circle cx="500" cy="-500" r="400" />
+ </clipPath>
+
+ <clipPath id="clip2" clipPathUnits="userSpaceOnUse" >
+ <rect x="100" y="-900" width="800" height="400"/>
+ </clipPath>
+
+ <g clip-path="url(#clip)">
+ <rect x="100" y="-900" width="800" height="800"
+ stroke="green" stroke-width="100"
+ clip-path="url(#clip2)" />
+ </g>
+</svg>
diff --git a/test/svg/doc.9.clip-object3.svg b/test/svg/doc.9.clip-object3.svg
new file mode 100644
index 000000000..b291df79f
--- /dev/null
+++ b/test/svg/doc.9.clip-object3.svg
@@ -0,0 +1,15 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000">
+ <clipPath id="clip" clipPathUnits="objectBoundingBox">
+ <circle cx=".5" cy=".5" r=".5" />
+ </clipPath>
+
+ <clipPath id="clip2" clipPathUnits="objectBoundingBox">
+ <rect x="0" y="0" width="1" height="0.5"/>
+ </clipPath>
+
+ <g clip-path="url(#clip)">
+ <rect x="100" y="-900" width="800" height="800"
+ stroke="green" stroke-width="100"
+ clip-path="url(#clip2)" />
+ </g>
+</svg>
diff --git a/test/svg/doc.A.g.svg b/test/svg/doc.A.g.svg
new file mode 100644
index 000000000..bdaade725
--- /dev/null
+++ b/test/svg/doc.A.g.svg
@@ -0,0 +1,14 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink" >
+ <defs>
+ <circle id="circle"
+ cx="0" cy="0" r="250" />
+ </defs>
+
+ <g opacity="0.5">
+ <use xlink:href="#circle" x="330" y="-500"
+ fill="red" />
+ <use xlink:href="#circle" x="670" y="-500"
+ fill="green" />
+ </g>
+</svg>
diff --git a/test/svg/fill.0.name.svg b/test/svg/fill.0.name.svg
new file mode 100644
index 000000000..e377b8827
--- /dev/null
+++ b/test/svg/fill.0.name.svg
@@ -0,0 +1,4 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="indigo" />
+</svg>
diff --git a/test/svg/fill.1.hex6.svg b/test/svg/fill.1.hex6.svg
new file mode 100644
index 000000000..04759d78a
--- /dev/null
+++ b/test/svg/fill.1.hex6.svg
@@ -0,0 +1,4 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="#AA55AA" />
+</svg>
diff --git a/test/svg/fill.2.hex3.svg b/test/svg/fill.2.hex3.svg
new file mode 100644
index 000000000..9f9bce580
--- /dev/null
+++ b/test/svg/fill.2.hex3.svg
@@ -0,0 +1,4 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="#A5A" />
+</svg>
diff --git a/test/svg/fill.3.rgb.svg b/test/svg/fill.3.rgb.svg
new file mode 100644
index 000000000..c18b03bb5
--- /dev/null
+++ b/test/svg/fill.3.rgb.svg
@@ -0,0 +1,4 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="rgb (75, 0 , 130)" />
+</svg>
diff --git a/test/svg/fill.4.current-color.svg b/test/svg/fill.4.current-color.svg
new file mode 100644
index 000000000..cf77d65a6
--- /dev/null
+++ b/test/svg/fill.4.current-color.svg
@@ -0,0 +1,4 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="currentColor" />
+</svg>
diff --git a/test/svg/fill.5.palette.svg b/test/svg/fill.5.palette.svg
new file mode 100644
index 000000000..53ea97512
--- /dev/null
+++ b/test/svg/fill.5.palette.svg
@@ -0,0 +1,4 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="var(--color1, red)" />
+</svg>
diff --git a/test/svg/fill.6.opacity.svg b/test/svg/fill.6.opacity.svg
new file mode 100644
index 000000000..59b4eb41f
--- /dev/null
+++ b/test/svg/fill.6.opacity.svg
@@ -0,0 +1,4 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"
+ fill="magenta" fill-opacity="0.5" />
+</svg>
diff --git a/test/svg/fill.7.color.svg b/test/svg/fill.7.color.svg
new file mode 100644
index 000000000..745b2e881
--- /dev/null
+++ b/test/svg/fill.7.color.svg
@@ -0,0 +1,5 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ color="green" >
+ <rect x="100" y="-750" width="800" height="500"
+ fill="currentColor" />
+</svg>
diff --git a/test/svg/fill.8.rule.svg b/test/svg/fill.8.rule.svg
new file mode 100644
index 000000000..366ff6760
--- /dev/null
+++ b/test/svg/fill.8.rule.svg
@@ -0,0 +1,8 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <g transform="scale(5,5) translate(0,-150)">
+ <polygon fill-rule="nonzero"
+ points="50,0 21,90 98,35 2,35 79,90"/>
+ <polygon fill-rule="evenodd"
+ points="150,0 121,90 198,35 102,35 179,90"/>
+ </g>
+</svg>
diff --git a/test/svg/fuzzer/README b/test/svg/fuzzer/README
new file mode 100644
index 000000000..4bb8d9654
--- /dev/null
+++ b/test/svg/fuzzer/README
@@ -0,0 +1,19 @@
+libFuzzer based fuzzing for cairo-svg-glyph-render.c
+====================================================
+
+Build
+-----
+CC=clang CFLAGS="-DDEBUG_SVG_RENDER -g -fsanitize=fuzzer-no-link,address" meson -Db_lundef=false bld-fuzzer
+ninja -C bld-fuzzer
+
+
+Test
+----
+ ./bld-fuzzer/test/svg/fuzzer/svg-render-fuzzer <CORPUS DIR>
+
+where <CORPUS DIR> is a directory containing SVG files.
+
+If the fuzzer crashes, a crash-* file will be written. Run the
+fuzzer with the crash file to reproduce the crash.
+
+ ./bld-fuzzer/test/svg/fuzzer/svg-render-fuzzer <crash-file>
diff --git a/test/svg/fuzzer/meson.build b/test/svg/fuzzer/meson.build
new file mode 100644
index 000000000..3e8f7b943
--- /dev/null
+++ b/test/svg/fuzzer/meson.build
@@ -0,0 +1,14 @@
+fuzz_targets = [
+ 'svg-render-fuzzer'
+]
+
+fuzz_args = ['-fsanitize=fuzzer,address']
+
+foreach target_name : fuzz_targets
+ exe = executable(target_name, [target_name + '.c'],
+ include_directories: [incbase, incsrc],
+ c_args: [fuzz_args],
+ link_with: [libcairo],
+ link_args: [fuzz_args, extra_link_args],
+ dependencies: [deps, test_deps])
+endforeach
diff --git a/test/svg/fuzzer/svg-render-fuzzer.c b/test/svg/fuzzer/svg-render-fuzzer.c
new file mode 100644
index 000000000..08eb79dd8
--- /dev/null
+++ b/test/svg/fuzzer/svg-render-fuzzer.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright © 2022 Uli Schlachter
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Uli Schlachter <psychon@znc.in>
+ */
+
+#include <cairo.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+cairo_bool_t
+_cairo_debug_svg_render (cairo_t *cr,
+ const char *svg_document,
+ const char *element,
+ double units_per_em,
+ int debug_level);
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ cairo_surface_t *s = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+ cairo_t *cr = cairo_create(s);
+
+ /* Get us a zero terminated string */
+ const char *svg_document = strndup ((const char *) data, size);
+
+ _cairo_debug_svg_render (cr,
+ svg_document,
+ NULL,
+ 1000,
+ 0);
+ free (svg_document);
+ cairo_destroy (cr);
+ cairo_surface_destroy (s);
+ return 0;
+}
diff --git a/test/svg/gradient.0.lin-pad.svg b/test/svg/gradient.0.lin-pad.svg
new file mode 100644
index 000000000..0ec54092f
--- /dev/null
+++ b/test/svg/gradient.0.lin-pad.svg
@@ -0,0 +1,10 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <linearGradient id="grad" x1="33%" x21="66%">
+ <stop offset="0%" stop-color="blue" stop-opacity="1" />
+ <stop offset="100%" stop-color="red" stop-opacity="0.5" />
+ </linearGradient>
+ </defs>
+ <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" />
+</svg>
+
diff --git a/test/svg/gradient.1.lin-reflect.svg b/test/svg/gradient.1.lin-reflect.svg
new file mode 100644
index 000000000..9e3e50cb9
--- /dev/null
+++ b/test/svg/gradient.1.lin-reflect.svg
@@ -0,0 +1,11 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <linearGradient id="grad" x1="33%" x2="66%"
+ spreadMethod="reflect">
+ <stop offset="0%" stop-color="blue" stop-opacity="1" />
+ <stop offset="100%" stop-color="red" stop-opacity="1" />
+ </linearGradient>
+ </defs>
+ <rect x="0" y="-900" width="1000" height="800" fill="url(#grad)" />
+</svg>
+
diff --git a/test/svg/gradient.2.lin-repeat.svg b/test/svg/gradient.2.lin-repeat.svg
new file mode 100644
index 000000000..1f023f5e1
--- /dev/null
+++ b/test/svg/gradient.2.lin-repeat.svg
@@ -0,0 +1,11 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <linearGradient id="grad" x1="33%" x2="66%"
+ spreadMethod="repeat">
+ <stop offset="0%" stop-color="blue" stop-opacity="1" />
+ <stop offset="100%" stop-color="red" stop-opacity="1" />
+ </linearGradient>
+ </defs>
+ <rect x="0" y="-900" width="1000" height="800" fill="url(#grad)" />
+</svg>
+
diff --git a/test/svg/gradient.3.lin-user.svg b/test/svg/gradient.3.lin-user.svg
new file mode 100644
index 000000000..fc90328f0
--- /dev/null
+++ b/test/svg/gradient.3.lin-user.svg
@@ -0,0 +1,11 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <linearGradient id="grad" x1="300" y1="-500" x2="600" y2="-500"
+ gradientUnits="userSpaceOnUse">
+ <stop offset="0%" stop-color="blue" stop-opacity="1" />
+ <stop offset="100%" stop-color="red" stop-opacity="1" />
+ </linearGradient>
+ </defs>
+ <rect x="0" y="-900" width="1000" height="800" fill="url(#grad)" />
+</svg>
+
diff --git a/test/svg/gradient.4.lin-transform.svg b/test/svg/gradient.4.lin-transform.svg
new file mode 100644
index 000000000..bc8f5b622
--- /dev/null
+++ b/test/svg/gradient.4.lin-transform.svg
@@ -0,0 +1,10 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <linearGradient id="grad" gradientTransform="rotate(45)">
+ <stop offset="0%" stop-color="blue" stop-opacity="1" />
+ <stop offset="100%" stop-color="red" stop-opacity="1" />
+ </linearGradient>
+ </defs>
+ <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" />
+</svg>
+
diff --git a/test/svg/gradient.5.rad-pad.svg b/test/svg/gradient.5.rad-pad.svg
new file mode 100644
index 000000000..b631ddc73
--- /dev/null
+++ b/test/svg/gradient.5.rad-pad.svg
@@ -0,0 +1,10 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <radialGradient id="grad" cx="50%" cy="50%"
+ fx="0.75" fy="0.35" r="0.5">
+ <stop offset="0%" stop-color="white" stop-opacity="1" />
+ <stop offset="100%" stop-color="green" stop-opacity="1" />
+ </radialGradient>
+ </defs>
+ <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" />
+</svg>
diff --git a/test/svg/gradient.6.rad-reflect.svg b/test/svg/gradient.6.rad-reflect.svg
new file mode 100644
index 000000000..b6fea76be
--- /dev/null
+++ b/test/svg/gradient.6.rad-reflect.svg
@@ -0,0 +1,11 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <radialGradient id="grad" cx="75%" cy="25%" r="33%"
+ fx="0.64" fy="0.18" fr="0.17"
+ spreadMethod="reflect" >
+ <stop offset="0%" stop-color="white" stop-opacity="1" />
+ <stop offset="100%" stop-color="green" stop-opacity="1" />
+ </radialGradient>
+ </defs>
+ <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" />
+</svg>
diff --git a/test/svg/gradient.7.rad-repeat.svg b/test/svg/gradient.7.rad-repeat.svg
new file mode 100644
index 000000000..63d138d2a
--- /dev/null
+++ b/test/svg/gradient.7.rad-repeat.svg
@@ -0,0 +1,11 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <radialGradient id="grad" cx="75%" cy="25%" r="33%"
+ fx="0.64" fy="0.18" fr="0.17"
+ spreadMethod="repeat" >
+ <stop offset="0%" stop-color="white" stop-opacity="1" />
+ <stop offset="100%" stop-color="green" stop-opacity="1" />
+ </radialGradient>
+ </defs>
+ <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" />
+</svg>
diff --git a/test/svg/gradient.8.rad-user.svg b/test/svg/gradient.8.rad-user.svg
new file mode 100644
index 000000000..e1d9c61f0
--- /dev/null
+++ b/test/svg/gradient.8.rad-user.svg
@@ -0,0 +1,11 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <radialGradient id="grad" cx="450" cy="-550" r="400"
+ fx="600" fy="-400" fr="10"
+ gradientUnits="userSpaceOnUse" >
+ <stop offset="0%" stop-color="red" stop-opacity="1" />
+ <stop offset="100%" stop-color="green" stop-opacity="0.5" />
+ </radialGradient>
+ </defs>
+ <rect x="0" y="-1000" width="1000" height="1000" fill="url(#grad)" />
+</svg>
diff --git a/test/svg/gradient.9.rad-transform.svg b/test/svg/gradient.9.rad-transform.svg
new file mode 100644
index 000000000..4b90aaaf6
--- /dev/null
+++ b/test/svg/gradient.9.rad-transform.svg
@@ -0,0 +1,11 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <defs>
+ <radialGradient id="grad" cx="50%" cy="25%"
+ fx="0.75" fy="0.35" r="0.5"
+ gradientTransform="scale(1, 2)">
+ <stop offset="0%" stop-color="red" stop-opacity="1" />
+ <stop offset="100%" stop-color="green" stop-opacity="1" />
+ </radialGradient>
+ </defs>
+ <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" />
+</svg>
diff --git a/test/svg/meson.build b/test/svg/meson.build
new file mode 100644
index 000000000..858e9d9cc
--- /dev/null
+++ b/test/svg/meson.build
@@ -0,0 +1,9 @@
+if librsvg_dep.found()
+ executable('svg-render',
+ 'svg-render.c',
+ dependencies: [libcairo_dep, librsvg_dep])
+endif
+
+if cc.links(files(meson.project_source_root() / 'meson-cc-tests/fuzzer.c'), args: '-fsanitize=fuzzer,address')
+ subdir('fuzzer')
+endif
diff --git a/test/svg/path.0.line.svg b/test/svg/path.0.line.svg
new file mode 100644
index 000000000..19d50914a
--- /dev/null
+++ b/test/svg/path.0.line.svg
@@ -0,0 +1,8 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <path fill="none" stroke="black" stroke-width="20"
+ d="M 200 -200
+ L 500 -500
+ H 800
+ V -200
+ " />
+</svg>
diff --git a/test/svg/path.1.curve.svg b/test/svg/path.1.curve.svg
new file mode 100644
index 000000000..49c252ac8
--- /dev/null
+++ b/test/svg/path.1.curve.svg
@@ -0,0 +1,9 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <path fill="none" stroke="black" stroke-width="20"
+ d="M200,-400
+ C200,-200
+ 500,-200
+ 500,-400
+ S800,-600
+ 800,-400" />
+</svg>
diff --git a/test/svg/path.2.quad.svg b/test/svg/path.2.quad.svg
new file mode 100644
index 000000000..00a0dde57
--- /dev/null
+++ b/test/svg/path.2.quad.svg
@@ -0,0 +1,8 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <path fill="none" stroke="black" stroke-width="20"
+ d="M200,-300
+ Q400,-50
+ 600,-300
+ T1000,-300"
+ />
+</svg>
diff --git a/test/svg/path.3.arc.svg b/test/svg/path.3.arc.svg
new file mode 100644
index 000000000..f177a72af
--- /dev/null
+++ b/test/svg/path.3.arc.svg
@@ -0,0 +1,7 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <path fill="none" stroke="black" stroke-width="20"
+ d="M500,-500
+ L 712 -712
+ A300,300 0 1,0 712, -288 z"
+ />
+</svg>
diff --git a/test/svg/shapes.0.rect.svg b/test/svg/shapes.0.rect.svg
new file mode 100644
index 000000000..17db34649
--- /dev/null
+++ b/test/svg/shapes.0.rect.svg
@@ -0,0 +1,3 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500"/>
+</svg>
diff --git a/test/svg/shapes.1.rounded-rect.svg b/test/svg/shapes.1.rounded-rect.svg
new file mode 100644
index 000000000..717470bee
--- /dev/null
+++ b/test/svg/shapes.1.rounded-rect.svg
@@ -0,0 +1,3 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <rect x="100" y="-750" width="800" height="500" rx="100" ry="100"/>
+</svg>
diff --git a/test/svg/shapes.2.circle.svg b/test/svg/shapes.2.circle.svg
new file mode 100644
index 000000000..3c07bad83
--- /dev/null
+++ b/test/svg/shapes.2.circle.svg
@@ -0,0 +1,3 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <circle cx="500" cy="-500" r="400"/>
+</svg>
diff --git a/test/svg/shapes.3.ellipse.svg b/test/svg/shapes.3.ellipse.svg
new file mode 100644
index 000000000..67260a404
--- /dev/null
+++ b/test/svg/shapes.3.ellipse.svg
@@ -0,0 +1,3 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <ellipse cx="500" cy="-500" rx="400" ry="200"/>
+</svg>
diff --git a/test/svg/shapes.4.line.svg b/test/svg/shapes.4.line.svg
new file mode 100644
index 000000000..58de42947
--- /dev/null
+++ b/test/svg/shapes.4.line.svg
@@ -0,0 +1,3 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="200" y1="-200" x2="800" y2="-800" stroke="black" stroke-width="20"/>
+</svg>
diff --git a/test/svg/shapes.5.polyline.svg b/test/svg/shapes.5.polyline.svg
new file mode 100644
index 000000000..0cc5c383c
--- /dev/null
+++ b/test/svg/shapes.5.polyline.svg
@@ -0,0 +1,12 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <polyline fill="none" stroke="black" stroke-width="20"
+ points="100, -100,
+ 300, -100,
+ 300, -300,
+ 500, -300,
+ 500, -500,
+ 700, -500
+ 700, -700
+ 900, -700
+ 900, -900" />
+</svg>
diff --git a/test/svg/shapes.6.polygon.svg b/test/svg/shapes.6.polygon.svg
new file mode 100644
index 000000000..56bda0705
--- /dev/null
+++ b/test/svg/shapes.6.polygon.svg
@@ -0,0 +1,12 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="500" height="500">
+<polygon points="350, -75
+ 379, -161
+ 469, -161
+ 397, -215
+ 423, -301
+ 350, -250
+ 277, -301
+ 303, -215
+ 231, -161
+ 321, -161" />
+</svg>
diff --git a/test/svg/stroke.0.name.svg b/test/svg/stroke.0.name.svg
new file mode 100644
index 000000000..f2a926475
--- /dev/null
+++ b/test/svg/stroke.0.name.svg
@@ -0,0 +1,6 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-500" x2="900" y2="-500"
+ fill="none"
+ stroke-width="100"
+ stroke="indigo" />
+</svg>
diff --git a/test/svg/stroke.1.hex6.svg b/test/svg/stroke.1.hex6.svg
new file mode 100644
index 000000000..89f2b1b38
--- /dev/null
+++ b/test/svg/stroke.1.hex6.svg
@@ -0,0 +1,6 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-500" x2="900" y2="-500"
+ fill="none"
+ stroke-width="100"
+ stroke="#AA55AA" />
+</svg>
diff --git a/test/svg/stroke.2.hex3.svg b/test/svg/stroke.2.hex3.svg
new file mode 100644
index 000000000..a8565a7b6
--- /dev/null
+++ b/test/svg/stroke.2.hex3.svg
@@ -0,0 +1,6 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-500" x2="900" y2="-500"
+ fill="none"
+ stroke-width="100"
+ stroke="#A5A" />
+</svg>
diff --git a/test/svg/stroke.3.rgb.svg b/test/svg/stroke.3.rgb.svg
new file mode 100644
index 000000000..42e7514e4
--- /dev/null
+++ b/test/svg/stroke.3.rgb.svg
@@ -0,0 +1,6 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-500" x2="900" y2="-500"
+ fill="none"
+ stroke-width="100"
+ stroke="rgb(75,0,130)" />
+</svg>
diff --git a/test/svg/stroke.4.current-color.svg b/test/svg/stroke.4.current-color.svg
new file mode 100644
index 000000000..9d645b881
--- /dev/null
+++ b/test/svg/stroke.4.current-color.svg
@@ -0,0 +1,6 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-500" x2="900" y2="-500"
+ fill="none"
+ stroke-width="100"
+ stroke="currentColor" />
+</svg>
diff --git a/test/svg/stroke.5.palette.svg b/test/svg/stroke.5.palette.svg
new file mode 100644
index 000000000..1262a7ba0
--- /dev/null
+++ b/test/svg/stroke.5.palette.svg
@@ -0,0 +1,6 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-500" x2="900" y2="-500"
+ fill="none"
+ stroke-width="100"
+ stroke="var(--color1, red)" />
+</svg>
diff --git a/test/svg/stroke.6.opacity.svg b/test/svg/stroke.6.opacity.svg
new file mode 100644
index 000000000..b84d1bdc9
--- /dev/null
+++ b/test/svg/stroke.6.opacity.svg
@@ -0,0 +1,6 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-500" x2="900" y2="-500"
+ fill="none"
+ stroke-width="100"
+ stroke="magenta" stroke-opacity="0.5" />
+</svg>
diff --git a/test/svg/stroke.7.color.svg b/test/svg/stroke.7.color.svg
new file mode 100644
index 000000000..952f48261
--- /dev/null
+++ b/test/svg/stroke.7.color.svg
@@ -0,0 +1,7 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ color="green" >
+ <line x1="100" y1="-500" x2="900" y2="-500"
+ fill="none"
+ stroke-width="100"
+ stroke="currentColor" />
+</svg>
diff --git a/test/svg/stroke.8.width.svg b/test/svg/stroke.8.width.svg
new file mode 100644
index 000000000..bb9edea90
--- /dev/null
+++ b/test/svg/stroke.8.width.svg
@@ -0,0 +1,14 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-900" x2="900" y2="-900"
+ fill="none"
+ stroke-width="100"
+ stroke="black" />
+ <line x1="100" y1="-500" x2="900" y2="-500"
+ fill="none"
+ stroke-width="200"
+ stroke="black" />
+ <line x1="100" y1="-100" x2="900" y2="-100"
+ fill="none"
+ stroke-width="300"
+ stroke="black" />
+</svg>
diff --git a/test/svg/stroke.9.cap.svg b/test/svg/stroke.9.cap.svg
new file mode 100644
index 000000000..35046446c
--- /dev/null
+++ b/test/svg/stroke.9.cap.svg
@@ -0,0 +1,17 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-900" x2="900" y2="-900"
+ fill="none"
+ stroke-width="200"
+ stroke-linecap="butt"
+ stroke="black" />
+ <line x1="100" y1="-500" x2="900" y2="-500"
+ fill="none"
+ stroke-width="200"
+ stroke-linecap="round"
+ stroke="black" />
+ <line x1="100" y1="-100" x2="900" y2="-100"
+ fill="none"
+ stroke-width="200"
+ stroke-linecap="square"
+ stroke="black" />
+</svg>
diff --git a/test/svg/stroke.A.dash.svg b/test/svg/stroke.A.dash.svg
new file mode 100644
index 000000000..2be5a1d90
--- /dev/null
+++ b/test/svg/stroke.A.dash.svg
@@ -0,0 +1,27 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-950" x2="900" y2="-950"
+ fill="none"
+ stroke-width="100"
+ stroke-dasharray="none"
+ stroke="black" />
+ <line x1="100" y1="-750" x2="900" y2="-750"
+ fill="none"
+ stroke-width="100"
+ stroke-dasharray="200"
+ stroke="black" />
+ <line x1="100" y1="-550" x2="900" y2="-550"
+ fill="none"
+ stroke-width="100"
+ stroke-dasharray="200 50"
+ stroke="black" />
+ <line x1="100" y1="-350" x2="900" y2="-350"
+ fill="none"
+ stroke-width="100"
+ stroke-dasharray="200 50 100"
+ stroke="black" />
+ <line x1="100" y1="-150" x2="900" y2="-150"
+ fill="none"
+ stroke-width="100"
+ stroke-dasharray="200 50 100 150"
+ stroke="black" />
+</svg>
diff --git a/test/svg/stroke.B.dash-offset.svg b/test/svg/stroke.B.dash-offset.svg
new file mode 100644
index 000000000..f7623ea84
--- /dev/null
+++ b/test/svg/stroke.B.dash-offset.svg
@@ -0,0 +1,31 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <line x1="100" y1="-950" x2="900" y2="-950"
+ fill="none"
+ stroke-width="100"
+ stroke-dasharray="none"
+ stroke="black" />
+ <line x1="100" y1="-750" x2="900" y2="-750"
+ fill="none"
+ stroke-width="100"
+ stroke-dasharray="200"
+ stroke-dashoffset="100"
+ stroke="black" />
+ <line x1="100" y1="-550" x2="900" y2="-550"
+ fill="none"
+ stroke-width="100"
+ stroke-dasharray="200 50"
+ stroke-dashoffset="100"
+ stroke="black" />
+ <line x1="100" y1="-350" x2="900" y2="-350"
+ fill="none"
+ stroke-width="100"
+ stroke-dasharray="200 50 100"
+ stroke-dashoffset="100"
+ stroke="black" />
+ <line x1="100" y1="-150" x2="900" y2="-150"
+ fill="none"
+ stroke-width="100"
+ stroke-dasharray="200 50 100 150"
+ stroke-dashoffset="100"
+ stroke="black" />
+</svg>
diff --git a/test/svg/stroke.C.miter.svg b/test/svg/stroke.C.miter.svg
new file mode 100644
index 000000000..1dc4ee6a7
--- /dev/null
+++ b/test/svg/stroke.C.miter.svg
@@ -0,0 +1,10 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <polyline
+ points="100, -200
+ 900, -400
+ 100, -700"
+ fill="none"
+ stroke-width="200"
+ stroke-linejoin="miter"
+ stroke="black" />
+</svg>
diff --git a/test/svg/stroke.D.round.svg b/test/svg/stroke.D.round.svg
new file mode 100644
index 000000000..3e4c6236f
--- /dev/null
+++ b/test/svg/stroke.D.round.svg
@@ -0,0 +1,10 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <polyline
+ points="100, -200
+ 900, -400
+ 100, -700"
+ fill="none"
+ stroke-width="200"
+ stroke-linejoin="round"
+ stroke="black" />
+</svg>
diff --git a/test/svg/stroke.E.bevel.svg b/test/svg/stroke.E.bevel.svg
new file mode 100644
index 000000000..25d9e3803
--- /dev/null
+++ b/test/svg/stroke.E.bevel.svg
@@ -0,0 +1,10 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <polyline
+ points="100, -200
+ 900, -400
+ 100, -700"
+ fill="none"
+ stroke-width="200"
+ stroke-linejoin="bevel"
+ stroke="black" />
+</svg>
diff --git a/test/svg/stroke.F.miter-limit.svg b/test/svg/stroke.F.miter-limit.svg
new file mode 100644
index 000000000..14357f0b4
--- /dev/null
+++ b/test/svg/stroke.F.miter-limit.svg
@@ -0,0 +1,11 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
+ <polyline
+ points="100, -200
+ 900, -400
+ 100, -700"
+ fill="none"
+ stroke-width="200"
+ stroke-linejoin="miter"
+ stroke-miterlimit="2"
+ stroke="black" />
+</svg>
diff --git a/test/svg/svg-font-template.ttx b/test/svg/svg-font-template.ttx
new file mode 100644
index 000000000..715074dda
--- /dev/null
+++ b/test/svg/svg-font-template.ttx
@@ -0,0 +1,190 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.19">
+
+ <GlyphOrder>
+ <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
+ <GlyphID id="0" name=".notdef"/>
+ </GlyphOrder>
+
+ <head>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x3e7355ef"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000001"/>
+ <unitsPerEm value="1000"/>
+ <created value="Wed Jun 15 00:00:00 2022"/>
+ <modified value="Wed Jun 15 00:00:00 2022"/>
+ <xMin value="0"/>
+ <yMin value="0"/>
+ <xMax value="1000"/>
+ <yMax value="1000"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="6"/>
+ <fontDirectionHint value="2"/>
+ <indexToLocFormat value="0"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="0x00010000"/>
+ <ascent value="1000"/>
+ <descent value="0"/>
+ <lineGap value="200"/>
+ <advanceWidthMax value="1100"/>
+ <minLeftSideBearing value="0"/>
+ <minRightSideBearing value="0"/>
+ <xMaxExtent value="1000"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ <numberOfHMetrics value="2"/>
+ </hhea>
+
+ <maxp>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="0x10000"/>
+ <numGlyphs value="2"/>
+ <maxPoints value="1"/>
+ <maxContours value="1"/>
+ <maxCompositePoints value="1"/>
+ <maxCompositeContours value="1"/>
+ <maxZones value="1"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="256"/>
+ <maxSizeOfInstructions value="1"/>
+ <maxComponentElements value="2"/>
+ <maxComponentDepth value="1"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="1000"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00000001"/>
+ <ySubscriptXSize value="600"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="600"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="300"/>
+ <yStrikeoutSize value="0"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="0"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="djr "/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="65"/>
+ <usLastCharIndex value="65"/>
+ <sTypoAscender value="1000"/>
+ <sTypoDescender value="0"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="300"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="720"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="3"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="1100" lsb="0"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="0" platEncID="3" language="0">
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+
+ <!-- The xMin, yMin, xMax and yMax values
+ will be recalculated by the compiler. -->
+
+ <TTGlyph name=".notdef"/><!-- contains no outline data -->
+
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Cairo Font Template
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Cairo Font Template Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="0"/>
+ <underlineThickness value="0"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+ <CPAL>
+ <version value="0"/>
+ <numPaletteEntries value="2"/>
+ <palette index="0">
+ <color index="0" value="#C5A1D7FF"/>
+ <color index="1" value="#80DFC8FF"/>
+ </palette>
+ <palette index="1">
+ <color index="0" value="#6392A9FF"/>
+ <color index="1" value="#7896B3FF"/>
+ </palette>
+ </CPAL>
+
+ <SVG>
+ <svgDoc endGlyphID="0" startGlyphID="0">
+ <![CDATA[<svg xmlns="http://www.w3.org/2000/svg"></svg>]]>
+ </svgDoc>
+ <colorPalettes>
+ </colorPalettes>
+ </SVG>
+
+</ttFont>
diff --git a/test/svg/svg-render.c b/test/svg/svg-render.c
new file mode 100644
index 000000000..8f67ebdc2
--- /dev/null
+++ b/test/svg/svg-render.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright © 2016 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>
+ */
+
+/* Compilation:
+ * Build cairo with -DDEBUG_SVG_RENDER
+ * gcc -o svg-render svg-render.c `pkg-config --cflags --libs cairo librsvg`
+ */
+
+/* svg-render - render SVG files using both the cairo glyph renderer and librsvg.
+ *
+ * This allows testing the cairo SVG test cases before assembling them into an SVG font.
+ * Usage:
+ * svg-render [-b] [-s] [-g <id>] [-e <em_size> ] input.svg
+ *
+ * Output is written to input.cairo.png and input.rsvg.png.
+ *
+ * -b print bounding box.
+ * -s Use standard SVG viewport. See below.
+ * -g render glyph with id <id>
+ * -e set the EM size. The default is 1000.
+ *
+ * SVG Glyphs are assumed to be wholely within the view port.
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include <cairo.h>
+#include <librsvg/rsvg.h>
+
+typedef enum { CAIRO_SVG, LIBRSVG } svg_renderer_t;
+
+/* output image size */
+#define WIDTH 1000
+#define HEIGHT 1000
+
+static cairo_bool_t bbox = FALSE;
+static cairo_bool_t standard_svg = FALSE;
+static const char *glyph_id = NULL;
+static int em_size = 1000;
+
+cairo_bool_t
+_cairo_debug_svg_render (cairo_t *cr,
+ const char *svg_document,
+ const char *element,
+ double units_per_em,
+ int debug_level);
+
+static void
+cairo_render (const char *svg_document, cairo_t *cr)
+{
+ if (!_cairo_debug_svg_render (cr, svg_document, glyph_id, em_size, 2))
+ printf("_cairo_debug_svg_render() failed\n");
+}
+
+static void
+librsvg_render (const char *svg_document, cairo_t *cr)
+{
+ gboolean has_width;
+ gboolean has_height;
+ gboolean has_viewbox;
+ RsvgLength svg_width;
+ RsvgLength svg_height;
+ RsvgRectangle svg_viewbox;
+ RsvgRectangle viewport;
+ double width, height;
+ GError *error = NULL;
+
+ RsvgHandle *handle = rsvg_handle_new_from_data ((guint8 *)svg_document,
+ strlen(svg_document),
+ &error);
+ if (!handle) {
+ printf ("Could not load: %s", error->message);
+ return;
+ }
+
+ /* Default width if not specified is EM Square */
+ width = em_size;
+ height = em_size;
+
+ /* Get width/height if specified. */
+ rsvg_handle_get_intrinsic_dimensions(handle,
+ &has_width,
+ &svg_width,
+ &has_height,
+ &svg_height,
+ &has_viewbox,
+ &svg_viewbox);
+ if (has_width)
+ width = svg_width.length;
+
+ if (has_height)
+ height = svg_height.length;
+
+ /* We set the viewport for the call rsvg_handle_render_layer() to
+ * width/height. That way if either dimension is not specified in
+ * the SVG it will be inherited from the viewport we provide.
+ *
+ * As this scales up the rendered dimensions by width/height we
+ * need to undo this scaling to get a unit square scale that
+ * matches the cairo SVG renderer scale. The OpenType SVG spec
+ * does not say what to do if width != height. In this case we
+ * will just use a uniform scale that ensures the viewport fits in
+ * the unit square and also center it.
+ */
+
+ if (width > height) {
+ cairo_scale (cr, 1.0/width, 1.0/width);
+ cairo_translate (cr, 0, (width - height)/2.0);
+ } else {
+ cairo_scale (cr, 1.0/height, 1.0/height);
+ cairo_translate (cr, (height - width)/2.0, 0);
+ }
+
+ viewport.x = 0;
+ viewport.y = 0;
+ viewport.width = width;
+ viewport.height = height;
+ if (!rsvg_handle_render_layer (handle, cr, glyph_id, &viewport, &error)) {
+ printf ("librsvg render failed: %s", error->message);
+ return;
+ }
+}
+
+static void
+render_svg (const char *svg_document, svg_renderer_t renderer, const char* out_file)
+{
+ double x, y, w, h;
+
+ cairo_surface_t *recording = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL);
+ cairo_t *cr = cairo_create (recording);
+
+ /* Scale up to image size when recording to reduce rounding errors
+ * in cairo_recording_surface_ink_extents()
+ */
+ cairo_scale (cr, WIDTH, HEIGHT);
+
+ if (renderer == CAIRO_SVG) {
+ cairo_render (svg_document, cr);
+ } else {
+ librsvg_render (svg_document, cr);
+ }
+ cairo_destroy (cr);
+
+ if (bbox) {
+ cairo_recording_surface_ink_extents (recording, &x, &y, &w, &h);
+ if (renderer == CAIRO_SVG)
+ printf("cairo ");
+ else
+ printf("librsvg");
+
+ printf(" bbox left: %d right: %d top: %d bottom: %d\n",
+ (int)floor(x),
+ (int)ceil(x + w),
+ (int)floor(y),
+ (int)ceil(y + h));
+ }
+
+ cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT);
+ cr = cairo_create (surface);
+
+ /* If rendering a glyph need to translate base line to bottom of image */
+ if (standard_svg)
+ cairo_set_source_surface (cr, recording, 0, 0);
+ else
+ cairo_set_source_surface (cr, recording, 0, HEIGHT);
+
+ cairo_paint (cr);
+
+ cairo_surface_write_to_png (surface, out_file);
+ cairo_surface_destroy (surface);
+}
+
+static char *
+create_output_name (const char *svg_file, svg_renderer_t renderer)
+{
+ char buf[1000];
+ int len;
+
+ strcpy (buf, svg_file);
+ len = strlen (buf);
+
+ if (strlen (buf) > 5 && strcmp (buf + len - 4, ".svg") == 0)
+ buf[len - 4] = 0;
+
+ if (renderer == CAIRO_SVG)
+ strcat (buf, ".cairo.png");
+ else
+ strcat (buf, ".rsvg.png");
+
+ return strdup (buf);
+}
+
+static char *
+read_file(const char *filename)
+{
+ FILE *fp;
+ int len;
+ char *data;
+
+ fp = fopen (filename, "r");
+ if (fp == NULL)
+ return NULL;
+
+ fseek (fp, 0, SEEK_END);
+ len = ftell(fp);
+ rewind (fp);
+ data = malloc (len + 1);
+ if (fread(data, len, 1, fp) != 1)
+ return NULL;
+ data[len] = 0;
+ fclose(fp);
+ return data;
+}
+
+static void
+usage_and_exit()
+{
+ printf ("svg-render [-b] [-s] [-g <id>] [-e <em_size> ] input.svg\n");
+ exit (1);
+}
+
+int
+main(int argc, char **argv)
+{
+ const char *input_file = NULL;
+ char *svg_document;
+ char *output_file;
+
+ argc--;
+ argv++;
+ while (argc > 0) {
+ if (strcmp (argv[0], "-b") == 0) {
+ bbox = TRUE;
+ argc--;
+ argv++;
+ } else if (strcmp (argv[0], "-s") == 0) {
+ standard_svg = TRUE;
+ argc--;
+ argv++;
+ } else if (strcmp (argv[0], "-g") == 0) {
+ if (argc > 1) {
+ glyph_id = argv[1];
+ argc -= 2;
+ argv += 2;
+ } else {
+ usage_and_exit();
+ }
+ } else if (strcmp (argv[0], "-e") == 0) {
+ if (argc > 1) {
+ em_size = atoi (argv[1]);
+ if (em_size <= 0) {
+ usage_and_exit();
+ }
+ argc -= 2;
+ argv += 2;
+ } else {
+ usage_and_exit();
+ }
+ } else {
+ input_file = argv[0];
+ argc--;
+ argv++;
+ }
+ }
+ if (!input_file)
+ usage_and_exit();
+
+ svg_document = read_file (input_file);
+ if (!svg_document) {
+ printf("error reading file %s\n", input_file);
+ exit (1);
+ }
+
+ output_file = create_output_name (input_file, CAIRO_SVG);
+ render_svg (svg_document, CAIRO_SVG, output_file);
+ free (output_file);
+
+ output_file = create_output_name (input_file, LIBRSVG);
+ render_svg (svg_document, LIBRSVG, output_file);
+ free (output_file);
+
+ free (svg_document);
+
+ return 0;
+}
diff --git a/test/svg/transform.0.translate.svg b/test/svg/transform.0.translate.svg
new file mode 100644
index 000000000..5d9555673
--- /dev/null
+++ b/test/svg/transform.0.translate.svg
@@ -0,0 +1,8 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <rect id="square" width="300" height="300"/>
+ </defs>
+ <use xlink:href="#square" transform="translate(100, -900)"/>
+ <use xlink:href="#square" transform="translate(600, -400)"/>
+</svg>
diff --git a/test/svg/transform.1.scale.svg b/test/svg/transform.1.scale.svg
new file mode 100644
index 000000000..b7742fc80
--- /dev/null
+++ b/test/svg/transform.1.scale.svg
@@ -0,0 +1,10 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <rect id="square" width="300" height="300"/>
+ </defs>
+ <use xlink:href="#square" transform="translate(100, -900)"/>
+ <g transform="translate(400, -400)">
+ <use xlink:href="#square" transform="scale(1.5, 0.5)"/>
+ </g>
+</svg>
diff --git a/test/svg/transform.2.rotate.svg b/test/svg/transform.2.rotate.svg
new file mode 100644
index 000000000..926ae63fc
--- /dev/null
+++ b/test/svg/transform.2.rotate.svg
@@ -0,0 +1,10 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <rect id="square" width="300" height="300"/>
+ </defs>
+ <use xlink:href="#square" transform="translate(100, -900)"/>
+ <g transform="translate(600, -600)">
+ <use xlink:href="#square" transform="rotate(30)"/>
+ </g>
+</svg>
diff --git a/test/svg/transform.3.skewX.svg b/test/svg/transform.3.skewX.svg
new file mode 100644
index 000000000..f7555534d
--- /dev/null
+++ b/test/svg/transform.3.skewX.svg
@@ -0,0 +1,10 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <rect id="square" width="300" height="300"/>
+ </defs>
+ <use xlink:href="#square" transform="translate(100, -900)"/>
+ <g transform="translate(400, -400)">
+ <use xlink:href="#square" transform="skewX(30)"/>
+ </g>
+</svg>
diff --git a/test/svg/transform.4.skewY.svg b/test/svg/transform.4.skewY.svg
new file mode 100644
index 000000000..cd62c8a8a
--- /dev/null
+++ b/test/svg/transform.4.skewY.svg
@@ -0,0 +1,10 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <rect id="square" width="300" height="300"/>
+ </defs>
+ <use xlink:href="#square" transform="translate(100, -900)"/>
+ <g transform="translate(400, -500)">
+ <use xlink:href="#square" transform="skewY(30)"/>
+ </g>
+</svg>
diff --git a/test/svg/transform.5.matrix.svg b/test/svg/transform.5.matrix.svg
new file mode 100644
index 000000000..643fbe36b
--- /dev/null
+++ b/test/svg/transform.5.matrix.svg
@@ -0,0 +1,10 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <rect id="square" width="300" height="300"/>
+ </defs>
+ <use xlink:href="#square" transform="translate(100, -900)"/>
+ <g transform="translate(600, -600)">
+ <use xlink:href="#square" transform="matrix(1, 0.4, -0.6, 1.1, 50, -70)"/>
+ </g>
+</svg>
diff --git a/test/svg/transform.6.multiple.svg b/test/svg/transform.6.multiple.svg
new file mode 100644
index 000000000..90c7b3054
--- /dev/null
+++ b/test/svg/transform.6.multiple.svg
@@ -0,0 +1,16 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <path id="heart" d="M 10,30 A 20,20 0,0,1 50,30 A 20,20 0,0,1 90,30 Q 90,60 50,90 Q 10,60 10,30 z" />
+ </defs>
+ <use xlink:href="#heart"
+ transform="translate(10, -650)
+ rotate(-10 50 100)
+ translate(-166 125.5)
+ skewX(40)
+ scale(1 0.5),scale(8, 8)"
+ fill="grey"/>
+ <use xlink:href="#heart"
+ transform="translate(300, -800),scale(6, 6)"
+ fill="none" stroke="red" />
+</svg>
diff --git a/test/svg/transform.7.stroke.svg b/test/svg/transform.7.stroke.svg
new file mode 100644
index 000000000..f56b24dfe
--- /dev/null
+++ b/test/svg/transform.7.stroke.svg
@@ -0,0 +1,20 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <defs>
+ <circle id="c1"
+ cx="100" cy="100" r="80"
+ fill="none"
+ stroke="black"
+ stroke-width="20" />
+ <circle id="c2"
+ cx="100" cy="100" r="80"
+ fill="none"
+ stroke="black"
+ stroke-width="20"
+ transform="scale(3,3)" />
+ </defs>
+
+ <use xlink:href="#c1" x="100" y="-900"/>
+ <use xlink:href="#c2" x="300" y="-700"/>
+
+</svg>
diff --git a/test/user-font-color.c b/test/user-font-color.c
index 781d6945d..db8b6a173 100644
--- a/test/user-font-color.c
+++ b/test/user-font-color.c
@@ -32,16 +32,27 @@
#include "cairo-test.h"
+#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#define BORDER 10
#define TEXT_SIZE 64
-#define WIDTH (TEXT_SIZE * 6 + 2*BORDER)
-#define HEIGHT (TEXT_SIZE + 2*BORDER)
+#define WIDTH (TEXT_SIZE * 11 + 2*BORDER)
+#define HEIGHT (4*TEXT_SIZE + 5*BORDER)
-#define TEXT "abcdef"
+#define TEXT "abcdefghij"
+
+/* These characters will be drawn twice with a different foreground color */
+#define FG_TEXT "acfh"
+
+/* Uppercase draws the same text but forces the use of the non-color
+ * render callback */
+#define TEXT_NO_COLOR "ABCDEFGHIJ"
+#define FG_TEXT_NO_COLOR "ACFH"
+
+#define TEXT_PATH "aabccdeffghhij"
static cairo_status_t
@@ -55,39 +66,60 @@ test_scaled_font_init (cairo_scaled_font_t *scaled_font,
}
static void
-render_glyph_solid (cairo_t *cr, double width, double height, cairo_bool_t color)
+render_glyph_solid (cairo_t *cr,
+ double width,
+ double height,
+ cairo_bool_t color,
+ cairo_scaled_font_t *scaled_font)
{
- cairo_pattern_t *pattern = cairo_pattern_reference(cairo_get_source (cr));
-
if (color)
- cairo_set_source_rgba (cr, 0, 1, 1, 0.5);
+ cairo_set_source_rgba (cr, 0.7, 0.2, 0.1, 0.9);
cairo_rectangle (cr, 0, 0, width/2, height/2);
cairo_fill (cr);
- if (color)
- cairo_set_source (cr, pattern);
+ if (color) {
+ if (scaled_font)
+ cairo_set_source (cr, cairo_user_scaled_font_get_foreground_marker (scaled_font));
+ else
+ cairo_set_source_rgba (cr, 0.2, 0.5, 0.3, 0.9);
+ }
cairo_rectangle (cr, width/4, height/4, width/2, height/2);
cairo_fill (cr);
if (color)
- cairo_set_source_rgba (cr, 1, 1, 0, 0.5);
+ cairo_set_source_rgba (cr, 0.2, 0.3, 0.5, 0.9);
cairo_rectangle (cr, width/2, height/2, width/2, height/2);
cairo_fill (cr);
-
- cairo_pattern_destroy (pattern);
}
static void
-render_glyph_linear (cairo_t *cr, double width, double height, cairo_bool_t color)
+render_glyph_linear (cairo_t *cr,
+ double width,
+ double height,
+ cairo_bool_t color,
+ cairo_scaled_font_t *scaled_font)
{
cairo_pattern_t *pat;
+ cairo_pattern_t *fg;
pat = cairo_pattern_create_linear (0.0, 0.0, width, height);
- cairo_pattern_add_color_stop_rgba (pat, 0, 1, 0, 0, 1);
- cairo_pattern_add_color_stop_rgba (pat, 0.5, 0, 1, 0, color ? 0.5 : 1);
- cairo_pattern_add_color_stop_rgba (pat, 1, 0, 0, 1, 1);
- cairo_set_source (cr, pat);
+ if (scaled_font) {
+ double r, g, b, a;
+
+ fg = cairo_user_scaled_font_get_foreground_source (scaled_font);
+ if (cairo_pattern_get_rgba (fg, &r, &g, &b, &a) != CAIRO_STATUS_SUCCESS) {
+ r = g = b = 0;
+ a = 1;
+ }
+ cairo_pattern_add_color_stop_rgba (pat, 0, r, g, b, a);
+ cairo_pattern_add_color_stop_rgb (pat, 1, 0, 0, 1);
+ } else {
+ cairo_pattern_add_color_stop_rgb (pat, 0, 1, 0.4, 0.2);
+ cairo_pattern_add_color_stop_rgb (pat, 0.5, 0.2, 1, 0.4);
+ cairo_pattern_add_color_stop_rgb (pat, 1, 0.2, 0.3, 1);
+ }
+ cairo_set_source (cr, pat);
cairo_rectangle (cr, 0, 0, width, height);
cairo_fill (cr);
}
@@ -101,23 +133,23 @@ render_glyph_text (cairo_t *cr, double width, double height, cairo_bool_t color)
cairo_set_font_size(cr, 0.5);
if (color)
- cairo_set_source_rgb (cr, 0.5, 0.5, 0);
+ cairo_set_source_rgb (cr, 0.5, 0.7, 0);
cairo_move_to (cr, width*0.1, height/2);
cairo_show_text (cr, "a");
if (color)
- cairo_set_source_rgb (cr, 0, 0.5, 0.5);
+ cairo_set_source_rgb (cr, 0, 0.5, 0.7);
cairo_move_to (cr, width*0.4, height*0.9);
cairo_show_text (cr, "z");
}
static cairo_status_t
-test_scaled_font_render_color_glyph (cairo_scaled_font_t *scaled_font,
- unsigned long glyph,
- cairo_t *cr,
- cairo_text_extents_t *metrics)
+test_scaled_font_render_glyph_common (cairo_scaled_font_t *scaled_font,
+ unsigned long glyph,
+ cairo_t *cr,
+ cairo_text_extents_t *metrics,
+ cairo_bool_t color)
{
- cairo_status_t status = CAIRO_STATUS_SUCCESS;
double width = 0.5;
double height = 0.8;
@@ -125,54 +157,78 @@ test_scaled_font_render_color_glyph (cairo_scaled_font_t *scaled_font,
cairo_translate (cr, 0.125, -0.6);
switch (glyph) {
case 'a':
- render_glyph_solid (cr, width, height, TRUE);
+ render_glyph_solid (cr, width, height, color, scaled_font);
break;
case 'b':
- render_glyph_linear (cr, width, height, TRUE);
+ render_glyph_solid (cr, width, height, color, NULL);
break;
case 'c':
- render_glyph_text (cr, width, height, TRUE);
+ render_glyph_linear (cr, width, height, color, scaled_font);
break;
case 'd':
- render_glyph_solid (cr, width, height, TRUE);
- status = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
+ render_glyph_linear (cr, width, height, color, NULL);
break;
case 'e':
- render_glyph_linear (cr, width, height, TRUE);
- status = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
+ render_glyph_text (cr, width, height, color);
break;
case 'f':
- render_glyph_solid (cr, width, height, TRUE);
- status = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
+ cairo_push_group (cr);
+ render_glyph_solid (cr, width, height, color, scaled_font);
+ cairo_pop_group_to_source (cr);
+ cairo_paint (cr);
+ break;
+ case 'g':
+ cairo_push_group (cr);
+ render_glyph_solid (cr, width, height, color, NULL);
+ cairo_pop_group_to_source (cr);
+ cairo_paint (cr);
+ break;
+ case 'h':
+ cairo_push_group (cr);
+ render_glyph_linear (cr, width, height, color, scaled_font);
+ cairo_pop_group_to_source (cr);
+ cairo_paint (cr);
+ break;
+ case 'i':
+ cairo_push_group (cr);
+ render_glyph_linear (cr, width, height, color, NULL);
+ cairo_pop_group_to_source (cr);
+ cairo_paint (cr);
+ break;
+ case 'j':
+ cairo_push_group (cr);
+ render_glyph_text (cr, width, height, color);
+ cairo_pop_group_to_source (cr);
+ cairo_paint (cr);
break;
}
- return status;
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
-test_scaled_font_render_glyph (cairo_scaled_font_t *scaled_font,
- unsigned long glyph,
- cairo_t *cr,
- cairo_text_extents_t *metrics)
+test_scaled_font_render_color_glyph_callback (cairo_scaled_font_t *scaled_font,
+ unsigned long glyph,
+ cairo_t *cr,
+ cairo_text_extents_t *metrics)
{
- double width = 0.5;
- double height = 0.8;
- metrics->x_advance = 0.75;
- cairo_translate (cr, 0.125, -0.6);
- switch (glyph) {
- case 'd':
- render_glyph_solid (cr, width, height, FALSE);
- break;
- case 'e':
- render_glyph_linear (cr, width, height, FALSE);
- break;
- case 'f':
- render_glyph_text (cr, width, height, FALSE);
- break;
- }
+ if (isupper(glyph))
+ return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED;
- return CAIRO_STATUS_SUCCESS;
+ return test_scaled_font_render_glyph_common (scaled_font, glyph, cr, metrics, TRUE);
+}
+
+static cairo_status_t
+test_scaled_font_render_glyph_callback (cairo_scaled_font_t *scaled_font,
+ unsigned long glyph,
+ cairo_t *cr,
+ cairo_text_extents_t *metrics)
+{
+ int c = glyph;
+ if (isupper(c))
+ c = tolower(c);
+
+ return test_scaled_font_render_glyph_common (scaled_font, c, cr, metrics, FALSE);
}
static cairo_status_t
@@ -183,13 +239,35 @@ _user_font_face_create (cairo_font_face_t **out)
user_font_face = cairo_user_font_face_create ();
cairo_user_font_face_set_init_func (user_font_face, test_scaled_font_init);
- cairo_user_font_face_set_render_color_glyph_func (user_font_face, test_scaled_font_render_color_glyph);
- cairo_user_font_face_set_render_glyph_func (user_font_face, test_scaled_font_render_glyph);
+ cairo_user_font_face_set_render_color_glyph_func (user_font_face,
+ test_scaled_font_render_color_glyph_callback);
+ cairo_user_font_face_set_render_glyph_func (user_font_face,
+ test_scaled_font_render_glyph_callback);
*out = user_font_face;
return CAIRO_STATUS_SUCCESS;
}
+/* Any text characters that are in fg_text will be drawn with a different color */
+static void
+draw_line (cairo_t *cr, const char *text, const char *fg_text)
+{
+ char buf[10];
+
+ for (unsigned i = 0; i < strlen(text); i++) {
+ buf[0] = text[i];
+ buf[1] = 0;
+
+ if (strchr (fg_text, text[i])) {
+ cairo_set_source_rgb (cr, 1, 0, 0);
+ cairo_show_text (cr, buf);
+ }
+
+ cairo_set_source_rgb (cr, 0, 1, 0);
+ cairo_show_text (cr, buf);
+ }
+}
+
static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
@@ -198,6 +276,7 @@ draw (cairo_t *cr, int width, int height)
cairo_font_extents_t font_extents;
cairo_text_extents_t extents;
cairo_status_t status;
+ cairo_font_options_t *font_options;
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_paint (cr);
@@ -239,10 +318,31 @@ draw (cairo_t *cr, int width, int height)
cairo_set_line_width (cr, 2);
cairo_stroke (cr);
- /* text in color */
- cairo_set_source_rgb (cr, 0, 0.3, 0);
+ /* Line 1: text in color */
cairo_move_to (cr, BORDER, BORDER + font_extents.ascent);
- cairo_show_text (cr, text);
+ draw_line (cr, TEXT, FG_TEXT);
+
+ /* Line 2: text in non-color (color render callback returns
+ * CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED.
+ */
+ cairo_move_to (cr, BORDER, BORDER + font_extents.height + 1*BORDER + font_extents.ascent);
+ draw_line (cr, TEXT_NO_COLOR, FG_TEXT_NO_COLOR);
+
+ /* Line 3: Filled version of color text in blue */
+ cairo_move_to (cr, BORDER, BORDER + 2*font_extents.height + 2*BORDER + font_extents.ascent);
+ cairo_set_source_rgb (cr, 0, 0, 1);
+ cairo_text_path (cr, TEXT_PATH);
+ cairo_fill (cr);
+
+ /* Line 4: color glyphs with CAIRO_COLOR_MODE_NO_COLOR font option. */
+ font_options = cairo_font_options_create ();
+ cairo_get_font_options (cr, font_options);
+ cairo_font_options_set_color_mode (font_options, CAIRO_COLOR_MODE_NO_COLOR);
+ cairo_set_font_options (cr, font_options);
+ cairo_font_options_destroy (font_options);
+
+ cairo_move_to (cr, BORDER, BORDER + 3*font_extents.height + 3*BORDER + font_extents.ascent);
+ draw_line (cr, TEXT, FG_TEXT);
return CAIRO_TEST_SUCCESS;
}
diff --git a/test/user-font-proxy.c b/test/user-font-proxy.c
index e4063f0eb..42f51b602 100644
--- a/test/user-font-proxy.c
+++ b/test/user-font-proxy.c
@@ -40,7 +40,9 @@
#else
#define HEIGHT WIDTH
#endif
-#define TEXT "geez... cairo user-font"
+
+#define TEXT1 "cairo user-font."
+#define TEXT2 " zg"
static cairo_user_data_key_t fallback_font_key;
@@ -148,11 +150,16 @@ _user_font_face_create (cairo_font_face_t **out)
static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
- const char text[] = TEXT;
cairo_font_extents_t font_extents;
cairo_text_extents_t extents;
cairo_font_face_t *font_face;
cairo_status_t status;
+ char full_text[100];
+
+ strcpy(full_text, TEXT1);
+ strcat(full_text, TEXT2);
+ strcat(full_text, TEXT2);
+ strcat(full_text, TEXT2);
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_paint (cr);
@@ -174,7 +181,7 @@ draw (cairo_t *cr, int width, int height)
cairo_set_font_size (cr, TEXT_SIZE);
cairo_font_extents (cr, &font_extents);
- cairo_text_extents (cr, text, &extents);
+ cairo_text_extents (cr, full_text, &extents);
/* logical boundaries in red */
cairo_move_to (cr, 0, BORDER);
@@ -199,16 +206,26 @@ draw (cairo_t *cr, int width, int height)
cairo_set_line_width (cr, 2);
cairo_stroke (cr);
- /* text in gray */
- cairo_set_source_rgb (cr, 0, 0, 0);
+
+ /* TEXT1 in black */
cairo_move_to (cr, BORDER, BORDER + font_extents.ascent);
- cairo_show_text (cr, text);
+ cairo_set_source_rgb (cr, 0, 0, 0);
+ cairo_show_text (cr, TEXT1);
+ /* Draw TEXT2 three times with three different foreground colors.
+ * This checks that cairo uses the foreground color and does not cache
+ * glyph images when the foreground color changes.
+ */
+ cairo_show_text (cr, TEXT2);
+ cairo_set_source_rgb (cr, 0, 0.5, 0);
+ cairo_show_text (cr, TEXT2);
+ cairo_set_source_rgb (cr, 0.2, 0.5, 0.5);
+ cairo_show_text (cr, TEXT2);
/* filled version of text in light blue */
cairo_set_source_rgb (cr, 0, 0, 1);
cairo_move_to (cr, BORDER, BORDER + font_extents.height + BORDER + font_extents.ascent);
- cairo_text_path (cr, text);
+ cairo_text_path (cr, full_text);
cairo_fill (cr);
return CAIRO_TEST_SUCCESS;
diff --git a/test/user-font.c b/test/user-font.c
index d02a90f4d..a8aed23b3 100644
--- a/test/user-font.c
+++ b/test/user-font.c
@@ -34,7 +34,7 @@
#define BORDER 10
#define TEXT_SIZE 64
-#define WIDTH (TEXT_SIZE * 15 + 2*BORDER)
+#define WIDTH (TEXT_SIZE * 16 + 2*BORDER)
#ifndef ROTATED
#define HEIGHT ((TEXT_SIZE + 2*BORDER)*3)
#else
@@ -42,7 +42,7 @@
#endif
#define TEXT1 "cairo user-font."
-#define TEXT2 " zg."
+#define TEXT2 " zg"
#define END_GLYPH 0
#define STROKE 126
@@ -202,6 +202,24 @@ _user_font_face_create (cairo_font_face_t **out, cairo_bool_t color_render)
return CAIRO_STATUS_SUCCESS;
}
+static void
+draw_line (cairo_t *cr)
+{
+ /* TEXT1 in black */
+ cairo_set_source_rgb (cr, 0, 0, 0);
+ cairo_show_text (cr, TEXT1);
+
+ /* Draw TEXT2 three times with three different foreground colors.
+ * This checks that cairo uses the foreground color and does not cache
+ * glyph images when the foreground color changes.
+ */
+ cairo_show_text (cr, TEXT2);
+ cairo_set_source_rgb (cr, 0, 0.5, 0);
+ cairo_show_text (cr, TEXT2);
+ cairo_set_source_rgb (cr, 0.2, 0.5, 0.5);
+ cairo_show_text (cr, TEXT2);
+}
+
static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
@@ -214,6 +232,7 @@ draw (cairo_t *cr, int width, int height)
strcpy(full_text, TEXT1);
strcat(full_text, TEXT2);
strcat(full_text, TEXT2);
+ strcat(full_text, TEXT2);
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_paint (cr);
@@ -260,21 +279,14 @@ draw (cairo_t *cr, int width, int height)
cairo_set_line_width (cr, 2);
cairo_stroke (cr);
- /* First line. Text in black, except first "zg." in green */
- cairo_set_source_rgb (cr, 0, 0, 0);
+ /* First line. TEXT1 in black. TEXT2 in different colors. */
cairo_move_to (cr, BORDER, BORDER + font_extents.ascent);
- cairo_show_text (cr, TEXT1);
- cairo_set_source_rgb (cr, 0, 1, 0);
- cairo_show_text (cr, TEXT2);
- cairo_set_source_rgb (cr, 0, 0, 0);
- cairo_show_text (cr, TEXT2);
+ draw_line (cr);
- /* Now draw the second line using the render_color_glyph callback. The
- * output should be the same because same render function is used
- * and the render function does not set a color. This exercises
- * the paint color glyph with foreground color code path and
- * ensures cairo updates the glyph image when the foreground color
- * changes.
+ /* Now draw the second line using the render_color_glyph
+ * callback. The text should be all black because the default
+ * color of render function is used instead of the foreground
+ * color.
*/
status = _user_font_face_create (&font_face, TRUE);
if (status) {
@@ -287,13 +299,8 @@ draw (cairo_t *cr, int width, int height)
cairo_set_font_size (cr, TEXT_SIZE);
- /* text in black, except first "zg." in green */
cairo_move_to (cr, BORDER, BORDER + font_extents.height + 2*BORDER + font_extents.ascent);
- cairo_show_text (cr, TEXT1);
- cairo_set_source_rgb (cr, 0, 1, 0);
- cairo_show_text (cr, TEXT2);
- cairo_set_source_rgb (cr, 0, 0, 0);
- cairo_show_text (cr, TEXT2);
+ draw_line (cr);
/* Third line. Filled version of text in blue */
cairo_set_source_rgb (cr, 0, 0, 1);
diff --git a/util/Makefile.am b/util/Makefile.am
deleted file mode 100644
index 3b25f6159..000000000
--- a/util/Makefile.am
+++ /dev/null
@@ -1,98 +0,0 @@
-include $(top_srcdir)/build/Makefile.am.common
-
-SUBDIRS = . cairo-missing
-
-if CAIRO_HAS_GOBJECT_FUNCTIONS
-SUBDIRS += cairo-gobject
-endif
-
-if CAIRO_HAS_INTERPRETER
-SUBDIRS += cairo-script
-endif
-
-if CAIRO_HAS_TRACE
-SUBDIRS += cairo-trace
-if CAIRO_HAS_DLSYM
-if CAIRO_HAS_SCRIPT_SURFACE
-if CAIRO_HAS_TEE_SURFACE
-SUBDIRS += cairo-fdr
-endif
-endif
-endif
-endif
-
-if BUILD_SPHINX
-if CAIRO_HAS_DLSYM
-if CAIRO_HAS_SCRIPT_SURFACE
-if CAIRO_HAS_TEE_SURFACE
-SUBDIRS += cairo-sphinx
-endif
-endif
-endif
-endif
-
-AM_CPPFLAGS = -I$(top_srcdir)/src \
- -I$(top_builddir)/src \
- -I$(top_srcdir)/util/cairo-script \
- $(CAIRO_CFLAGS)
-
-EXTRA_PROGRAMS += show-contour show-traps show-edges show-polygon show-events
-if CAIRO_HAS_INTERPRETER
-EXTRA_PROGRAMS += trace-to-xml xml-to-trace
-endif
-
-trace_to_xml_LDADD = cairo-script/libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LDADD)
-
-xml_to_trace_LDADD = -lexpat
-
-show_traps_SOURCES = show-traps.c
-show_traps_CFLAGS = $(gtk_CFLAGS)
-#show_traps_LDADD = $(top_builddir)/src/libcairo.la $(gtk_LIBS)
-show_traps_LDADD = $(gtk_LIBS)
-
-show_polygon_SOURCES = show-polygon.c
-show_polygon_CFLAGS = $(gtk_CFLAGS)
-#show_polygon_LDADD = $(top_builddir)/src/libcairo.la $(gtk_LIBS)
-show_polygon_LDADD = $(gtk_LIBS)
-
-show_edges_SOURCES = show-edges.c
-show_edges_CFLAGS = $(gtk_CFLAGS)
-#show_edges_LDADD = $(top_builddir)/src/libcairo.la $(gtk_LIBS)
-show_edges_LDADD = $(gtk_LIBS)
-
-show_contour_SOURCES = show-contour.c
-show_contour_CFLAGS = $(gtk_CFLAGS)
-#show_contour_LDADD = $(top_builddir)/src/libcairo.la $(gtk_LIBS)
-show_contour_LDADD = $(gtk_LIBS)
-
-show_events_SOURCES = show-events.c
-show_events_CFLAGS = $(gtk_CFLAGS)
-#show_events_LDADD = $(top_builddir)/src/libcairo.la $(gtk_LIBS)
-show_events_LDADD = $(gtk_LIBS)
-
-util: malloc-stats.so
-
-.la.so:
- $(RM) $@
- $(LN_S) .libs/$*.so $@
-
-CLEANFILES += *.so
-
-# The -rpath is needed to build shared objects that are not installed,
-# ie. with EXTRA_LTLIBRARIES
-AM_LDFLAGS = -module -avoid-version -export-dynamic -rpath /dev/null
-
-EXTRA_LTLIBRARIES += malloc-stats.la
-
-if HAVE_GTK
-EXTRA_PROGRAMS += font-view
-font_view_CFLAGS = $(gtk_CFLAGS)
-font_view_LDADD = ../src/libcairo.la $(gtk_LIBS)
-endif
-
-EXTRA_DIST += \
- COPYING \
- xr2cairo \
- cairo-api-update \
- cairo-view \
- waterfall
diff --git a/util/cairo-fdr/Makefile.am b/util/cairo-fdr/Makefile.am
deleted file mode 100644
index 5cd542219..000000000
--- a/util/cairo-fdr/Makefile.am
+++ /dev/null
@@ -1,15 +0,0 @@
-cairolibdir = $(libdir)/cairo
-
-#bin_SCRIPTS = cairo-fdr
-cairolib_LTLIBRARIES = cairo-fdr.la
-
-AM_CPPFLAGS = -I$(top_srcdir)/src \
- -I$(top_builddir)/src
-
-cairo_fdr_la_SOURCES = fdr.c
-cairo_fdr_la_CPPFLAGS = $(AM_CPPFLAGS)
-cairo_fdr_la_CFLAGS = $(CAIRO_CFLAGS)
-cairo_fdr_la_LDFLAGS = -module -no-undefined -avoid-version
-if CAIRO_HAS_DL
-cairo_fdr_la_LIBADD = -ldl
-endif
diff --git a/util/cairo-gobject/Makefile.am b/util/cairo-gobject/Makefile.am
deleted file mode 100644
index 22c1a278a..000000000
--- a/util/cairo-gobject/Makefile.am
+++ /dev/null
@@ -1,15 +0,0 @@
-lib_LTLIBRARIES = libcairo-gobject.la
-
-AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src
-
-cairoincludedir=$(includedir)/cairo
-cairoinclude_HEADERS = cairo-gobject.h
-libcairo_gobject_la_SOURCES = \
- cairo-gobject-enums.c \
- cairo-gobject-structs.c \
- $(NULL)
-
-libcairo_gobject_la_CFLAGS = $(CAIRO_CFLAGS) $(GOBJECT_CFLAGS)
-libcairo_gobject_la_LDFLAGS = -version-info $(CAIRO_LIBTOOL_VERSION_INFO) -no-undefined $(export_symbols)
-libcairo_gobject_la_LIBADD = $(top_builddir)/src/libcairo.la $(CAIRO_LIBS) $(GOBJECT_LIBS)
-
diff --git a/util/cairo-missing/Makefile.am b/util/cairo-missing/Makefile.am
deleted file mode 100644
index 907861026..000000000
--- a/util/cairo-missing/Makefile.am
+++ /dev/null
@@ -1,10 +0,0 @@
-include $(top_srcdir)/util/cairo-missing/Makefile.sources
-
-AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src
-
-noinst_LTLIBRARIES = libcairo-missing.la
-
-libcairo_missing_la_SOURCES = \
- $(libcairo_missing_sources) \
- $(libcairo_missing_headers) \
- $(NULL)
diff --git a/util/cairo-missing/Makefile.sources b/util/cairo-missing/Makefile.sources
deleted file mode 100644
index 1a306314a..000000000
--- a/util/cairo-missing/Makefile.sources
+++ /dev/null
@@ -1,8 +0,0 @@
-libcairo_missing_sources = \
- strndup.c \
- getline.c \
- $(NULL)
-
-libcairo_missing_headers = \
- cairo-missing.h \
- $(NULL)
diff --git a/util/cairo-missing/Makefile.win32 b/util/cairo-missing/Makefile.win32
deleted file mode 100644
index c2c5bc01e..000000000
--- a/util/cairo-missing/Makefile.win32
+++ /dev/null
@@ -1,10 +0,0 @@
-top_srcdir = ../../
-include $(top_srcdir)/build/Makefile.win32.common
-include $(top_srcdir)/util/cairo-missing/Makefile.sources
-
-all: inform $(CFG)/libcairo-missing.lib
-
-libcairo_missing_OBJECTS = $(patsubst %.c, $(CFG)/%-static.obj, $(libcairo_missing_sources))
-
-$(CFG)/libcairo-missing.lib: $(libcairo_missing_OBJECTS)
- @$(AR) $(CAIRO_ARFLAGS) -OUT:$@ $^
diff --git a/util/cairo-missing/cairo-missing.h b/util/cairo-missing/cairo-missing.h
index 741b498a8..5d947163f 100644
--- a/util/cairo-missing/cairo-missing.h
+++ b/util/cairo-missing/cairo-missing.h
@@ -38,7 +38,6 @@
#include <sys/types.h>
#ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#if !defined(_SSIZE_T_DEFINED) && !defined(_SSIZE_T_)
diff --git a/util/cairo-missing/strndup.c b/util/cairo-missing/strndup.c
index 280ea3017..049802b76 100644
--- a/util/cairo-missing/strndup.c
+++ b/util/cairo-missing/strndup.c
@@ -37,15 +37,19 @@ char *
strndup (const char *s,
size_t n)
{
+ const char *end;
size_t len;
char *sdup;
if (s == NULL)
return NULL;
- len = strlen (s);
- if (len > n)
+ end = memchr (s, 0, n);
+ if (end)
+ len = end - s;
+ else
len = n;
+
sdup = (char *) _cairo_malloc (len + 1);
if (sdup != NULL) {
memcpy (sdup, s, len);
diff --git a/util/cairo-script/Makefile.am b/util/cairo-script/Makefile.am
deleted file mode 100644
index 82519fb31..000000000
--- a/util/cairo-script/Makefile.am
+++ /dev/null
@@ -1,37 +0,0 @@
-include $(top_srcdir)/util/cairo-script/Makefile.sources
-
-SUBDIRS = examples
-
-lib_LTLIBRARIES = libcairo-script-interpreter.la
-EXTRA_PROGRAMS = csi-replay csi-exec csi-bind
-
-AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src
-
-cairoincludedir=$(includedir)/cairo
-cairoinclude_HEADERS = cairo-script-interpreter.h
-libcairo_script_interpreter_la_SOURCES = \
- $(libcairo_script_interpreter_sources) \
- $(libcairo_script_interpreter_headers) \
- $(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) $(lzo_LIBS) -lz
-
-pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = cairo-script-interpreter.pc
-
-csi_replay_SOURCES = csi-replay.c
-csi_replay_CFLAGS = $(CAIRO_CFLAGS)
-csi_replay_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
-
-csi_exec_SOURCES = csi-exec.c
-csi_exec_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
-
-if CAIRO_HAS_SCRIPT_SURFACE
-EXTRA_PROGRAMS += csi-trace
-csi_trace_SOURCES = csi-trace.c
-csi_trace_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
-endif
-
-EXTRA_DIST = \
- COPYING
diff --git a/util/cairo-script/Makefile.sources b/util/cairo-script/Makefile.sources
deleted file mode 100644
index fd73a17cf..000000000
--- a/util/cairo-script/Makefile.sources
+++ /dev/null
@@ -1,13 +0,0 @@
-libcairo_script_interpreter_sources = \
- 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_headers = \
- cairo-script-private.h \
- $(NULL)
diff --git a/util/cairo-script/Makefile.win32 b/util/cairo-script/Makefile.win32
deleted file mode 100644
index 0aef981c1..000000000
--- a/util/cairo-script/Makefile.win32
+++ /dev/null
@@ -1,10 +0,0 @@
-top_srcdir = ../../
-include $(top_srcdir)/build/Makefile.win32.common
-include $(top_srcdir)/util/cairo-script/Makefile.sources
-
-all: inform $(CFG)/libcairo-script-interpreter.lib
-
-libcairo_script_interpreter_OBJECTS = $(patsubst %.c, $(CFG)/%-static.obj, $(libcairo_script_interpreter_sources))
-
-$(CFG)/libcairo-script-interpreter.lib: $(libcairo_script_interpreter_OBJECTS)
- @$(AR) $(CAIRO_ARFLAGS) -OUT:$@ $(libcairo_script_interpreter_OBJECTS)
diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c
index d0452d338..21fba5cc7 100644
--- a/util/cairo-script/cairo-script-operators.c
+++ b/util/cairo-script/cairo-script-operators.c
@@ -6799,6 +6799,9 @@ _integer_constants[] = {
{ "RGB16_565", CAIRO_FORMAT_RGB16_565 },
{ "RGB24", CAIRO_FORMAT_RGB24 },
{ "ARGB32", CAIRO_FORMAT_ARGB32 },
+ { "RGB30", CAIRO_FORMAT_RGB30 },
+ { "RGB96F", CAIRO_FORMAT_RGB96F },
+ { "RGBA128F", CAIRO_FORMAT_RGBA128F },
{ "INVALID", CAIRO_FORMAT_INVALID },
{ NULL, 0 }
diff --git a/util/cairo-script/csi-replay.c b/util/cairo-script/csi-replay.c
index 9d9be72c2..4460d6414 100644
--- a/util/cairo-script/csi-replay.c
+++ b/util/cairo-script/csi-replay.c
@@ -206,64 +206,6 @@ _xrender_surface_create (void *closure,
#endif
#endif
-#if CAIRO_HAS_GL_GLX_SURFACE
-#include <cairo-gl.h>
-static cairo_gl_context_t *
-_glx_get_context (cairo_content_t content)
-{
- static cairo_gl_context_t *context;
-
- if (context == NULL) {
- int rgba_attribs[] = {
- GLX_RGBA,
- GLX_RED_SIZE, 1,
- GLX_GREEN_SIZE, 1,
- GLX_BLUE_SIZE, 1,
- GLX_ALPHA_SIZE, 1,
- GLX_DOUBLEBUFFER,
- None
- };
- XVisualInfo *visinfo;
- GLXContext gl_ctx;
- Display *dpy;
-
- dpy = XOpenDisplay (NULL);
- if (dpy == NULL) {
- fprintf (stderr, "Failed to open display.\n");
- exit (1);
- }
-
- visinfo = glXChooseVisual (dpy, DefaultScreen (dpy), rgba_attribs);
- if (visinfo == NULL) {
- fprintf (stderr, "Failed to create RGBA, double-buffered visual\n");
- exit (1);
- }
-
- gl_ctx = glXCreateContext (dpy, visinfo, NULL, True);
- XFree (visinfo);
-
- context = cairo_glx_context_create (dpy, gl_ctx);
- }
-
- return context;
-}
-
-static cairo_surface_t *
-_glx_surface_create (void *closure,
- cairo_content_t content,
- double width, double height,
- long uid)
-{
- if (width == 0)
- width = 1;
- if (height == 0)
- height = 1;
-
- return cairo_gl_surface_create (_glx_get_context (content),
- content, width, height);
-}
-#endif
-
#if CAIRO_HAS_PDF_SURFACE
#include <cairo-pdf.h>
static cairo_surface_t *
@@ -341,9 +283,6 @@ main (int argc, char **argv)
#if CAIRO_HAS_XLIB_XRENDER_SURFACE
{ "--xrender", _xrender_surface_create },
#endif
-#if CAIRO_HAS_GL_GLX_SURFACE
- { "--glx", _glx_surface_create },
-#endif
#if CAIRO_HAS_XLIB_SURFACE
{ "--xlib", _xlib_surface_create },
#endif
diff --git a/util/cairo-script/examples/Makefile.am b/util/cairo-script/examples/Makefile.am
deleted file mode 100644
index a87f02d9a..000000000
--- a/util/cairo-script/examples/Makefile.am
+++ /dev/null
@@ -1,10 +0,0 @@
-EXTRA_DIST = \
- dragon.cs \
- hilbert.cs \
- infinichess.cs \
- interference.cs \
- pythagoras-tree.cs \
- sierpinski.cs \
- wedgeAnnulus_crop_ybRings.cs \
- world-map.cs \
- zrusin.cs
diff --git a/util/cairo-sphinx/Makefile.am b/util/cairo-sphinx/Makefile.am
deleted file mode 100644
index 3c1126320..000000000
--- a/util/cairo-sphinx/Makefile.am
+++ /dev/null
@@ -1,43 +0,0 @@
-cairolibdir = $(libdir)/cairo
-
-cairolib_LTLIBRARIES = cairo-sphinx.la
-bin_PROGRAMS = cairo-sphinx
-
-AM_CPPFLAGS = -I$(top_srcdir)/src \
- -I$(top_builddir)/src \
- -I$(top_srcdir)/boilerplate \
- -I$(top_srcdir)/util/cairo-script
-
-cairo_sphinx_la_SOURCES = fdr.c
-cairo_sphinx_la_CPPFLAGS = $(AM_CPPFLAGS)
-cairo_sphinx_la_CFLAGS = $(CAIRO_CFLAGS)
-cairo_sphinx_la_LDFLAGS = -module -no-undefined -avoid-version
-if CAIRO_HAS_DL
-cairo_sphinx_la_LIBADD = -ldl
-endif
-
-cairo_sphinx_SOURCES = sphinx.c
-cairo_sphinx_CPPFLAGS = $(AM_CPPFLAGS) -DLIBDIR="\"$(cairolibdir)\""
-cairo_sphinx_CFLAGS = $(CAIRO_CFLAGS) $(real_pthread_CFLAGS) $(glib_CFLAGS)
-cairo_sphinx_LDADD = \
- $(real_pthread_LIBS) \
- $(top_builddir)/util/cairo-script/libcairo-script-interpreter.la \
- $(top_builddir)/boilerplate/libcairoboilerplate.la \
- $(top_builddir)/src/libcairo.la \
- $(glib_LIBS) \
- $(CAIRO_LDADD) \
- $(shm_LIBS)
-cairo_sphinx_DEPENDENCIES = \
- $(top_builddir)/util/cairo-script/libcairo-script-interpreter.la \
- $(top_builddir)/boilerplate/libcairoboilerplate.la \
- $(top_builddir)/src/libcairo.la
-
-# Install rules to rebuild the libraries and add explicit dependencies
-$(top_builddir)/boilerplate/libcairoboilerplate.la: $(top_builddir)/src/libcairo.la
- cd $(top_builddir)/boilerplate && $(MAKE) $(AM_MAKEFLAGS) libcairoboilerplate.la
-
-$(top_builddir)/src/libcairo.la:
- cd $(top_builddir)/src && $(MAKE) $(AM_MAKEFLAGS) libcairo.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
diff --git a/util/cairo-sphinx/sphinx.c b/util/cairo-sphinx/sphinx.c
index 9e248aff1..741e406d6 100644
--- a/util/cairo-sphinx/sphinx.c
+++ b/util/cairo-sphinx/sphinx.c
@@ -559,7 +559,8 @@ compare_images (cairo_surface_t *a,
int channel;
for (channel = 0; channel < 4; channel++) {
- unsigned va, vb, diff;
+ int va, vb;
+ unsigned diff;
va = (ua[x] >> (channel*8)) & 0xff;
vb = (ub[x] >> (channel*8)) & 0xff;
@@ -588,7 +589,8 @@ compare_images (cairo_surface_t *a,
int channel;
for (channel = 0; channel < 3; channel++) {
- unsigned va, vb, diff;
+ int va, vb;
+ unsigned diff;
va = (ua[x] >> (channel*8)) & 0xff;
vb = (ub[x] >> (channel*8)) & 0xff;
@@ -614,7 +616,7 @@ compare_images (cairo_surface_t *a,
if (aa[x] != bb[x]) {
unsigned diff = abs (aa[x] - bb[x]);
if (diff > 1) {
- uint8_t va, vb;
+ int8_t va, vb;
va = get_median_8 (x, y, aa, width, height, stride);
vb = get_median_8 (x, y, bb, width, height, stride);
@@ -642,6 +644,9 @@ compare_images (cairo_surface_t *a,
case CAIRO_FORMAT_INVALID:
case CAIRO_FORMAT_RGB16_565: /* XXX */
+ case CAIRO_FORMAT_RGB30:
+ case CAIRO_FORMAT_RGB96F:
+ case CAIRO_FORMAT_RGBA128F:
break;
}
diff --git a/util/cairo-trace/Makefile.am b/util/cairo-trace/Makefile.am
deleted file mode 100644
index a0091f882..000000000
--- a/util/cairo-trace/Makefile.am
+++ /dev/null
@@ -1,40 +0,0 @@
-cairolibdir = $(libdir)/cairo
-cairooutdir = $(localstatedir)/lib/cairo-trace
-
-bin_SCRIPTS = cairo-trace
-cairolib_LTLIBRARIES = libcairo-trace.la
-
-AM_CPPFLAGS = -I$(top_srcdir)/src \
- -I$(top_builddir)/src
-
-libcairo_trace_la_SOURCES = trace.c
-libcairo_trace_la_CPPFLAGS = -DCAIRO_TRACE_OUTDIR="\"$(cairooutdir)\"" \
- $(AM_CPPFLAGS)
-libcairo_trace_la_CFLAGS = $(CAIRO_CFLAGS) $(real_pthread_CFLAGS)
-libcairo_trace_la_LDFLAGS = -module -no-undefined -avoid-version
-
-libcairo_trace_la_LIBADD = $(real_pthread_LIBS) -lz
-if CAIRO_HAS_DL
-libcairo_trace_la_LIBADD += -ldl
-endif
-
-if CAIRO_HAS_SYMBOL_LOOKUP
-libcairo_trace_la_SOURCES += \
- lookup-symbol.c \
- lookup-symbol.h
-libcairo_trace_la_LIBADD += $(BFD_LIBS)
-endif
-
-
-system-install: install
- -mkdir -p $(cairooutdir)
- -chmod 01777 $(cairooutdir)
- grep -sq $(cairolibdir)/libcairo-trace.so /etc/ld.so.preload || echo $(cairolibdir)/libcairo-trace.so >> /etc/ld.so.preload
-
-system-uninstall: uninstall
- sed -e '/libcairo-trace.so/d' < /etc/ld.so.preload > /tmp/ld.so.preload && mv /tmp/ld.so.preload /etc/ld.so.preload;
-
-EXTRA_DIST = \
- COPYING \
- COPYING-GPL-3 \
- cairo-trace.in
diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c
index 61e57f4d8..7ccdc41dc 100644
--- a/util/cairo-trace/trace.c
+++ b/util/cairo-trace/trace.c
@@ -1600,6 +1600,7 @@ _status_to_string (cairo_status_t status)
f(WIN32_GDI_ERROR);
f(TAG_ERROR);
f(DWRITE_ERROR);
+ f(SVG_FONT_ERROR);
case CAIRO_STATUS_LAST_STATUS:
break;
}
@@ -5322,191 +5323,3 @@ cairo_recording_surface_create (cairo_content_t content,
_exit_trace ();
return ret;
}
-
-#if CAIRO_HAS_GL_SURFACE || CAIRO_HAS_GLESV2_SURFACE
-#include <cairo-gl.h>
-cairo_surface_t *
-cairo_gl_surface_create (cairo_device_t *abstract_device,
- cairo_content_t content,
- int width,
- int height)
-{
- cairo_surface_t *ret;
-
- _enter_trace ();
-
- ret = DLCALL (cairo_gl_surface_create, abstract_device, content, width, height);
-
- _emit_line_info ();
- if (_write_lock ()) {
- Object *obj = _create_surface (ret);
-
- _trace_printf ("dict\n"
- " /type /gl 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,
- obj->token);
- obj->width = width;
- obj->height = height;
- obj->defined = TRUE;
- _push_object (obj);
- dump_stack(__func__);
- _write_unlock ();
- }
-
- _exit_trace ();
- return ret;
-}
-
-cairo_surface_t *
-cairo_gl_surface_create_for_texture (cairo_device_t *abstract_device,
- cairo_content_t content,
- unsigned int tex,
- int width,
- int height)
-{
- cairo_surface_t *ret;
-
- _enter_trace ();
-
- ret = DLCALL (cairo_gl_surface_create_for_texture, abstract_device, content, tex, width, height);
-
- _emit_line_info ();
- if (_write_lock ()) {
- Object *obj = _create_surface (ret);
-
- _trace_printf ("dict\n"
- " /type /gl 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,
- obj->token);
- obj->width = width;
- obj->height = height;
- obj->defined = TRUE;
- _push_object (obj);
- dump_stack(__func__);
- _write_unlock ();
- }
-
- _exit_trace ();
- return ret;
-}
-
-#if CAIRO_HAS_GLX_FUNCTIONS
-cairo_surface_t *
-cairo_gl_surface_create_for_window (cairo_device_t *device,
- Window win,
- int width, int height)
-{
- cairo_surface_t *ret;
-
- _enter_trace ();
-
- ret = DLCALL (cairo_gl_surface_create_for_window, device, win, width, height);
-
- _emit_line_info ();
- if (_write_lock ()) {
- Object *obj = _create_surface (ret);
-
- _trace_printf ("dict\n"
- " /type /gl set\n"
- " /width %d set\n"
- " /height %d set\n"
- " surface dup /s%ld exch def\n",
- width, height,
- obj->token);
- obj->width = width;
- obj->height = height;
- obj->defined = TRUE;
- _push_object (obj);
- dump_stack(__func__);
- _write_unlock ();
- }
-
- _exit_trace ();
- return ret;
-}
-#endif
-
-#if CAIRO_HAS_WGL_FUNCTIONS
-cairo_surface_t *
-cairo_gl_surface_create_for_dc (cairo_device_t *device,
- HDC dc,
- int width,
- int height)
-{
- cairo_surface_t *ret;
-
- _enter_trace ();
-
- ret = DLCALL (cairo_gl_surface_create_for_dc, device, dc, width, height);
-
- _emit_line_info ();
- if (_write_lock ()) {
- Object *obj = _create_surface (ret);
-
- _trace_printf ("dict\n"
- " /type /gl set\n"
- " /width %d set\n"
- " /height %d set\n"
- " surface dup /s%ld exch def\n",
- width, height,
- obj->token);
- obj->width = width;
- obj->height = height;
- obj->defined = TRUE;
- _push_object (obj);
- dump_stack(__func__);
- _write_unlock ();
- }
-
- _exit_trace ();
- return ret;
-}
-#endif
-
-#if CAIRO_HAS_EGL_FUNCTIONS
-cairo_surface_t *
-cairo_gl_surface_create_for_egl (cairo_device_t *device,
- EGLSurface egl,
- int width,
- int height)
-{
- cairo_surface_t *ret;
-
- _enter_trace ();
-
- ret = DLCALL (cairo_gl_surface_create_for_egl, device, egl, width, height);
-
- _emit_line_info ();
- if (_write_lock ()) {
- Object *obj = _create_surface (ret);
-
- _trace_printf ("dict\n"
- " /type /gl set\n"
- " /width %d set\n"
- " /height %d set\n"
- " surface dup /s%ld exch def\n",
- width, height,
- obj->token);
- obj->width = width;
- obj->height = height;
- obj->defined = TRUE;
- _push_object (obj);
- dump_stack(__func__);
- _write_unlock ();
- }
-
- _exit_trace ();
- return ret;
-}
-#endif
-#endif
diff --git a/util/malloc-stats.c b/util/malloc-stats.c
index cf712bd3a..a086b0543 100644
--- a/util/malloc-stats.c
+++ b/util/malloc-stats.c
@@ -173,12 +173,18 @@ func_stats_add (const void *caller, int is_realloc, size_t size)
#include <dlfcn.h>
static void *(*old_malloc)(size_t);
+static void *(*old_calloc)(size_t, size_t);
static void *(*old_realloc)(void *, size_t);
static int enable_hook = 0;
+static void init(void);
+
void *
malloc(size_t size)
{
+ if (!old_malloc)
+ init ();
+
if (enable_hook) {
enable_hook = 0;
void *caller = __builtin_return_address(0);
@@ -190,8 +196,27 @@ malloc(size_t size)
}
void *
+calloc(size_t nmemb, size_t size)
+{
+ if (!old_calloc)
+ init ();
+
+ if (enable_hook) {
+ enable_hook = 0;
+ void *caller = __builtin_return_address(0);
+ func_stats_add (caller, 0, nmemb * size);
+ enable_hook = 1;
+ }
+
+ return old_calloc (nmemb, size);
+}
+
+void *
realloc(void *ptr, size_t size)
{
+ if (!old_malloc)
+ init ();
+
if (enable_hook) {
enable_hook = 0;
void *caller = __builtin_return_address(0);
@@ -202,7 +227,7 @@ realloc(void *ptr, size_t size)
return old_realloc (ptr, size);
}
-static void __attribute__ ((constructor))
+static void
init(void)
{
old_malloc = dlsym(RTLD_NEXT, "malloc");
@@ -210,6 +235,11 @@ init(void)
fprintf(stderr, "%s\n", dlerror());
exit(1);
}
+ old_calloc = dlsym(RTLD_NEXT, "calloc");
+ if (!old_calloc) {
+ fprintf(stderr, "%s\n", dlerror());
+ exit(1);
+ }
old_realloc = dlsym(RTLD_NEXT, "realloc");
if (!old_realloc) {
fprintf(stderr, "%s\n", dlerror());
diff --git a/util/meson.build b/util/meson.build
index 5cc209cc9..3c3bf26c2 100644
--- a/util/meson.build
+++ b/util/meson.build
@@ -42,14 +42,6 @@ if gtk_dep.found()
]
endif
-if feature_conf.get('CAIRO_HAS_XML_SURFACE', 0) == 1
- expat_dep = dependency('expat', fallback: ['expat', 'expat_dep'])
- cairo_utils += [
- ['trace-to-xml.c', {'deps': [expat_dep]}],
- ['xml-to-trace.c', {'deps': [expat_dep]}],
- ]
-endif
-
foreach util : cairo_utils
exe_name = util[0].split('.')[0]
util_deps = util.get(1, {}).get('deps', [])
diff --git a/util/trace-to-xml.c b/util/trace-to-xml.c
deleted file mode 100644
index b4295fbdd..000000000
--- a/util/trace-to-xml.c
+++ /dev/null
@@ -1,76 +0,0 @@
-#include "config.h"
-
-#include <cairo-xml.h>
-#include <cairo-script-interpreter.h>
-
-#include <stdio.h>
-#include <string.h>
-
-static cairo_surface_t *
-_surface_create (void *_closure,
- cairo_content_t content,
- double width, double height,
- long uid)
-{
- cairo_surface_t **closure = _closure;
- cairo_surface_t *surface;
- cairo_rectangle_t extents;
-
- extents.x = extents.y = 0;
- extents.width = width;
- extents.height = height;
- surface = cairo_recording_surface_create (content, &extents);
- if (*closure == NULL)
- *closure = cairo_surface_reference (surface);
-
- return surface;
-}
-
-static cairo_status_t
-stdio_write (void *closure, const unsigned char *data, unsigned len)
-{
- if (fwrite (data, len, 1, closure) == 1)
- return CAIRO_STATUS_SUCCESS;
- else
- return CAIRO_STATUS_WRITE_ERROR;
-}
-
-int
-main (int argc, char **argv)
-{
- cairo_surface_t *surface = NULL;
- const cairo_script_interpreter_hooks_t hooks = {
- .closure = &surface,
- .surface_create = _surface_create,
- };
- cairo_script_interpreter_t *csi;
- FILE *in = stdin, *out = stdout;
-
- if (argc >= 2 && strcmp (argv[1], "-"))
- in = fopen (argv[1], "r");
- if (argc >= 3 && strcmp (argv[2], "-"))
- out = fopen (argv[2], "w");
-
- csi = cairo_script_interpreter_create ();
- cairo_script_interpreter_install_hooks (csi, &hooks);
- cairo_script_interpreter_feed_stream (csi, in);
- cairo_script_interpreter_finish (csi);
- cairo_script_interpreter_destroy (csi);
-
- if (surface != NULL) {
- cairo_device_t *xml;
-
- xml = cairo_xml_create_for_stream (stdio_write, out);
- cairo_xml_for_recording_surface (xml, surface);
- cairo_device_destroy (xml);
-
- cairo_surface_destroy (surface);
- }
-
- if (in != stdin)
- fclose (in);
- if (out != stdout)
- fclose (out);
-
- return 0;
-}
diff --git a/util/xml-to-trace.c b/util/xml-to-trace.c
deleted file mode 100644
index 13b7e5706..000000000
--- a/util/xml-to-trace.c
+++ /dev/null
@@ -1,263 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <expat.h>
-#include <assert.h>
-
-struct trace {
- FILE *stream;
- char tail_buf[80];
- const char *tail;
- int surface_depth;
-};
-
-static void
-start_element (void *closure,
- const char *element,
- const char **attr)
-{
- struct trace *trace = closure;
-
- if (strcmp (element, "surface") == 0) {
- const char *content = "COLOR_ALPHA";
- const char *width = NULL;
- const char *height = NULL;
-
- while (*attr) {
- if (strcmp (*attr, "content") == 0) {
- content = *++attr;
- } else if (strcmp (*attr, "width") == 0) {
- width = *++attr;
- } else if (strcmp (*attr, "height") == 0) {
- height = *++attr;
- } else {
- fprintf (stderr, "unknown surface attribute '%s'\n", *attr);
- attr++;
- }
- attr++;
- }
-
- fprintf (trace->stream, "<< /content //%s", content);
- if (width != NULL && height != NULL) {
- fprintf (trace->stream,
- " /width %s /height %s",
- width, height);
- }
- if (trace->surface_depth++ == 0)
- fprintf (trace->stream, " >> surface context\n");
- else
- fprintf (trace->stream, " >> surface dup context\n");
- } else if (strcmp (element, "image") == 0) {
- const char *format = "ARGB24";
- const char *width = NULL;
- const char *height = NULL;
-
- while (*attr) {
- if (strcmp (*attr, "format") == 0) {
- format = *++attr;
- } else if (strcmp (*attr, "width") == 0) {
- width = *++attr;
- } else if (strcmp (*attr, "height") == 0) {
- height = *++attr;
- } else {
- fprintf (stderr, "unknown image attribute '%s'\n", *attr);
- attr++;
- }
- attr++;
- }
-
- fprintf (trace->stream,
- "<< /format //%s /width %s /height %s /mime-type (image/png) /source <{",
- format, width, height);
- assert (trace->tail == NULL);
- trace->tail = "}> >> image pattern\n";
- } else if (strcmp (element, "solid") == 0) {
- trace->tail = " rgba\n";
- } else if (strcmp (element, "linear") == 0) {
- const char *x1 = NULL;
- const char *x2 = NULL;
- const char *y1 = NULL;
- const char *y2 = NULL;
-
- while (*attr) {
- if (strcmp (*attr, "x1") == 0) {
- x1 = *++attr;
- } else if (strcmp (*attr, "x2") == 0) {
- x2 = *++attr;
- } else if (strcmp (*attr, "y1") == 0) {
- y1 = *++attr;
- } else if (strcmp (*attr, "y2") == 0) {
- y2 = *++attr;
- } else {
- fprintf (stderr, "unknown linear attribute '%s'\n", *attr);
- attr++;
- }
- attr++;
- }
-
- fprintf (trace->stream, "%s %s %s %s linear\n", x1, y1, x2, y2);
- } else if (strcmp (element, "radial") == 0) {
- const char *x1 = NULL;
- const char *y1 = NULL;
- const char *r1 = NULL;
- const char *y2 = NULL;
- const char *x2 = NULL;
- const char *r2 = NULL;
-
- while (*attr) {
- if (strcmp (*attr, "x1") == 0) {
- x1 = *++attr;
- } else if (strcmp (*attr, "y1") == 0) {
- y1 = *++attr;
- } else if (strcmp (*attr, "r1") == 0) {
- r1 = *++attr;
- } else if (strcmp (*attr, "x2") == 0) {
- x2 = *++attr;
- } else if (strcmp (*attr, "y2") == 0) {
- y2 = *++attr;
- } else if (strcmp (*attr, "r2") == 0) {
- r2 = *++attr;
- } else {
- fprintf (stderr, "unknown radial attribute '%s'\n", *attr);
- attr++;
- }
- attr++;
- }
-
- fprintf (trace->stream,
- "%s %s %s %s %s %s radial\n",
- x1, y1, r1, x2, y2, r2);
- } else if (strcmp (element, "matrix") == 0) {
- fprintf (trace->stream, "[ ");
- trace->tail = " ] set-matrix\n";
- } else if (strcmp (element, "extend") == 0) {
- trace->tail = " set-extend\n";
- } else if (strcmp (element, "filter") == 0) {
- trace->tail = " set-filter\n";
- } else if (strcmp (element, "operator") == 0) {
- trace->tail = " set-operator\n";
- } else if (strcmp (element, "tolerance") == 0) {
- trace->tail = " set-tolerance\n";
- } else if (strcmp (element, "fill-rule") == 0) {
- trace->tail = " set-fill-rule\n";
- } else if (strcmp (element, "line-cap") == 0) {
- trace->tail = " set-line-cap\n";
- } else if (strcmp (element, "line-join") == 0) {
- trace->tail = " set-line-join\n";
- } else if (strcmp (element, "line-width") == 0) {
- trace->tail = " set-line-width\n";
- } else if (strcmp (element, "miter-limit") == 0) {
- trace->tail = " set-miter-limit\n";
- } else if (strcmp (element, "antialias") == 0) {
- trace->tail = " set-antialias\n";
- } else if (strcmp (element, "color-stop") == 0) {
- trace->tail = " add-color-stop\n";
- } else if (strcmp (element, "path") == 0) {
- /* need to reset the matrix to identity before the path */
- fprintf (trace->stream, "identity set-matrix ");
- trace->tail = "\n";
- } else if (strcmp (element, "dash") == 0) {
- const char *offset = "0";
-
- while (*attr) {
- if (strcmp (*attr, "offset") == 0) {
- offset = *++attr;
- }
- attr++;
- }
-
- fprintf (trace->stream, "[");
- sprintf (trace->tail_buf, "] %s set-dash\n", offset);
- trace->tail = trace->tail_buf;
- } else {
- }
-}
-
-static void
-cdata (void *closure,
- const XML_Char *s,
- int len)
-{
- struct trace *trace = closure;
-
- if (trace->tail)
- fwrite (s, len, 1, trace->stream);
-}
-
-static void
-end_element (void *closure,
- const char *element)
-{
- struct trace *trace = closure;
-
- if (trace->tail) {
- fprintf (trace->stream, "%s", trace->tail);
- trace->tail = NULL;
- }
-
- if (strcmp (element, "paint") == 0) {
- fprintf (trace->stream, "paint\n");
- } else if (strcmp (element, "mask") == 0) {
- fprintf (trace->stream, "mask\n");
- } else if (strcmp (element, "stroke") == 0) {
- fprintf (trace->stream, "stroke\n");
- } else if (strcmp (element, "fill") == 0) {
- fprintf (trace->stream, "fill\n");
- } else if (strcmp (element, "glyphs") == 0) {
- fprintf (trace->stream, "show-glyphs\n");
- } else if (strcmp (element, "clip") == 0) {
- fprintf (trace->stream, "clip\n");
- } else if (strcmp (element, "source-pattern") == 0) {
- fprintf (trace->stream, "set-source\n");
- } else if (strcmp (element, "mask-pattern") == 0) {
- } else if (strcmp (element, "surface") == 0) {
- if (--trace->surface_depth == 0)
- fprintf (trace->stream, "pop\n");
- else
- fprintf (trace->stream, "pop pattern\n");
- }
-}
-
-int
-main (int argc, char **argv)
-{
- struct trace trace;
- XML_Parser p;
- char buf[8192];
- int done = 0;
- FILE *in = stdin;
-
- trace.stream = stdout;
- trace.tail = NULL;
- trace.surface_depth = 0;
-
- if (argc >= 2 && strcmp (argv[1], "-"))
- in = fopen (argv[1], "r");
- if (argc >= 3 && strcmp (argv[2], "-"))
- trace.stream = fopen (argv[2], "w");
-
- p = XML_ParserCreate (NULL);
- XML_SetUserData (p, &trace);
- XML_SetElementHandler (p, start_element, end_element);
- XML_SetCharacterDataHandler (p, cdata);
- do {
- int len;
-
- len = fread (buf, 1, sizeof (buf), in);
- done = feof (stdin);
-
- if (XML_Parse (p, buf, len, done) == XML_STATUS_ERROR) {
- fprintf (stderr, "Parse error at line %ld:\n%s\n",
- XML_GetCurrentLineNumber (p),
- XML_ErrorString (XML_GetErrorCode (p)));
- exit (-1);
- }
- } while (! done);
- XML_ParserFree (p);
-
- if (in != stdin)
- fclose (in);
- if (trace.stream != stdout)
- fclose (trace.stream);
-
- return 0;
-}
diff --git a/version.py b/version.py
index 7e0ded0d7..aabc20593 100755
--- a/version.py
+++ b/version.py
@@ -5,27 +5,49 @@
# Extracts the version from cairo-version.h for the meson build files.
#
import os
+import re
import sys
-if __name__ == '__main__':
- srcroot = os.path.dirname(__file__)
- version_major = None
- version_minor = None
- version_micro = None
+MAJOR_RE = re.compile(
+ r'^\s*#\s*define\s+CAIRO_VERSION_MAJOR\s+(?P<number>[0-9]+)\s*$',
+ re.UNICODE)
- f = open(os.path.join(srcroot, 'src', 'cairo-version.h'), 'r', encoding='utf-8')
+MINOR_RE = re.compile(
+ r'^\s*#\s*define\s+CAIRO_VERSION_MINOR\s+(?P<number>[0-9]+)\s*$',
+ re.UNICODE)
+
+MICRO_RE = re.compile(
+ r'^\s*#\s*define\s+CAIRO_VERSION_MICRO\s+(?P<number>[0-9]+)\s*$',
+ re.UNICODE)
+
+version_major = None
+version_minor = None
+version_micro = None
+
+srcroot = os.path.dirname(__file__)
+version_h = os.path.join(srcroot, "src", "cairo-version.h")
+
+with open(version_h, "r", encoding="utf-8") as f:
for line in f:
- if line.startswith('#define CAIRO_VERSION_MAJOR '):
- version_major = line[28:].strip()
- if line.startswith('#define CAIRO_VERSION_MINOR '):
- version_minor = line[28:].strip()
- if line.startswith('#define CAIRO_VERSION_MICRO '):
- version_micro = line[28:].strip()
- f.close()
-
- if not (version_major and version_minor and version_micro):
- print('ERROR: Could not extract cairo version from cairo-version.h in', srcroot, file=sys.stderr)
- sys.exit(-1)
-
- print('{0}.{1}.{2}'.format(version_major, version_minor, version_micro))
+ res = MAJOR_RE.match(line)
+ if res:
+ assert version_major is None
+ version_major = res.group('number')
+ continue
+ res = MINOR_RE.match(line)
+ if res:
+ assert version_minor is None
+ version_minor = res.group('number')
+ continue
+ res = MICRO_RE.match(line)
+ if res:
+ assert version_micro is None
+ version_micro = res.group('number')
+ continue
+
+if not (version_major and version_minor and version_micro):
+ print(f"ERROR: Could not extract version from cairo-version.h in {srcroot}", file=sys.stderr) # noqa
+ sys.exit(-1)
+
+print(f"{version_major}.{version_minor}.{version_micro}")