summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
128 files changed, 8960 insertions, 16604 deletions
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 */