summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Worth <cworth@cworth.org>2006-04-18 15:18:31 -0700
committerCarl Worth <cworth@cworth.org>2006-04-18 15:18:31 -0700
commit448e904b2a64769aa9cfd8ea011c2b5fb6ec883b (patch)
tree3c6648d822914691133d97bc17b3ff0bd533c240
parentcb778760cb87e727a701603bcea3a2cdc063d785 (diff)
parentffab2592fc5d0ccd498aff2f4e645eefe351b61b (diff)
downloadcairo-448e904b2a64769aa9cfd8ea011c2b5fb6ec883b.tar.gz
Merge branch 'cairo' into new-sub-path
Conflicts: src/cairo-path-stroke.c src/cairo-pdf-surface.c src/cairo-ps-surface.c
-rw-r--r--.gitignore1
-rw-r--r--AUTHORS1
-rw-r--r--INSTALL2
-rw-r--r--Makefile.am47
-rw-r--r--RELEASING26
-rwxr-xr-xautogen.sh2
-rw-r--r--configure.in4
-rw-r--r--doc/public/cairo-docs.xml1
-rw-r--r--doc/public/cairo-sections.txt8
-rw-r--r--doc/public/tmpl/cairo-svg.sgml52
-rw-r--r--pixman/src/fbcompose.c12
-rw-r--r--pixman/src/fbedge.c2
-rw-r--r--pixman/src/fbedgeimp.h2
-rw-r--r--pixman/src/fbpict.c6
-rw-r--r--pixman/src/fbpict.h2
-rw-r--r--pixman/src/icpixels.c3
-rw-r--r--pixman/src/ictrap.c2
-rw-r--r--pixman/src/pixman-xserver-compat.h2
-rw-r--r--pixman/src/pixman.h4
-rw-r--r--pixman/src/pixregion.c6
-rw-r--r--pixman/src/pixregionint.h2
-rw-r--r--pixman/src/renderedge.c2
-rw-r--r--pixman/src/renderedge.h2
-rw-r--r--src/Makefile.am19
-rw-r--r--src/cairo-analysis-surface-private.h55
-rw-r--r--src/cairo-analysis-surface.c256
-rw-r--r--src/cairo-atsui-font.c186
-rw-r--r--src/cairo-base85-stream.c130
-rw-r--r--src/cairo-beos-surface.cpp250
-rw-r--r--src/cairo-cache-private.h2
-rw-r--r--src/cairo-clip.c4
-rw-r--r--src/cairo-directfb-surface.c9
-rw-r--r--src/cairo-font.c25
-rw-r--r--src/cairo-ft-font.c14
-rw-r--r--src/cairo-glitz-surface.c15
-rw-r--r--src/cairo-hash-private.h2
-rw-r--r--src/cairo-hash.c43
-rw-r--r--src/cairo-image-surface.c10
-rw-r--r--src/cairo-lzw.c400
-rw-r--r--src/cairo-meta-surface-private.h2
-rw-r--r--src/cairo-meta-surface.c3
-rw-r--r--src/cairo-operator.c119
-rw-r--r--src/cairo-output-stream.c147
-rw-r--r--src/cairo-paginated-surface-private.h96
-rw-r--r--src/cairo-paginated-surface.c167
-rw-r--r--src/cairo-path-stroke.c55
-rw-r--r--src/cairo-pattern.c124
-rw-r--r--src/cairo-pdf-surface.c347
-rw-r--r--src/cairo-ps-surface.c1693
-rw-r--r--src/cairo-quartz-private.h10
-rw-r--r--src/cairo-quartz-surface.c237
-rw-r--r--src/cairo-quartz.h4
-rw-r--r--src/cairo-scaled-font.c28
-rw-r--r--src/cairo-surface-fallback.c9
-rw-r--r--src/cairo-surface.c79
-rw-r--r--src/cairo-svg-surface.c306
-rw-r--r--src/cairo-wideint.c3
-rw-r--r--src/cairo-wideint.h3
-rw-r--r--src/cairo-win32-font.c4
-rw-r--r--src/cairo-win32-private.h7
-rw-r--r--src/cairo-win32-surface.c253
-rw-r--r--src/cairo-win32.h8
-rw-r--r--src/cairo-xcb-surface.c1
-rw-r--r--src/cairo-xlib-surface.c52
-rw-r--r--src/cairo.c49
-rw-r--r--src/cairo.h139
-rw-r--r--src/cairoint.h119
-rw-r--r--src/test-fallback-surface.c1
-rw-r--r--src/test-meta-surface.c1
-rw-r--r--src/test-paginated-surface.c220
-rw-r--r--test/.gitignore4
-rw-r--r--test/Makefile.am29
-rw-r--r--test/cairo-test.c165
-rw-r--r--test/caps-joins-ps-argb32-ref.pngbin0 -> 995 bytes
-rw-r--r--test/caps-sub-paths-ps-argb32-ref.pngbin0 -> 170 bytes
-rw-r--r--test/clip-fill-rule-ps-argb32-ref.pngbin0 -> 280 bytes
-rw-r--r--test/clip-nesting-ps-argb32-ref.pngbin0 -> 488 bytes
-rw-r--r--test/clip-twice-ps-argb32-ref.pngbin0 -> 460 bytes
-rw-r--r--test/dash-caps-joins-ps-argb32-ref.pngbin0 -> 1247 bytes
-rw-r--r--test/dash-caps-joins-ref.pngbin3219 -> 2583 bytes
-rw-r--r--test/dash-caps-joins-rgb24-ref.pngbin2946 -> 2465 bytes
-rw-r--r--test/dash-offset-negative-ps-argb32-ref.pngbin0 -> 170 bytes
-rw-r--r--test/dash-zero-length-ps-argb32-ref.pngbin0 -> 214 bytes
-rw-r--r--test/dash-zero-length-ref.pngbin0 -> 235 bytes
-rw-r--r--test/dash-zero-length-rgb24-ref.pngbin0 -> 222 bytes
-rw-r--r--test/dash-zero-length.c88
-rw-r--r--test/fill-and-stroke-ps-argb32-ref.pngbin0 -> 243 bytes
-rw-r--r--test/fill-rule-ps-argb32-ref.pngbin0 -> 1078 bytes
-rw-r--r--test/font-face-get-type.c64
-rw-r--r--test/ft-font-create-for-ft-face.c14
-rw-r--r--test/leaky-polygon-ps-argb32-ref.pngbin0 -> 233 bytes
-rw-r--r--test/line-width-ps-argb32-ref.pngbin0 -> 201 bytes
-rw-r--r--test/mask.c8
-rw-r--r--test/path-data-ps-argb32-ref.pngbin0 -> 322 bytes
-rw-r--r--test/pattern-get-type.c74
-rw-r--r--test/rectangle-rounding-error-ps-argb32-ref.pngbin0 -> 258 bytes
-rw-r--r--test/show-glyphs-many-ref.pngbin0 -> 118 bytes
-rw-r--r--test/show-glyphs-many-rgb24-ref.pngbin0 -> 115 bytes
-rw-r--r--test/show-glyphs-many.c127
-rw-r--r--test/show-text-current-point-ps-argb32-ref.pngbin0 -> 638 bytes
-rw-r--r--test/show-text-current-point-svg-argb32-ref.pngbin0 -> 4236 bytes
-rw-r--r--test/show-text-current-point-svg-rgb24-ref.pngbin0 -> 4236 bytes
-rw-r--r--test/text-antialias-gray-ps-argb32-ref.pngbin0 -> 305 bytes
-rw-r--r--test/text-antialias-gray-svg-argb32-ref.pngbin0 -> 1077 bytes
-rw-r--r--test/text-antialias-gray-svg-rgb24-ref.pngbin0 -> 1077 bytes
-rw-r--r--test/text-antialias-none-ps-argb32-ref.pngbin0 -> 305 bytes
-rw-r--r--test/text-antialias-none-svg-argb32-ref.pngbin0 -> 1077 bytes
-rw-r--r--test/text-antialias-none-svg-rgb24-ref.pngbin0 -> 1077 bytes
-rw-r--r--test/text-antialias-subpixel-ps-argb32-ref.pngbin0 -> 305 bytes
-rw-r--r--test/text-antialias-subpixel-svg-argb32-ref.pngbin0 -> 1077 bytes
-rw-r--r--test/text-antialias-subpixel-svg-rgb24-ref.pngbin0 -> 1077 bytes
-rw-r--r--test/text-pattern-svg-argb32-ref.pngbin0 -> 2643 bytes
-rw-r--r--test/text-pattern-svg-rgb24-ref.pngbin0 -> 2428 bytes
-rw-r--r--test/transforms-ps-argb32-ref.pngbin0 -> 287 bytes
-rw-r--r--test/unantialiased-shapes-ps-argb32-ref.pngbin0 -> 4076 bytes
-rw-r--r--test/unantialiased-shapes-svg-argb32-ref.pngbin0 -> 19689 bytes
-rw-r--r--test/unantialiased-shapes-svg-rgb24-ref.pngbin0 -> 19689 bytes
117 files changed, 4942 insertions, 1528 deletions
diff --git a/.gitignore b/.gitignore
index 73e1e4e75..f8e50fe9e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+ChangeLog
Makefile
Makefile.in
aclocal.m4
diff --git a/AUTHORS b/AUTHORS
index e6f0863c3..ad0b97cfb 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -14,6 +14,7 @@ John Ehresman <jpe@wingide.com> Build fixes for win32
John Ellson <ellson@research.att.com> First font/glyph extents functions
Behdad Esfahbod <behdad@behdad.org> Release script improvements, bug fixes.
Bertram Felgenhauer <int-e@gmx.de> Fixes for subtle arithmetic errors
+Bdale Garbee <bdale@gag.com> Provided essential support for cairo achitecture sessions
J. Ali Harlow <ali@avrc.city.ac.uk> win32 backend updates
Richard Henderson <rth@twiddle.net> "slim" macros for better shared libraries
James Henstridge <james@daa.com.au> Build fixes related to freetype
diff --git a/INSTALL b/INSTALL
index 4a49f008d..ab82781bd 100644
--- a/INSTALL
+++ b/INSTALL
@@ -16,7 +16,7 @@ This final step may require temporary root access (eg. with sudo) if
you don't have write permission to the directory in which cairo will
be installed.
-NOTE: If you are working with source from CVS rather than from a tar
+NOTE: If you are working with source from git/cvs rather than from a tar
file, then you should use ./autogen.sh in place of ./configure
anywhere it is mentioned in these instructions.
diff --git a/Makefile.am b/Makefile.am
index ab5ca24bf..165f9c349 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -11,6 +11,21 @@ EXTRA_DIST = \
COPYING-LGPL-2.1 \
COPYING-MPL-1.1 \
cairo.pc.in
+MAINTAINERCLEANFILES = \
+ $(srcdir)/INSTALL \
+ $(srcdir)/aclocal.m4 \
+ $(srcdir)/autoscan.log \
+ $(srcdir)/compile \
+ $(srcdir)/config.guess \
+ $(srcdir)/config.h.in \
+ $(srcdir)/config.sub \
+ $(srcdir)/configure.scan \
+ $(srcdir)/depcomp \
+ $(srcdir)/install-sh \
+ $(srcdir)/ltmain.sh \
+ $(srcdir)/missing \
+ $(srcdir)/mkinstalldirs \
+ `find "$(srcdir)" -type f -name Makefile.in -print`
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = cairo.pc
@@ -20,6 +35,30 @@ check-valgrind: all
DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc
+# Creating ChangeLog from git log:
+
+MAINTAINERCLEANFILES += ChangeLog
+
+EXTRA_DIST += ChangeLog
+
+ChangeLog: $(srcdir)/ChangeLog
+
+$(srcdir)/ChangeLog:
+ @if test -d "$(srcdir)/.git"; then \
+ (cd "$(srcdir)" && \
+ ./missing --run git-log) | fmt --split-only > $@.tmp \
+ && mv -f $@.tmp $@ \
+ || ($(RM) $@.tmp; \
+ echo Failed to generate ChangeLog, your ChangeLog may be outdated >&2; \
+ (test -f $@ || echo git-log is required to generate this file >> $@)); \
+ else \
+ test -f $@ || \
+ (echo A git checkout and git-log is required to generate ChangeLog >&2 && \
+ echo A git checkout and git-log is required to generate this file >> $@); \
+ fi
+
+.PHONY: ChangeLog $(srcdir)/ChangeLog
+
# Some custom targets to make it easier to release things.
# Use either:
# make release-check
@@ -82,7 +121,7 @@ release-verify-newer:
@echo -n "Checking that no $(VERSION) release already exists..."
@ssh $(RELEASE_UPLOAD_HOST) test ! -e $(RELEASE_UPLOAD_DIR)/$(tar_file) \
|| (echo "Ouch." && echo "Found: $(RELEASE_UPLOAD_HOST):$(RELEASE_UPLOAD_DIR)/$(tar_file)" \
- && echo "Are you sure you have an updated CVS checkout?" \
+ && echo "Are you sure you have an updated checkout?" \
&& echo "This should never happen." \
&& false)
@echo "Good."
@@ -104,9 +143,9 @@ release-upload: release-check $(tar_file) $(sha1_file) $(gpg_file)
scp $(tar_file) $(sha1_file) $(gpg_file) $(RELEASE_UPLOAD_HOST):$(RELEASE_UPLOAD_DIR)
mv $(tar_file) $(sha1_file) $(gpg_file) releases
ssh $(RELEASE_UPLOAD_HOST) "rm -f $(RELEASE_UPLOAD_DIR)/LATEST-$(PACKAGE)-[0-9]* && ln -s $(tar_file) $(RELEASE_UPLOAD_DIR)/LATEST-$(PACKAGE)-$(VERSION)"
- $(CVS) tag RELEASE_$(CAIRO_VERSION_MAJOR)_$(CAIRO_VERSION_MINOR)_$(CAIRO_VERSION_MICRO)
+ git tag -s $(CAIRO_VERSION_MAJOR).$(CAIRO_VERSION_MINOR).$(CAIRO_VERSION_MICRO)
-release-publish: release-upload releases/$(sha1_file)
+release-publish-message: releases/$(sha1_file)
@echo ""
@echo "Please send an announcement to $(RELEASE_ANNOUNCE_LIST)"
@echo "including the following:"
@@ -133,6 +172,8 @@ release-publish: release-upload releases/$(sha1_file)
@echo "Last but not least, do not forget to bump up the micro"
@echo "version component to the next (odd) number and commit."
+release-publish: release-upload release-publish-message
+
# XXX: Depending on all here is rather overkill. We don't really need
# the library built in order to create the documentation.
docs-publish: all
diff --git a/RELEASING b/RELEASING
index df87e3847..49dd82ce9 100644
--- a/RELEASING
+++ b/RELEASING
@@ -1,12 +1,7 @@
Here are the steps to follow to create a new cairo release:
-1) Ensure that there are no local, uncommitted modifications. The best
- thing to do here may be to begin with a fresh checkout from CVS:
-
- cvs -d cairographics.org:/cvs/cairo co cairo
-
- But it's probably good enough if "cvs -q update -Ad" generates no
- output.
+1) Ensure that there are no local, uncommitted modifications.
+ It's probably good enough if "git diff" doesn't output anything.
2) Verify that the code passes "make distcheck"
@@ -32,7 +27,10 @@ Here are the steps to follow to create a new cairo release:
previous release tag:
find src/ -name '*.h' -not -name '*-private.h' -not -name 'cairoint.h' | \
- xargs cvs diff -r RELEASE_X_Y_Z
+ xargs git diff X.Y.Z --
+
+ Note that for older releases made under CVS, the tag name is
+ RELEASE_X_Y_Z instead.
4) Increment cairo_version_{minor|micro} and LT_{CURRENT|VERSION|AGE}
in configure.in:
@@ -55,9 +53,8 @@ Here are the steps to follow to create a new cairo release:
5) Commit the changes to NEWS and configure.in
- Don't forget to fill out the ChangeLog just like with any
- other commit. It's especially important to mention the new
- version number in the ChangeLog.
+ It's especially important to mention the new version number in your
+ commit log.
6) Run "make release-publish" which will perform the following steps
for you:
@@ -71,8 +68,13 @@ Here are the steps to follow to create a new cairo release:
* scp the three files to appear on http://cairographics.org/releases
* Place local copies of the three files in the releases directory
* Create a LATEST-package-version file (after deleting any old one)
- * Tag the entire source tree with a tag of the form RELEASE_X_Y_Z
+ * Tag the entire source tree with a tag of the form X.Y.Z, and sign
+ the tag with your GPG key (asks for your GPG password, and you
+ may need to set GIT_COMMITTER_NAME and GIT_COMMITTER_EMAIL to match
+ your public-key's setting or this fails.)
* Provide some text for the release announcement (see below).
+ If for some reason you lost this message, "make release-publish-message"
+ prints it for you.
7) Increment cairo_version_micro to the next larger (odd) number in
configure, and commit.
diff --git a/autogen.sh b/autogen.sh
index 88ad4f74b..57bf60111 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -7,7 +7,7 @@ PACKAGE=cairo
LIBTOOLIZE=${LIBTOOLIZE-libtoolize}
LIBTOOLIZE_FLAGS="--copy --force"
AUTOHEADER=${AUTOHEADER-autoheader}
-AUTOMAKE_FLAGS="--add-missing"
+AUTOMAKE_FLAGS="--add-missing --foreign"
AUTOCONF=${AUTOCONF-autoconf}
# automake 1.8 requires autoconf 2.58
diff --git a/configure.in b/configure.in
index b957ada3d..020b394d1 100644
--- a/configure.in
+++ b/configure.in
@@ -1,7 +1,7 @@
AC_PREREQ(2.54)
# cairo package version number, (as distinct from shared library version)
-# An odd micro number indicates in-progress development, (eg. from CVS)
+# An odd micro number indicates in-progress development, (eg. from git/cvs)
# An even micro number indicates a released version.
m4_define(cairo_version_major, 1)
m4_define(cairo_version_minor, 1)
@@ -810,6 +810,6 @@ if test x"$use_beos" = "xyes" ; then
echo "$WARNING_MESSAGE" | sed 's/@BACKEND@/BeOS/'
fi
-if test x"$use_directfb" == "xyes" ; then
+if test x"$use_directfb" = "xyes" ; then
echo "$WARNING_MESSAGE" | sed 's/@BACKEND@/DirectFB/'
fi
diff --git a/doc/public/cairo-docs.xml b/doc/public/cairo-docs.xml
index 679eb9202..b78d269f4 100644
--- a/doc/public/cairo-docs.xml
+++ b/doc/public/cairo-docs.xml
@@ -40,6 +40,7 @@
<xi:include href="xml/cairo-ps.xml"/>
<xi:include href="xml/cairo-win32.xml"/>
<xi:include href="xml/cairo-beos.xml"/>
+ <xi:include href="xml/cairo-svg.xml"/>
<!-- Experimental Quartz and XCB backends removed
from the public doc for now.
<xi:include href="xml/cairo-quartz.xml"/>
diff --git a/doc/public/cairo-sections.txt b/doc/public/cairo-sections.txt
index bf84dd5ec..59f509805 100644
--- a/doc/public/cairo-sections.txt
+++ b/doc/public/cairo-sections.txt
@@ -109,6 +109,14 @@ cairo_xlib_surface_create_with_xrender_format
</SECTION>
<SECTION>
+<FILE>cairo-svg</FILE>
+<TITLE>SVG Surfaces</TITLE>
+cairo_svg_surface_create
+cairo_svg_surface_create_for_stream
+cairo_svg_surface_set_dpi
+</SECTION>
+
+<SECTION>
<FILE>cairo-surface</FILE>
<TITLE>cairo_surface_t</TITLE>
cairo_surface_t
diff --git a/doc/public/tmpl/cairo-svg.sgml b/doc/public/tmpl/cairo-svg.sgml
new file mode 100644
index 000000000..31bf69257
--- /dev/null
+++ b/doc/public/tmpl/cairo-svg.sgml
@@ -0,0 +1,52 @@
+<!-- ##### SECTION Title ##### -->
+SVG Surfaces
+
+<!-- ##### SECTION Short_Description ##### -->
+Rendering SVG documents
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### FUNCTION cairo_svg_surface_create ##### -->
+<para>
+
+</para>
+
+@filename:
+@width_in_points:
+@height_in_points:
+@Returns:
+
+
+<!-- ##### FUNCTION cairo_svg_surface_create_for_stream ##### -->
+<para>
+
+</para>
+
+@write_func:
+@closure:
+@width_in_points:
+@height_in_points:
+@Returns:
+
+
+<!-- ##### FUNCTION cairo_svg_surface_set_dpi ##### -->
+<para>
+
+</para>
+
+@surface:
+@x_dpi:
+@y_dpi:
+
+
diff --git a/pixman/src/fbcompose.c b/pixman/src/fbcompose.c
index 2289cee09..e316c6db6 100644
--- a/pixman/src/fbcompose.c
+++ b/pixman/src/fbcompose.c
@@ -33,10 +33,18 @@
#include "pixregionint.h"
+#ifdef _MSC_VER
+#define _USE_MATH_DEFINES
+#endif
+
#include <math.h>
-// #define PIXMAN_CONVOLUTION
-// #define PIXMAN_INDEXED_FORMATS
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+/* #define PIXMAN_CONVOLUTION */
+/* #define PIXMAN_INDEXED_FORMATS */
static Bool
PictureTransformPoint3d (pixman_transform_t *transform,
diff --git a/pixman/src/fbedge.c b/pixman/src/fbedge.c
index 2ee6e6cdc..f1289b3fa 100644
--- a/pixman/src/fbedge.c
+++ b/pixman/src/fbedge.c
@@ -1,6 +1,4 @@
/*
- * $Id: fbedge.c,v 1.3 2005-08-02 01:01:24 vektor Exp $
- *
* Copyright © 2004 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
diff --git a/pixman/src/fbedgeimp.h b/pixman/src/fbedgeimp.h
index 87691faf2..aa9ca90fa 100644
--- a/pixman/src/fbedgeimp.h
+++ b/pixman/src/fbedgeimp.h
@@ -1,6 +1,4 @@
/*
- * $Id: fbedgeimp.h,v 1.2 2005-01-21 18:38:42 cworth Exp $
- *
* Copyright © 2004 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
diff --git a/pixman/src/fbpict.c b/pixman/src/fbpict.c
index e074174e7..a09174009 100644
--- a/pixman/src/fbpict.c
+++ b/pixman/src/fbpict.c
@@ -1,6 +1,4 @@
/*
- * $Id: fbpict.c,v 1.8 2006-01-21 17:39:11 biesi Exp $
- *
* Copyright © 2000 SuSE, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
@@ -1151,7 +1149,7 @@ fbCompositeTrans_0888xnx0888(pixman_operator_t op,
setupPackedReader(ws,wt,isrc,wsrc,workingSource);
/* get to word aligned */
- switch(!(long)dst&3)
+ switch(~(long)dst&3)
{
case 1:
readPackedSource(rs);
@@ -1227,7 +1225,7 @@ fbCompositeTrans_0888xnx0888(pixman_operator_t op,
srcLine += srcStride;
w = width*3;
/* get to word aligned */
- switch(!(long)src&3)
+ switch(~(long)src&3)
{
case 1:
rd=alphamaskCombine24(*src++, *dst)>>8;
diff --git a/pixman/src/fbpict.h b/pixman/src/fbpict.h
index 95742ed8b..fbf00ed77 100644
--- a/pixman/src/fbpict.h
+++ b/pixman/src/fbpict.h
@@ -1,6 +1,4 @@
/*
- * $Id: fbpict.h,v 1.2 2005-09-12 12:55:11 otaylor Exp $
- *
* Copyright © 2000 Keith Packard
* 2005 Lars Knoll & Zack Rusin, Trolltech
*
diff --git a/pixman/src/icpixels.c b/pixman/src/icpixels.c
index 7b3798ed8..2ad34f478 100644
--- a/pixman/src/icpixels.c
+++ b/pixman/src/icpixels.c
@@ -1,6 +1,4 @@
/*
- * $Id: icpixels.c,v 1.9 2005-06-25 03:13:19 jrmuizel Exp $
- *
* Copyright © 1998 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
@@ -72,6 +70,7 @@ FbPixelsCreate (int width, int height, int depth)
return NULL;
buf = (pixman_bits_t *) ((char *)pixels + base + adjust);
+ memset (buf, 0, height * stride);
FbPixelsInit (pixels, buf, width, height, depth, bpp, stride);
diff --git a/pixman/src/ictrap.c b/pixman/src/ictrap.c
index 0ac51ca09..08bd0247b 100644
--- a/pixman/src/ictrap.c
+++ b/pixman/src/ictrap.c
@@ -1,6 +1,4 @@
/*
- * $Id: ictrap.c,v 1.27 2005-08-28 02:32:57 vektor Exp $
- *
* Copyright © 2002 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
diff --git a/pixman/src/pixman-xserver-compat.h b/pixman/src/pixman-xserver-compat.h
index 46e2825f9..5113abd54 100644
--- a/pixman/src/pixman-xserver-compat.h
+++ b/pixman/src/pixman-xserver-compat.h
@@ -72,8 +72,8 @@ typedef pixman_triangle_t xTriangle;
#define FB_SHIFT IC_SHIFT
#define FB_MASK IC_MASK
#define FB_ALLONES IC_ALLONES
+#define FbMaskBits IcMaskBits
*/
-//#define FbMaskBits IcMaskBits
/* XXX: We changed some function and field names which makes for some
* ugly hacks... */
diff --git a/pixman/src/pixman.h b/pixman/src/pixman.h
index bd5194eb1..00884e7ce 100644
--- a/pixman/src/pixman.h
+++ b/pixman/src/pixman.h
@@ -54,8 +54,6 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/
-/* $Id: pixman.h,v 1.25 2006-01-05 00:26:10 cworth Exp $ */
-
/* libic.h */
/*
@@ -83,7 +81,7 @@ SOFTWARE.
#if defined (__SVR4) && defined (__sun)
# include <sys/int_types.h>
-#elif defined (__OpenBSD__) || defined (_AIX)
+#elif defined (__OpenBSD__) || defined (_AIX) || defined (__osf__)
# include <inttypes.h>
#elif defined (_MSC_VER)
typedef __int8 int8_t;
diff --git a/pixman/src/pixregion.c b/pixman/src/pixregion.c
index 9c122f534..e5660969e 100644
--- a/pixman/src/pixregion.c
+++ b/pixman/src/pixregion.c
@@ -60,7 +60,7 @@ SOFTWARE.
#endif
#undef assert
-#ifdef DEBUG
+#ifdef DEBUG_PIXREGION
#define assert(expr) {if (!(expr)) \
FatalError("Assertion failed file %s, line %d: expr\n", \
__FILE__, __LINE__); }
@@ -208,7 +208,7 @@ if (((numRects) < ((reg)->data->size >> 1)) && ((reg)->data->size > 50)) \
}
-#ifdef DEBUG
+#ifdef DEBUG_PIXREGION
int
pixman_region16_print(rgn)
pixman_region16_t * rgn;
@@ -302,7 +302,7 @@ pixman_region16_valid(reg)
}
}
-#endif /* DEBUG */
+#endif /* DEBUG_PIXREGION */
/* Create a new empty region */
diff --git a/pixman/src/pixregionint.h b/pixman/src/pixregionint.h
index 86ff8e655..e47c45590 100644
--- a/pixman/src/pixregionint.h
+++ b/pixman/src/pixregionint.h
@@ -44,8 +44,6 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
******************************************************************/
-/* $Id: pixregionint.h,v 1.7 2004-04-16 15:32:53 cworth Exp $ */
-
#ifndef _PIXREGIONINT_H_
#define _PIXREGIONINT_H_
diff --git a/pixman/src/renderedge.c b/pixman/src/renderedge.c
index 525ea73f2..56fcfb3e0 100644
--- a/pixman/src/renderedge.c
+++ b/pixman/src/renderedge.c
@@ -1,6 +1,4 @@
/*
- * $Id: renderedge.c,v 1.2 2005-01-21 18:26:28 cworth Exp $
- *
* Copyright © 2004 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
diff --git a/pixman/src/renderedge.h b/pixman/src/renderedge.h
index 5c7c1e540..522e5034e 100644
--- a/pixman/src/renderedge.h
+++ b/pixman/src/renderedge.h
@@ -1,6 +1,4 @@
/*
- * $Id: renderedge.h,v 1.3 2005-02-21 21:29:22 cworth Exp $
- *
* Copyright © 2004 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
diff --git a/src/Makefile.am b/src/Makefile.am
index 908bcb284..4ccf3278b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -56,6 +56,11 @@ libcairo_beos_sources =
if CAIRO_HAS_BEOS_SURFACE
libcairo_beos_headers = cairo-beos.h
libcairo_beos_sources += cairo-beos-surface.cpp
+
+noinst_LTLIBRARIES = libcairo_beos.la
+libcairo_beos_la_SOURCES = $(libcairo_beos_sources)
+# BeOS system headers trigger this warning
+libcairo_beos_la_CXXFLAGS = -Wno-multichar
endif
if CAIRO_HAS_GLITZ_SURFACE
@@ -129,6 +134,7 @@ libcairo_la_SOURCES = \
cairo-arc.c \
cairo-arc-private.h \
cairo-array.c \
+ cairo-base85-stream.c \
cairo-cache.c \
cairo-cache-private.h \
cairo-clip.c \
@@ -145,7 +151,9 @@ libcairo_la_SOURCES = \
cairo-hash-private.h \
cairo-hull.c \
cairo-image-surface.c \
+ cairo-lzw.c \
cairo-matrix.c \
+ cairo-operator.c \
cairo-path.c \
cairo-path-bounds.c \
cairo-path-data.c \
@@ -173,6 +181,8 @@ libcairo_la_SOURCES = \
cairo-meta-surface-private.h \
cairo-paginated-surface.c \
cairo-paginated-surface-private.h \
+ cairo-analysis-surface.c \
+ cairo-analysis-surface-private.h \
$(libcairo_atsui_sources) \
$(libcairo_ft_sources) \
$(libcairo_ps_sources) \
@@ -187,19 +197,16 @@ libcairo_la_SOURCES = \
$(libcairo_glitz_sources) \
$(libcairo_win32_sources) \
$(libcairo_beos_sources) \
- $(libcairo_directfb_sources) \
+ $(libcairo_directfb_sources) \
cairoint.h
libcairo_la_LDFLAGS = -version-info @VERSION_INFO@ -no-undefined $(export_symbols)
-# this -Wno-multichar line is really just for the beos surface, because the
-# system headers trigger this warning.
-libcairo_la_CXXFLAGS = -Wno-multichar
INCLUDES = -I$(srcdir) -I$(top_srcdir)/pixman/src $(CAIRO_CFLAGS)
-libcairo_la_LIBADD = $(top_builddir)/pixman/src/libpixman.la $(CAIRO_LIBS)
+libcairo_la_LIBADD = $(top_builddir)/pixman/src/libpixman.la $(CAIRO_LIBS) $(noinst_LTLIBRARIES)
-libcairo_la_DEPENDENCIES = $(cairo_def_dependency) $(top_builddir)/pixman/src/libpixman.la
+libcairo_la_DEPENDENCIES = $(cairo_def_dependency) $(top_builddir)/pixman/src/libpixman.la $(noinst_LTLIBRARIES)
EXTRA_DIST = \
cairo.def
diff --git a/src/cairo-analysis-surface-private.h b/src/cairo-analysis-surface-private.h
new file mode 100644
index 000000000..62e67ae68
--- /dev/null
+++ b/src/cairo-analysis-surface-private.h
@@ -0,0 +1,55 @@
+/* $Id: $
+ *
+ * Copyright © 2005 Keith Packard
+ *
+ * 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 Keith Packard
+ *
+ * Contributor(s):
+ * Keith Packard <keithp@keithp.com>
+ */
+
+#ifndef CAIRO_ANALYSIS_SURFACE_H
+#define CAIRO_ANALYSIS_SURFACE_H
+
+#include "cairoint.h"
+
+cairo_private cairo_surface_t *
+_cairo_analysis_surface_create (cairo_surface_t *target,
+ int width,
+ int height);
+
+cairo_private pixman_region16_t *
+_cairo_analysis_surface_get_supported (cairo_surface_t *surface);
+
+cairo_private pixman_region16_t *
+_cairo_analysis_surface_get_unsupported (cairo_surface_t *unsupported);
+
+cairo_private cairo_bool_t
+_cairo_analysis_surface_has_unsupported (cairo_surface_t *unsupported);
+
+#endif /* CAIRO_ANALYSIS_SURFACE_H */
diff --git a/src/cairo-analysis-surface.c b/src/cairo-analysis-surface.c
new file mode 100644
index 000000000..76b84e10b
--- /dev/null
+++ b/src/cairo-analysis-surface.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright © 2006 Keith Packard
+ *
+ * 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 Keith Packard
+ *
+ * Contributor(s):
+ * Keith Packard <keithp@keithp.com>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-analysis-surface-private.h"
+#include "cairo-paginated-surface-private.h"
+
+typedef struct {
+ cairo_surface_t base;
+ int width;
+ int height;
+
+ cairo_surface_t *target;
+
+ cairo_bool_t fallback;
+} cairo_analysis_surface_t;
+
+static cairo_int_status_t
+_cairo_analysis_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_t *rectangle)
+{
+ cairo_analysis_surface_t *surface = abstract_surface;
+
+ return _cairo_surface_get_extents (surface->target, rectangle);
+}
+
+static cairo_int_status_t
+_cairo_analysis_surface_paint (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source)
+{
+ cairo_analysis_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ if (!surface->target->backend->paint)
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ else
+ status = (*surface->target->backend->paint) (surface->target, op,
+ source);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ surface->fallback = TRUE;
+ status = CAIRO_STATUS_SUCCESS;
+ }
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_analysis_surface_mask (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source,
+ cairo_pattern_t *mask)
+{
+ cairo_analysis_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ if (!surface->target->backend->mask)
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ else
+ status = (*surface->target->backend->mask) (surface->target, op,
+ source, mask);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ surface->fallback = TRUE;
+ status = CAIRO_STATUS_SUCCESS;
+ }
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_analysis_surface_stroke (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_stroke_style_t *style,
+ cairo_matrix_t *ctm,
+ cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ cairo_analysis_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ if (!surface->target->backend->stroke)
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ else
+ status = (*surface->target->backend->stroke) (surface->target, op,
+ source, path, style,
+ ctm, ctm_inverse,
+ tolerance, antialias);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ surface->fallback = TRUE;
+ status = CAIRO_STATUS_SUCCESS;
+ }
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_analysis_surface_fill (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ cairo_analysis_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ if (!surface->target->backend->fill)
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ else
+ status = (*surface->target->backend->fill) (surface->target, op,
+ source, path, fill_rule,
+ tolerance, antialias);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ surface->fallback = TRUE;
+ status = CAIRO_STATUS_SUCCESS;
+ }
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_analysis_surface_show_glyphs (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font)
+{
+ cairo_analysis_surface_t *surface = abstract_surface;
+ cairo_status_t status;
+
+ if (!surface->target->backend->show_glyphs)
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ else
+ status = (*surface->target->backend->show_glyphs) (surface->target, op,
+ source,
+ glyphs, num_glyphs,
+ scaled_font);
+ if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+ surface->fallback = TRUE;
+ status = CAIRO_STATUS_SUCCESS;
+ }
+ return status;
+}
+
+static const cairo_surface_backend_t cairo_analysis_surface_backend = {
+ CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
+ NULL, /* create_similar */
+ NULL, /* finish_surface */
+ NULL, /* acquire_source_image */
+ NULL, /* release_source_image */
+ NULL, /* acquire_dest_image */
+ NULL, /* release_dest_image */
+ NULL, /* clone_similar */
+ NULL, /* composite */
+ NULL, /* fill_rectangles */
+ NULL, /* composite_trapezoids */
+ NULL, /* copy_page */
+ NULL, /* show_page */
+ NULL, /* set_clip_region */
+ NULL, /* clip_path */
+ _cairo_analysis_surface_get_extents,
+ NULL, /* old_show_glyphs */
+ NULL, /* get_font_options */
+ NULL, /* flush */
+ NULL, /* mark_dirty_rectangle */
+ NULL, /* scaled_font_fini */
+ NULL, /* scaled_glyph_fini */
+ _cairo_analysis_surface_paint,
+ _cairo_analysis_surface_mask,
+ _cairo_analysis_surface_stroke,
+ _cairo_analysis_surface_fill,
+ _cairo_analysis_surface_show_glyphs,
+ NULL, /* snapshot */
+};
+
+cairo_private cairo_surface_t *
+_cairo_analysis_surface_create (cairo_surface_t *target,
+ int width,
+ int height)
+{
+ cairo_analysis_surface_t *surface;
+
+ surface = malloc (sizeof (cairo_analysis_surface_t));
+ if (surface == NULL)
+ goto FAIL;
+
+ _cairo_surface_init (&surface->base, &cairo_analysis_surface_backend);
+
+ surface->width = width;
+ surface->height = height;
+
+ surface->target = target;
+ surface->fallback = FALSE;
+
+ return &surface->base;
+FAIL:
+ _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ return NULL;
+}
+
+cairo_private pixman_region16_t *
+_cairo_analysis_surface_get_supported (cairo_surface_t *abstract_surface)
+{
+ /* XXX */
+ return NULL;
+}
+
+cairo_private pixman_region16_t *
+_cairo_analysis_surface_get_unsupported (cairo_surface_t *abstract_surface)
+{
+ /* XXX */
+ return NULL;
+}
+
+cairo_private cairo_bool_t
+_cairo_analysis_surface_has_unsupported (cairo_surface_t *abstract_surface)
+{
+ cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
+
+ return surface->fallback;
+}
+
+
diff --git a/src/cairo-atsui-font.c b/src/cairo-atsui-font.c
index 9f3b54da1..76b5a3c86 100644
--- a/src/cairo-atsui-font.c
+++ b/src/cairo-atsui-font.c
@@ -40,6 +40,16 @@
#include "cairo.h"
#include "cairo-quartz-private.h"
+/*
+ * FixedToFloat/FloatToFixed are 10.3+ SDK items - include definitions
+ * here so we can use older SDKs.
+ */
+#ifndef FixedToFloat
+#define fixed1 ((Fixed) 0x00010000L)
+#define FixedToFloat(a) ((float)(a) / fixed1)
+#define FloatToFixed(a) ((Fixed)((float)(a) * fixed1))
+#endif
+
typedef struct _cairo_atsui_font_face cairo_atsui_font_face_t;
typedef struct _cairo_atsui_font cairo_atsui_font_t;
@@ -94,6 +104,7 @@ _cairo_atsui_font_face_scaled_font_create (void *abstract_face,
}
static const cairo_font_face_backend_t _cairo_atsui_font_face_backend = {
+ CAIRO_FONT_TYPE_ATSUI,
_cairo_atsui_font_face_destroy,
_cairo_atsui_font_face_scaled_font_create
};
@@ -132,7 +143,7 @@ CreateSizedCopyOfStyle(ATSUStyle inStyle, const cairo_matrix_t *scale)
ATSUStyle style;
OSStatus err;
- // Set the style's size
+ /* Set the style's size */
CGAffineTransform theTransform =
CGAffineTransformMakeWithCairoFontScale(scale);
Fixed theSize =
@@ -174,7 +185,7 @@ _cairo_atsui_font_set_metrics (cairo_atsui_font_t *font)
extents.height = metrics.capHeight;
extents.max_x_advance = metrics.maxAdvanceWidth;
- // The FT backend doesn't handle max_y_advance either, so we'll ignore it for now.
+ /* The FT backend doesn't handle max_y_advance either, so we'll ignore it for now. */
extents.max_y_advance = 0.0;
_cairo_scaled_font_set_metrics (&font->base, &extents);
@@ -275,7 +286,7 @@ _cairo_atsui_font_create_toy(cairo_toy_font_face_t *toy_face,
kFontNoLanguageCode, &fontID);
if (err != noErr) {
- // couldn't get the font - remap css names and try again
+ /* couldn't get the font - remap css names and try again */
if (!strcmp(family, "serif"))
family = "Times";
@@ -287,7 +298,7 @@ _cairo_atsui_font_create_toy(cairo_toy_font_face_t *toy_face,
family = "Gadget";
else if (!strcmp(family, "monospace"))
family = "Courier";
- else // anything else - return error instead?
+ else /* anything else - return error instead? */
family = "Courier";
err = ATSUFindFontFromName(family, strlen(family),
@@ -504,7 +515,7 @@ _cairo_atsui_font_text_to_glyphs (void *abstract_font,
err = ATSUSetTextPointerLocation(textLayout, utf16, 0, n16, n16);
- // Set the style for all of the text
+ /* Set the style for all of the text */
err = ATSUSetRunStyle(textLayout,
font->style, kATSUFromTextBeginning, kATSUToTextEnd);
@@ -552,117 +563,140 @@ _cairo_atsui_font_old_show_glyphs (void *abstract_font,
int num_glyphs)
{
cairo_atsui_font_t *font = abstract_font;
- CGContextRef myBitmapContext;
- CGColorSpaceRef colorSpace;
+ CGContextRef myBitmapContext = 0, drawingContext;
+ CGColorSpaceRef colorSpace = 0;;
cairo_image_surface_t *destImageSurface;
int i;
void *extra = NULL;
-
- cairo_rectangle_t rect = {dest_x, dest_y, width, height};
- _cairo_surface_acquire_dest_image(generic_surface,
- &rect,
- &destImageSurface,
- &rect,
- &extra);
-
- // Create a CGBitmapContext for the dest surface for drawing into
- colorSpace = CGColorSpaceCreateDeviceRGB();
-
- myBitmapContext = CGBitmapContextCreate(destImageSurface->data,
- destImageSurface->width,
- destImageSurface->height,
- destImageSurface->depth / 4,
- destImageSurface->stride,
- colorSpace,
- kCGImageAlphaPremultipliedFirst);
- CGContextTranslateCTM(myBitmapContext, 0, destImageSurface->height);
- CGContextScaleCTM(myBitmapContext, 1.0f, -1.0f);
+ cairo_bool_t can_draw_directly;
+ cairo_rectangle_t rect;
+
+ /* Check if we can draw directly to the destination surface */
+ can_draw_directly = _cairo_surface_is_quartz (generic_surface) &&
+ _cairo_pattern_is_opaque_solid (pattern) &&
+ op == CAIRO_OPERATOR_OVER;
+
+ if (!can_draw_directly) {
+ rect.x = dest_x;
+ rect.y = dest_y;
+ rect.width = width;
+ rect.height = height;
+
+ _cairo_surface_acquire_dest_image(generic_surface,
+ &rect,
+ &destImageSurface,
+ &rect,
+ &extra);
+
+ /* Create a CGBitmapContext for the dest surface for drawing into */
+ colorSpace = CGColorSpaceCreateDeviceRGB();
+
+ myBitmapContext = CGBitmapContextCreate(destImageSurface->data,
+ destImageSurface->width,
+ destImageSurface->height,
+ destImageSurface->depth / 4,
+ destImageSurface->stride,
+ colorSpace,
+ kCGImageAlphaPremultipliedFirst);
+ CGContextTranslateCTM(myBitmapContext, 0, destImageSurface->height);
+ CGContextScaleCTM(myBitmapContext, 1.0f, -1.0f);
+
+ drawingContext = myBitmapContext;
+ } else {
+ drawingContext = ((cairo_quartz_surface_t *)generic_surface)->context;
+ CGContextSaveGState (drawingContext);
+ }
ATSFontRef atsFont = FMGetATSFontRefFromFont(font->fontID);
CGFontRef cgFont = CGFontCreateWithPlatformFont(&atsFont);
- CGContextSetFont(myBitmapContext, cgFont);
+ CGContextSetFont(drawingContext, cgFont);
CGAffineTransform textTransform =
CGAffineTransformMakeWithCairoFontScale(&font->base.scale);
textTransform = CGAffineTransformScale(textTransform, 1.0f, -1.0f);
- CGContextSetFontSize(myBitmapContext, 1.0);
- CGContextSetTextMatrix(myBitmapContext, textTransform);
+ CGContextSetFontSize(drawingContext, 1.0);
+ CGContextSetTextMatrix(drawingContext, textTransform);
- if (pattern->type == CAIRO_PATTERN_SOLID &&
+ if (pattern->type == CAIRO_PATTERN_TYPE_SOLID &&
_cairo_pattern_is_opaque_solid(pattern))
{
cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *)pattern;
- CGContextSetRGBFillColor(myBitmapContext,
+ CGContextSetRGBFillColor(drawingContext,
solid->color.red,
solid->color.green,
solid->color.blue, 1.0f);
} else {
- CGContextSetRGBFillColor(myBitmapContext, 0.0f, 0.0f, 0.0f, 0.0f);
+ CGContextSetRGBFillColor(drawingContext, 0.0f, 0.0f, 0.0f, 0.0f);
}
- if (_cairo_surface_is_quartz (generic_surface)) {
- cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *)generic_surface;
- if (surface->clip_region) {
- pixman_box16_t *boxes = pixman_region_rects (surface->clip_region);
- int num_boxes = pixman_region_num_rects (surface->clip_region);
- CGRect stack_rects[10];
- CGRect *rects;
- int i;
-
- if (num_boxes > 10)
- rects = malloc (sizeof (CGRect) * num_boxes);
- else
- rects = stack_rects;
-
- for (i = 0; i < num_boxes; i++) {
- rects[i].origin.x = boxes[i].x1;
- rects[i].origin.y = boxes[i].y1;
- rects[i].size.width = boxes[i].x2 - boxes[i].x1;
- rects[i].size.height = boxes[i].y2 - boxes[i].y1;
- }
-
- CGContextClipToRects (myBitmapContext, rects, num_boxes);
-
- if (rects != stack_rects)
- free(rects);
- }
- } else {
- /* XXX: Need to get the text clipped */
+ if (_cairo_surface_is_quartz (generic_surface)) {
+ cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *)generic_surface;
+ if (surface->clip_region) {
+ pixman_box16_t *boxes = pixman_region_rects (surface->clip_region);
+ int num_boxes = pixman_region_num_rects (surface->clip_region);
+ CGRect stack_rects[10];
+ CGRect *rects;
+ int i;
+
+ if (num_boxes > 10)
+ rects = malloc (sizeof (CGRect) * num_boxes);
+ else
+ rects = stack_rects;
+
+ for (i = 0; i < num_boxes; i++) {
+ rects[i].origin.x = boxes[i].x1;
+ rects[i].origin.y = boxes[i].y1;
+ rects[i].size.width = boxes[i].x2 - boxes[i].x1;
+ rects[i].size.height = boxes[i].y2 - boxes[i].y1;
+ }
+
+ CGContextClipToRects (drawingContext, rects, num_boxes);
+
+ if (rects != stack_rects)
+ free(rects);
}
+ } else {
+ /* XXX: Need to get the text clipped */
+ }
- // TODO - bold and italic text
- //
- // We could draw the text using ATSUI and get bold, italics
- // etc. for free, but ATSUI does a lot of text layout work
- // that we don't really need...
+ /* TODO - bold and italic text
+ *
+ * We could draw the text using ATSUI and get bold, italics
+ * etc. for free, but ATSUI does a lot of text layout work
+ * that we don't really need...
+ */
for (i = 0; i < num_glyphs; i++) {
CGGlyph theGlyph = glyphs[i].index;
- CGContextShowGlyphsAtPoint(myBitmapContext,
+ CGContextShowGlyphsAtPoint(drawingContext,
glyphs[i].x,
glyphs[i].y,
&theGlyph, 1);
}
-
- CGColorSpaceRelease(colorSpace);
- CGContextRelease(myBitmapContext);
-
- _cairo_surface_release_dest_image(generic_surface,
- &rect,
- destImageSurface,
- &rect,
- extra);
+ if (!can_draw_directly) {
+ CGColorSpaceRelease(colorSpace);
+ CGContextRelease(myBitmapContext);
+
+ _cairo_surface_release_dest_image(generic_surface,
+ &rect,
+ destImageSurface,
+ &rect,
+ extra);
+ } else {
+ CGContextRestoreGState (drawingContext);
+ }
return CAIRO_STATUS_SUCCESS;
}
const cairo_scaled_font_backend_t cairo_atsui_scaled_font_backend = {
+ CAIRO_FONT_TYPE_ATSUI,
_cairo_atsui_font_create_toy,
_cairo_atsui_font_fini,
_cairo_atsui_font_scaled_glyph_init,
diff --git a/src/cairo-base85-stream.c b/src/cairo-base85-stream.c
new file mode 100644
index 000000000..1d4535a9f
--- /dev/null
+++ b/src/cairo-base85-stream.c
@@ -0,0 +1,130 @@
+/* cairo_output_stream.c: Output stream abstraction
+ *
+ * Copyright © 2005 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is cairo_output_stream.c as distributed with the
+ * cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Author(s):
+ * Kristian Høgsberg <krh@redhat.com>
+ */
+
+#include "cairoint.h"
+
+typedef struct _cairo_base85_stream {
+ cairo_output_stream_t *output;
+ unsigned char four_tuple[4];
+ int pending;
+} cairo_base85_stream_t;
+
+static void
+_expand_four_tuple_to_five (unsigned char four_tuple[4],
+ unsigned char five_tuple[5],
+ cairo_bool_t *all_zero)
+{
+ uint32_t value;
+ int digit, i;
+
+ value = four_tuple[0] << 24 | four_tuple[1] << 16 | four_tuple[2] << 8 | four_tuple[3];
+ if (all_zero)
+ *all_zero = TRUE;
+ for (i = 0; i < 5; i++) {
+ digit = value % 85;
+ if (digit != 0 && all_zero)
+ *all_zero = FALSE;
+ five_tuple[4-i] = digit + 33;
+ value = value / 85;
+ }
+}
+
+static cairo_status_t
+_cairo_base85_stream_write (void *closure,
+ const unsigned char *data,
+ unsigned int length)
+{
+ cairo_base85_stream_t *stream = closure;
+ const unsigned char *ptr = data;
+ unsigned char five_tuple[5];
+ cairo_bool_t is_zero;
+
+ while (length) {
+ stream->four_tuple[stream->pending++] = *ptr++;
+ length--;
+ if (stream->pending == 4) {
+ _expand_four_tuple_to_five (stream->four_tuple, five_tuple, &is_zero);
+ if (is_zero)
+ _cairo_output_stream_write (stream->output, "z", 1);
+ else
+ _cairo_output_stream_write (stream->output, five_tuple, 5);
+ stream->pending = 0;
+ }
+ }
+
+ return _cairo_output_stream_get_status (stream->output);
+}
+
+static cairo_status_t
+_cairo_base85_stream_close (void *closure)
+{
+ cairo_status_t status;
+ cairo_base85_stream_t *stream = closure;
+ unsigned char five_tuple[5];
+
+ if (stream->pending) {
+ memset (stream->four_tuple + stream->pending, 0, 4 - stream->pending);
+ _expand_four_tuple_to_five (stream->four_tuple, five_tuple, NULL);
+ _cairo_output_stream_write (stream->output, five_tuple, stream->pending + 1);
+ }
+
+ /* Mark end of base85 data */
+ _cairo_output_stream_printf (stream->output, "~>");
+
+ status = _cairo_output_stream_get_status (stream->output);
+
+ free (stream);
+
+ return status;
+}
+
+cairo_output_stream_t *
+_cairo_base85_stream_create (cairo_output_stream_t *output)
+{
+ cairo_base85_stream_t *stream;
+
+ stream = malloc (sizeof (cairo_base85_stream_t));
+ if (stream == NULL)
+ return (cairo_output_stream_t *) &cairo_output_stream_nil;
+
+ stream->output = output;
+ stream->pending = 0;
+
+ return _cairo_output_stream_create (_cairo_base85_stream_write,
+ _cairo_base85_stream_close,
+ stream);
+}
+
diff --git a/src/cairo-beos-surface.cpp b/src/cairo-beos-surface.cpp
index b6448fa69..312bd88ff 100644
--- a/src/cairo-beos-surface.cpp
+++ b/src/cairo-beos-surface.cpp
@@ -70,6 +70,9 @@ struct cairo_beos_surface_t {
BBitmap* bitmap;
+ // If true, surface and view should be deleted when this surface is
+ // destroyed
+ bool owns_bitmap_view;
};
class AutoLockView {
@@ -92,6 +95,11 @@ class AutoLockView {
bool mOK;
};
+static cairo_surface_t *
+_cairo_beos_surface_create_internal (BView* view,
+ BBitmap* bmp,
+ bool owns_bitmap_view = false);
+
static BRect
_cairo_rect_to_brect (const cairo_rectangle_t* rect)
{
@@ -359,6 +367,7 @@ _cairo_image_surface_to_bitmap (cairo_image_surface_t* surface)
return data;
}
default:
+ assert(0);
return NULL;
}
}
@@ -414,10 +423,76 @@ _cairo_op_to_be_op (cairo_operator_t cairo_op,
};
}
+static cairo_surface_t *
+_cairo_beos_surface_create_similar (void *abstract_surface,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ fprintf(stderr, "Creating similar\n");
+
+ cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
+ abstract_surface);
+
+ if (width <= 0)
+ width = 1;
+ if (height <= 0)
+ height = 1;
+
+ BRect rect(0.0, 0.0, width - 1, height - 1);
+ BBitmap* bmp;
+ switch (content) {
+ case CAIRO_CONTENT_ALPHA:
+ // Can't support this natively
+ return _cairo_image_surface_create_with_content(content, width,
+ height);
+ case CAIRO_CONTENT_COLOR_ALPHA:
+ bmp = new BBitmap(rect, B_RGBA32, true);
+ break;
+ case CAIRO_CONTENT_COLOR:
+ // Match the color depth
+ if (surface->bitmap) {
+ color_space space = surface->bitmap->ColorSpace();
+ // No alpha was requested -> make sure not to return
+ // a surface with alpha
+ if (space == B_RGBA32)
+ space = B_RGB32;
+ if (space == B_RGBA15)
+ space = B_RGB15;
+ bmp = new BBitmap(rect, space, true);
+ } else {
+ BScreen scr(surface->view->Window());
+ color_space space = B_RGB32;
+ if (scr.IsValid())
+ space = scr.ColorSpace();
+ bmp = new BBitmap(rect, space, true);
+ }
+ break;
+ default:
+ assert(0);
+ return NULL;
+
+ };
+ BView* view = new BView(rect, "Cairo bitmap view", B_FOLLOW_ALL_SIDES, 0);
+ bmp->AddChild(view);
+ return _cairo_beos_surface_create_internal(view, bmp, true);
+}
+
static cairo_status_t
_cairo_beos_surface_finish (void *abstract_surface)
{
- // Nothing to do
+ cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
+ abstract_surface);
+ if (surface->owns_bitmap_view) {
+ if (surface->bitmap)
+ surface->bitmap->RemoveChild(surface->view);
+
+ delete surface->view;
+ delete surface->bitmap;
+
+ surface->view = NULL;
+ surface->bitmap = NULL;
+ }
return CAIRO_STATUS_SUCCESS;
}
@@ -549,13 +624,12 @@ _cairo_beos_surface_release_dest_image (void *abstract_surface,
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
abstract_surface);
+
AutoLockView locker(surface->view);
if (!locker)
return;
-
BBitmap* bitmap_to_draw = _cairo_image_surface_to_bitmap(image);
-
surface->view->PushState();
surface->view->SetDrawingMode(B_OP_COPY);
@@ -570,18 +644,18 @@ _cairo_beos_surface_release_dest_image (void *abstract_surface,
}
static cairo_int_status_t
-_cairo_beos_composite (cairo_operator_t op,
- cairo_pattern_t *src,
- cairo_pattern_t *mask,
- void *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_beos_surface_composite (cairo_operator_t op,
+ cairo_pattern_t *src,
+ cairo_pattern_t *mask,
+ void *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_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
dst);
@@ -598,7 +672,7 @@ _cairo_beos_composite (cairo_operator_t op,
return CAIRO_INT_STATUS_UNSUPPORTED;
// XXX should eventually support the others
- if (src->type != CAIRO_PATTERN_SURFACE ||
+ if (src->type != CAIRO_PATTERN_TYPE_SURFACE ||
src->extend != CAIRO_EXTEND_NONE)
{
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -617,63 +691,95 @@ _cairo_beos_composite (cairo_operator_t op,
cairo_surface_t* src_surface = reinterpret_cast<cairo_surface_pattern_t*>(src)->
surface;
- if (_cairo_surface_is_image(src_surface)) {
- fprintf(stderr, "Composite\n");
- // Draw it on screen.
+ // Get a bitmap
+ BBitmap* bmp = NULL;
+ bool free_bmp = false;
+ if (_cairo_surface_is_image(src_surface)) {
cairo_image_surface_t* img_surface =
reinterpret_cast<cairo_image_surface_t*>(src_surface);
- BBitmap* bmp = _cairo_image_surface_to_bitmap(img_surface);
- surface->view->PushState();
+ bmp = _cairo_image_surface_to_bitmap(img_surface);
+ free_bmp = true;
+ } else if (src_surface->backend == surface->base.backend) {
+ cairo_beos_surface_t *beos_surface =
+ reinterpret_cast<cairo_beos_surface_t*>(src_surface);
+ if (beos_surface->bitmap) {
+ AutoLockView locker(beos_surface->view);
+ if (locker)
+ beos_surface->view->Sync();
+ bmp = beos_surface->bitmap;
+ } else {
+ _cairo_beos_view_to_bitmap(surface->view, &bmp);
+ free_bmp = true;
+ }
+ }
- // If our image rect is only a subrect of the desired size, and we
- // aren't using B_OP_ALPHA, then we need to fill the rect first.
- if (mode == B_OP_COPY && !bmp->Bounds().Contains(srcRect)) {
- rgb_color black = { 0, 0, 0, 0 };
+ if (!bmp)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
- surface->view->SetDrawingMode(mode);
- surface->view->SetHighColor(black);
- surface->view->FillRect(dstRect);
- }
+ // So, BeOS seems to screw up painting an opaque bitmap onto a
+ // translucent one (it makes them partly transparent). Just return
+ // unsupported.
+ if (bmp->ColorSpace() == B_RGB32 && surface->bitmap &&
+ surface->bitmap->ColorSpace() == B_RGBA32 &&
+ (mode == B_OP_COPY || mode == B_OP_ALPHA))
+ {
+ if (free_bmp)
+ delete bmp;
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+ }
- if (mode == B_OP_ALPHA && img_surface->format != CAIRO_FORMAT_ARGB32) {
- mode = B_OP_COPY;
+ fprintf(stderr, "Composite\n");
+
+ // Draw it on screen.
+ surface->view->PushState();
+
+ // If our image rect is only a subrect of the desired size, and we
+ // aren't using B_OP_ALPHA, then we need to fill the rect first.
+ if (mode == B_OP_COPY && !bmp->Bounds().Contains(srcRect)) {
+ rgb_color black = { 0, 0, 0, 0 };
- }
surface->view->SetDrawingMode(mode);
+ surface->view->SetHighColor(black);
+ surface->view->FillRect(dstRect);
+ }
+
+ if (mode == B_OP_ALPHA && bmp->ColorSpace() == B_RGB32) {
+ mode = B_OP_COPY;
+ }
+ surface->view->SetDrawingMode(mode);
- if (surface->bitmap && surface->bitmap->ColorSpace() == B_RGBA32)
- surface->view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE);
- else
- surface->view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
+ if (surface->bitmap && surface->bitmap->ColorSpace() == B_RGBA32)
+ surface->view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE);
+ else
+ surface->view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
- surface->view->DrawBitmap(bmp, srcRect, dstRect);
+ surface->view->DrawBitmap(bmp, srcRect, dstRect);
- surface->view->PopState();
- delete bmp;
+ surface->view->PopState();
- return CAIRO_INT_STATUS_SUCCESS;
- }
+ if (free_bmp)
+ delete bmp;
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return CAIRO_INT_STATUS_SUCCESS;
}
static void
-_cairo_beos_fill_rectangle (cairo_beos_surface_t *surface,
- cairo_rectangle_t *rect)
+_cairo_beos_surface_fill_rectangle (cairo_beos_surface_t *surface,
+ cairo_rectangle_t *rect)
{
BRect brect(_cairo_rect_to_brect(rect));
surface->view->FillRect(brect);
}
static cairo_int_status_t
-_cairo_beos_fill_rectangles (void *abstract_surface,
- cairo_operator_t op,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int num_rects)
+_cairo_beos_surface_fill_rectangles (void *abstract_surface,
+ cairo_operator_t op,
+ const cairo_color_t *color,
+ cairo_rectangle_t *rects,
+ int num_rects)
{
fprintf(stderr, "Drawing %i rectangles\n", num_rects);
cairo_beos_surface_t *surface = reinterpret_cast<cairo_beos_surface_t*>(
@@ -716,7 +822,7 @@ _cairo_beos_fill_rectangles (void *abstract_surface,
surface->view->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
for (int i = 0; i < num_rects; ++i) {
- _cairo_beos_fill_rectangle(surface, &rects[i]);
+ _cairo_beos_surface_fill_rectangle(surface, &rects[i]);
}
surface->view->PopState();
@@ -777,15 +883,16 @@ _cairo_beos_surface_get_extents (void *abstract_surface,
}
static const struct _cairo_surface_backend cairo_beos_surface_backend = {
- NULL, /* create_similar */
+ CAIRO_SURFACE_TYPE_BEOS,
+ _cairo_beos_surface_create_similar,
_cairo_beos_surface_finish,
_cairo_beos_surface_acquire_source_image,
_cairo_beos_surface_release_source_image,
_cairo_beos_surface_acquire_dest_image,
_cairo_beos_surface_release_dest_image,
NULL, /* clone_similar */
- _cairo_beos_composite, /* composite */
- _cairo_beos_fill_rectangles,
+ _cairo_beos_surface_composite, /* composite */
+ _cairo_beos_surface_fill_rectangles,
NULL, /* composite_trapezoids */
NULL, /* copy_page */
NULL, /* show_page */
@@ -806,6 +913,28 @@ static const struct _cairo_surface_backend cairo_beos_surface_backend = {
NULL /* show_glyphs */
};
+static cairo_surface_t *
+_cairo_beos_surface_create_internal (BView* view,
+ BBitmap* bmp,
+ bool owns_bitmap_view)
+{
+ // Must use malloc, because cairo code will use free() on the surface
+ cairo_beos_surface_t *surface = static_cast<cairo_beos_surface_t*>(
+ malloc(sizeof(cairo_beos_surface_t)));
+ if (surface == NULL) {
+ _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ return const_cast<cairo_surface_t*>(&_cairo_surface_nil);
+ }
+
+ _cairo_surface_init(&surface->base, &cairo_beos_surface_backend);
+
+ surface->view = view;
+ surface->bitmap = bmp;
+ surface->owns_bitmap_view = owns_bitmap_view;
+
+ return (cairo_surface_t *) surface;
+}
+
/**
* cairo_beos_surface_create:
* @view: The view to draw on
@@ -842,20 +971,7 @@ cairo_surface_t *
cairo_beos_surface_create_for_bitmap (BView* view,
BBitmap* bmp)
{
- // Must use malloc, because cairo code will use free() on the surface
- cairo_beos_surface_t *surface = static_cast<cairo_beos_surface_t*>(
- malloc(sizeof(cairo_beos_surface_t)));
- if (surface == NULL) {
- _cairo_error (CAIRO_STATUS_NO_MEMORY);
- return const_cast<cairo_surface_t*>(&_cairo_surface_nil);
- }
-
- _cairo_surface_init(&surface->base, &cairo_beos_surface_backend);
-
- surface->view = view;
- surface->bitmap = bmp;
-
- return (cairo_surface_t *) surface;
+ return _cairo_beos_surface_create_internal(view, bmp);
}
// ---------------------------------------------------------------------------
diff --git a/src/cairo-cache-private.h b/src/cairo-cache-private.h
index a75e8c0be..566dbe22d 100644
--- a/src/cairo-cache-private.h
+++ b/src/cairo-cache-private.h
@@ -88,7 +88,7 @@ typedef struct _cairo_cache_entry {
} cairo_cache_entry_t;
typedef cairo_bool_t
-(*cairo_cache_keys_equal_func_t) (void *key_a, void *key_b);
+(*cairo_cache_keys_equal_func_t) (const void *key_a, const void *key_b);
typedef void
(*cairo_cache_callback_func_t) (void *entry,
diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index c76ebdcbf..0c862a388 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -248,8 +248,10 @@ _cairo_clip_intersect_path (cairo_clip_t *clip,
return CAIRO_STATUS_NO_MEMORY;
status = _cairo_path_fixed_init_copy (&clip_path->path, path);
- if (status)
+ if (status) {
+ free (clip_path);
return status;
+ }
clip_path->ref_count = 1;
clip_path->fill_rule = fill_rule;
diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c
index be1791584..fcd5dd781 100644
--- a/src/cairo-directfb-surface.c
+++ b/src/cairo-directfb-surface.c
@@ -150,7 +150,7 @@ static inline int cairo_to_directfb_format(cairo_format_t format ) {
return DSPF_A1;
default:
{
- //assert(0);
+ /*assert(0);*/
return DSPF_UNKNOWN;
}
}
@@ -483,9 +483,9 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
if( _dfb_set_operator(op,surface->buffer) == DFB_UNSUPPORTED )
return CAIRO_INT_STATUS_UNSUPPORTED;
- if (src_pattern->type == CAIRO_PATTERN_SOLID ) {
+ if (src_pattern->type == CAIRO_PATTERN_TYPE_SOLID ) {
- } else if (src_pattern->type != CAIRO_PATTERN_SURFACE ||
+ } else if (src_pattern->type != CAIRO_PATTERN_TYPE_SURFACE ||
src_pattern->extend != CAIRO_EXTEND_NONE) {
return CAIRO_INT_STATUS_UNSUPPORTED;
}
@@ -494,7 +494,7 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
/* FIXME: When we fully support RENDER style 4-channel
* masks we need to check r/g/b != 1.0.
*/
- if (mask_pattern->type != CAIRO_PATTERN_SOLID)
+ if (mask_pattern->type != CAIRO_PATTERN_TYPE_SOLID)
return CAIRO_INT_STATUS_UNSUPPORTED;
alpha = ((cairo_solid_pattern_t *)mask_pattern)->color.alpha_short >> 8;
@@ -662,6 +662,7 @@ _cairo_directfb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
static const cairo_surface_backend_t cairo_directfb_surface_backend = {
+ CAIRO_SURFACE_TYPE_DIRECTFB,
_cairo_directfb_surface_create_similar,
_cairo_directfb_surface_finish,
_cairo_directfb_surface_acquire_source_image,
diff --git a/src/cairo-font.c b/src/cairo-font.c
index b0fab1b4a..425021a1e 100644
--- a/src/cairo-font.c
+++ b/src/cairo-font.c
@@ -131,6 +131,18 @@ cairo_font_face_destroy (cairo_font_face_t *font_face)
}
/**
+ * cairo_font_face_get_type:
+ * @font_face: a #cairo_font_face_t
+ *
+ * Return value: The type of @font_face. See #cairo_font_type_t.
+ **/
+cairo_font_type_t
+cairo_font_face_get_type (cairo_font_face_t *font_face)
+{
+ return font_face->backend->type;
+}
+
+/**
* cairo_font_face_status:
* @font_face: a #cairo_font_face_t
*
@@ -198,8 +210,8 @@ cairo_font_face_set_user_data (cairo_font_face_t *font_face,
static const cairo_font_face_backend_t _cairo_toy_font_face_backend;
static int
-_cairo_toy_font_face_keys_equal (void *key_a,
- void *key_b);
+_cairo_toy_font_face_keys_equal (const void *key_a,
+ const void *key_b);
/* We maintain a hash table from family/weight/slant =>
* cairo_font_face_t for cairo_toy_font_t. The primary purpose of
@@ -300,11 +312,11 @@ _cairo_toy_font_face_fini (cairo_toy_font_face_t *font_face)
}
static int
-_cairo_toy_font_face_keys_equal (void *key_a,
- void *key_b)
+_cairo_toy_font_face_keys_equal (const void *key_a,
+ const void *key_b)
{
- cairo_toy_font_face_t *face_a = key_a;
- cairo_toy_font_face_t *face_b = key_b;
+ const cairo_toy_font_face_t *face_a = key_a;
+ const cairo_toy_font_face_t *face_b = key_b;
return (strcmp (face_a->family, face_b->family) == 0 &&
face_a->slant == face_b->slant &&
@@ -409,6 +421,7 @@ _cairo_toy_font_face_scaled_font_create (void *abstract_font_face
}
static const cairo_font_face_backend_t _cairo_toy_font_face_backend = {
+ CAIRO_FONT_TYPE_TOY,
_cairo_toy_font_face_destroy,
_cairo_toy_font_face_scaled_font_create
};
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 45997444d..a23388a72 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -103,8 +103,8 @@ struct _cairo_ft_unscaled_font {
};
static int
-_cairo_ft_unscaled_font_keys_equal (void *key_a,
- void *key_b);
+_cairo_ft_unscaled_font_keys_equal (const void *key_a,
+ const void *key_b);
static void
_cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled);
@@ -365,11 +365,11 @@ _cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled)
}
static int
-_cairo_ft_unscaled_font_keys_equal (void *key_a,
- void *key_b)
+_cairo_ft_unscaled_font_keys_equal (const void *key_a,
+ const void *key_b)
{
- cairo_ft_unscaled_font_t *unscaled_a = key_a;
- cairo_ft_unscaled_font_t *unscaled_b = key_b;
+ const cairo_ft_unscaled_font_t *unscaled_a = key_a;
+ const cairo_ft_unscaled_font_t *unscaled_b = key_b;
return (strcmp (unscaled_a->filename, unscaled_b->filename) == 0 &&
unscaled_a->id == unscaled_b->id);
@@ -1901,6 +1901,7 @@ _cairo_ft_show_glyphs (void *abstract_font,
}
const cairo_scaled_font_backend_t cairo_ft_scaled_font_backend = {
+ CAIRO_FONT_TYPE_FT,
_cairo_ft_scaled_font_create_toy,
_cairo_ft_scaled_font_fini,
_cairo_ft_scaled_glyph_init,
@@ -2004,6 +2005,7 @@ _cairo_ft_font_face_scaled_font_create (void *abstract_face,
}
static const cairo_font_face_backend_t _cairo_ft_font_face_backend = {
+ CAIRO_FONT_TYPE_FT,
_cairo_ft_font_face_destroy,
_cairo_ft_font_face_scaled_font_create
};
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index b62547236..c000917ac 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -551,8 +551,8 @@ _cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern,
attr->acquired = FALSE;
switch (pattern->type) {
- case CAIRO_PATTERN_LINEAR:
- case CAIRO_PATTERN_RADIAL: {
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ case CAIRO_PATTERN_TYPE_RADIAL: {
cairo_gradient_pattern_t *gradient =
(cairo_gradient_pattern_t *) pattern;
char *data;
@@ -587,7 +587,7 @@ _cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern,
if (!CAIRO_GLITZ_FEATURE_OK (dst->surface, FRAGMENT_PROGRAM))
break;
- if (pattern->type == CAIRO_PATTERN_RADIAL)
+ if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL)
n_base_params = 6;
else
n_base_params = 4;
@@ -639,7 +639,7 @@ _cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern,
glitz_buffer_destroy (buffer);
- if (pattern->type == CAIRO_PATTERN_LINEAR)
+ if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR)
{
cairo_linear_pattern_t *grad = (cairo_linear_pattern_t *) pattern;
@@ -776,8 +776,8 @@ _cairo_glitz_pattern_acquire_surfaces (cairo_pattern_t *src,
* information in mask, so this will need to change when we
* support RENDER-style 4-channel masks. */
- if (src->type == CAIRO_PATTERN_SOLID &&
- mask->type == CAIRO_PATTERN_SOLID)
+ if (src->type == CAIRO_PATTERN_TYPE_SOLID &&
+ mask->type == CAIRO_PATTERN_TYPE_SOLID)
{
cairo_color_t combined;
cairo_solid_pattern_t *src_solid = (cairo_solid_pattern_t *) src;
@@ -1018,7 +1018,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
if (_glitz_ensure_target (dst->surface))
return CAIRO_INT_STATUS_UNSUPPORTED;
- if (pattern->type == CAIRO_PATTERN_SURFACE)
+ if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
{
_cairo_pattern_init_copy (&tmp_src_pattern.base, pattern);
@@ -2121,6 +2121,7 @@ _cairo_glitz_surface_flush (void *abstract_surface)
}
static const cairo_surface_backend_t cairo_glitz_surface_backend = {
+ CAIRO_SURFACE_TYPE_GLITZ,
_cairo_glitz_surface_create_similar,
_cairo_glitz_surface_finish,
_cairo_glitz_surface_acquire_source_image,
diff --git a/src/cairo-hash-private.h b/src/cairo-hash-private.h
index 6dc9c9073..617b8410d 100644
--- a/src/cairo-hash-private.h
+++ b/src/cairo-hash-private.h
@@ -85,7 +85,7 @@ typedef struct _cairo_hash_entry {
} cairo_hash_entry_t;
typedef cairo_bool_t
-(*cairo_hash_keys_equal_func_t) (void *key_a, void *key_b);
+(*cairo_hash_keys_equal_func_t) (const void *key_a, const void *key_b);
typedef cairo_bool_t
(*cairo_hash_predicate_func_t) (void *entry);
diff --git a/src/cairo-hash.c b/src/cairo-hash.c
index e44ab3025..bfaac57ff 100644
--- a/src/cairo-hash.c
+++ b/src/cairo-hash.c
@@ -124,6 +124,7 @@ struct _cairo_hash_table {
cairo_hash_entry_t **entries;
unsigned long live_entries;
+ unsigned long iterating; /* Iterating, no insert, no resize */
};
/**
@@ -163,6 +164,7 @@ _cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal)
}
hash_table->live_entries = 0;
+ hash_table->iterating = 0;
return hash_table;
}
@@ -179,6 +181,10 @@ _cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal)
* and this function will halt. The rationale for this behavior is to
* avoid memory leaks and to avoid needless complication of the API
* with destroy notifiy callbacks.
+ *
+ * WARNING: The hash_table must have no running iterators in it when
+ * _cairo_hash_table_destroy is called. It is a fatal error otherwise,
+ * and this function will halt.
**/
void
_cairo_hash_table_destroy (cairo_hash_table_t *hash_table)
@@ -188,6 +194,8 @@ _cairo_hash_table_destroy (cairo_hash_table_t *hash_table)
/* The hash table must be empty. Otherwise, halt. */
assert (hash_table->live_entries == 0);
+ /* No iterators can be running. Otherwise, halt. */
+ assert (hash_table->iterating == 0);
free (hash_table->entries);
hash_table->entries = NULL;
@@ -440,6 +448,9 @@ _cairo_hash_table_random_entry (cairo_hash_table_t *hash_table,
* WARNING: It is a fatal error if an entry exists in the hash table
* with a matching key, (this function will halt).
*
+ * WARNING: It is a fatal error to insert an element while
+ * an iterator is running
+ *
* Instead of using insert to replace an entry, consider just editing
* the entry obtained with _cairo_hash_table_lookup. Or if absolutely
* necessary, use _cairo_hash_table_remove first.
@@ -454,6 +465,9 @@ _cairo_hash_table_insert (cairo_hash_table_t *hash_table,
cairo_status_t status;
cairo_hash_entry_t **entry;
+ /* Insert is illegal while an iterator is running. */
+ assert (hash_table->iterating == 0);
+
entry = _cairo_hash_table_lookup_internal (hash_table,
key_and_value, FALSE);
@@ -498,11 +512,16 @@ _cairo_hash_table_remove (cairo_hash_table_t *hash_table,
*entry = DEAD_ENTRY;
hash_table->live_entries--;
- /* This call _can_ fail, but only in failing to allocate new
- * memory to shrink the hash table. It does leave the table in a
- * consistent state, and we've already succeeded in removing the
- * entry, so we don't examine the failure status of this call. */
- _cairo_hash_table_resize (hash_table);
+ /* Check for table resize. Don't do this when iterating as this will
+ * reorder elements of the table and cause the iteration to potentially
+ * skip some elements. */
+ if (hash_table->iterating == 0) {
+ /* This call _can_ fail, but only in failing to allocate new
+ * memory to shrink the hash table. It does leave the table in a
+ * consistent state, and we've already succeeded in removing the
+ * entry, so we don't examine the failure status of this call. */
+ _cairo_hash_table_resize (hash_table);
+ }
}
/**
@@ -513,6 +532,12 @@ _cairo_hash_table_remove (cairo_hash_table_t *hash_table,
*
* Call @hash_callback for each live entry in the hash table, in a
* non-specified order.
+ *
+ * Entries in @hash_table may be removed by code executed from @hash_callback.
+ *
+ * Entries may not be inserted to @hash_table, nor may @hash_table
+ * be destroyed by code executed from @hash_callback. The relevant
+ * functions will halt in these cases.
**/
void
_cairo_hash_table_foreach (cairo_hash_table_t *hash_table,
@@ -525,9 +550,17 @@ _cairo_hash_table_foreach (cairo_hash_table_t *hash_table,
if (hash_table == NULL)
return;
+ /* Mark the table for iteration */
+ ++hash_table->iterating;
for (i = 0; i < hash_table->arrangement->size; i++) {
entry = hash_table->entries[i];
if (ENTRY_IS_LIVE(entry))
hash_callback (entry, closure);
}
+ /* If some elements were deleted during the iteration,
+ * the table may need resizing. Just do this every time
+ * as the check is inexpensive.
+ */
+ if (--hash_table->iterating == 0)
+ _cairo_hash_table_resize (hash_table);
}
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 108e89b5e..cef455b64 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -188,9 +188,10 @@ _create_pixman_format (cairo_format_t format)
* @height: height of the surface, in pixels
*
* Creates an image surface of the specified format and
- * dimensions. The initial contents of the surface is undefined; you
- * must explicitly initialize the surface contents, using, for
- * example, cairo_paint().
+ * dimensions. Initially the surface contents are all
+ * 0. (Specifically, within each pixel, each color or alpha channel
+ * belonging to format will be 0. The contents of bits within a pixel,
+ * but not belonging to the given format are undefined).
*
* Return value: a pointer to the newly created surface. The caller
* owns the surface and should call cairo_surface_destroy when done
@@ -861,7 +862,7 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op,
return status;
}
-static cairo_int_status_t
+cairo_int_status_t
_cairo_image_surface_set_clip_region (void *abstract_surface,
pixman_region16_t *region)
{
@@ -903,6 +904,7 @@ _cairo_surface_is_image (const cairo_surface_t *surface)
}
const cairo_surface_backend_t cairo_image_surface_backend = {
+ CAIRO_SURFACE_TYPE_IMAGE,
_cairo_image_surface_create_similar,
_cairo_image_surface_finish,
_cairo_image_surface_acquire_source_image,
diff --git a/src/cairo-lzw.c b/src/cairo-lzw.c
new file mode 100644
index 000000000..2a4a8e1e7
--- /dev/null
+++ b/src/cairo-lzw.c
@@ -0,0 +1,400 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2006 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ */
+
+#include "cairoint.h"
+
+typedef struct _lzw_buf {
+ cairo_status_t status;
+
+ unsigned char *data;
+ int data_size;
+ int num_data;
+ uint32_t pending;
+ int pending_bits;
+} lzw_buf_t;
+
+/* An lzw_buf_t is a simple, growable chunk of memory for holding
+ * variable-size objects of up to 16 bits each.
+ *
+ * Initialize an lzw_buf_t to the given size in bytes.
+ *
+ * To store objects into the lzw_buf_t, call _lzw_buf_store_bits and
+ * when finished, call _lzw_buf_store_pending, (which flushes out the
+ * last few bits that hadn't yet made a complete byte yet).
+ *
+ * Instead of returning failure from any functions, lzw_buf_t provides
+ * a status value that the caller can query, (and should query at
+ * least once when done with the object). The status value will be
+ * either CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY;
+ */
+static void
+_lzw_buf_init (lzw_buf_t *buf, int size)
+{
+ if (size == 0)
+ size = 16;
+
+ buf->status = CAIRO_STATUS_SUCCESS;
+
+ buf->data = malloc (size);
+ if (buf->data == NULL) {
+ buf->data_size = 0;
+ buf->status = CAIRO_STATUS_NO_MEMORY;
+ return;
+ }
+
+ buf->data_size = size;
+ buf->num_data = 0;
+ buf->pending = 0;
+ buf->pending_bits = 0;
+}
+
+/* Increase the buffer size by doubling.
+ *
+ * Returns CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY
+ */
+static cairo_status_t
+_lzw_buf_grow (lzw_buf_t *buf)
+{
+ int new_size = buf->data_size * 2;
+ unsigned char *new_data;
+
+ if (buf->status)
+ return buf->status;
+
+ new_data = realloc (buf->data, new_size);
+ if (new_data == NULL) {
+ free (buf->data);
+ buf->data_size = 0;
+ buf->status = CAIRO_STATUS_NO_MEMORY;
+ return buf->status;
+ }
+
+ buf->data = new_data;
+ buf->data_size = new_size;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* Store the lowest num_bits bits of values into buf.
+ *
+ * NOTE: The bits of value above size_in_bits must be 0, (so don't lie
+ * about the size).
+ *
+ * See also _lzw_buf_store_pending which must be called after the last
+ * call to _lzw_buf_store_bits.
+ *
+ * Sets buf->status to either CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY.
+ */
+static void
+_lzw_buf_store_bits (lzw_buf_t *buf, uint16_t value, int num_bits)
+{
+ cairo_status_t status;
+
+ assert (value <= (1 << num_bits) - 1);
+
+ if (buf->status)
+ return;
+
+ buf->pending = (buf->pending << num_bits) | value;
+ buf->pending_bits += num_bits;
+
+ while (buf->pending_bits >= 8) {
+ if (buf->num_data >= buf->data_size) {
+ status = _lzw_buf_grow (buf);
+ if (status)
+ return;
+ }
+ buf->data[buf->num_data++] = buf->pending >> (buf->pending_bits - 8);
+ buf->pending_bits -= 8;
+ }
+}
+
+/* Store the last remaining pending bits into the buffer.
+ *
+ * NOTE: This function must be called after the last call to
+ * _lzw_buf_store_bits.
+ *
+ * Sets buf->status to either CAIRO_STATUS_SUCCESS or CAIRO_STATUS_NO_MEMORY.
+ */
+static void
+_lzw_buf_store_pending (lzw_buf_t *buf)
+{
+ cairo_status_t status;
+
+ if (buf->status)
+ return;
+
+ if (buf->pending_bits == 0)
+ return;
+
+ assert (buf->pending_bits < 8);
+
+ if (buf->num_data >= buf->data_size) {
+ status = _lzw_buf_grow (buf);
+ if (status)
+ return;
+ }
+
+ buf->data[buf->num_data++] = buf->pending << (8 - buf->pending_bits);
+ buf->pending_bits = 0;
+}
+
+/* LZW defines a few magic code values */
+#define LZW_CODE_CLEAR_TABLE 256
+#define LZW_CODE_EOD 257
+#define LZW_CODE_FIRST 258
+
+/* We pack three separate values into a symbol as follows:
+ *
+ * 12 bits (31 down to 20): CODE: code value used to represent this symbol
+ * 12 bits (19 down to 8): PREV: previous code value in chain
+ * 8 bits ( 7 down to 0): NEXT: next byte value in chain
+ */
+typedef uint32_t lzw_symbol_t;
+
+#define LZW_SYMBOL_SET(sym, prev, next) ((sym) = ((prev) << 8)|(next))
+#define LZW_SYMBOL_SET_CODE(sym, code, prev, next) ((sym) = ((code << 20)|(prev) << 8)|(next))
+#define LZW_SYMBOL_GET_CODE(sym) (((sym) >> 20))
+#define LZW_SYMBOL_GET_PREV(sym) (((sym) >> 8) & 0x7ff)
+#define LZW_SYMBOL_GET_BYTE(sym) (((sym) >> 0) & 0x0ff)
+
+/* The PREV+NEXT fields can be seen as the key used to fetch values
+ * from the hash table, while the code is the value fetched.
+ */
+#define LZW_SYMBOL_KEY_MASK 0x000fffff
+
+/* Since code values are only stored starting with 258 we can safely
+ * use a zero value to represent free slots in the hash table. */
+#define LZW_SYMBOL_FREE 0x00000000
+
+/* These really aren't very free for modifying. First, the PostScript
+ * specification sets the 9-12 bit range. Second, the encoding of
+ * lzw_symbol_t above also relies on 2 of LZW_BITS_MAX plus one byte
+ * fitting within 32 bits.
+ *
+ * But other than that, the LZW compression scheme could function with
+ * more bits per code.
+ */
+#define LZW_BITS_MIN 9
+#define LZW_BITS_MAX 12
+#define LZW_BITS_BOUNDARY(bits) ((1<<(bits))-1)
+#define LZW_MAX_SYMBOLS (1<<LZW_BITS_MAX)
+
+#define LZW_SYMBOL_TABLE_SIZE 9013
+#define LZW_SYMBOL_MOD1 LZW_SYMBOL_TABLE_SIZE
+#define LZW_SYMBOL_MOD2 9011
+
+typedef struct _lzw_symbol_table {
+ lzw_symbol_t table[LZW_SYMBOL_TABLE_SIZE];
+} lzw_symbol_table_t;
+
+/* Initialize the hash table to entirely empty */
+static void
+_lzw_symbol_table_init (lzw_symbol_table_t *table)
+{
+ memset (table->table, 0, LZW_SYMBOL_TABLE_SIZE * sizeof (lzw_symbol_t));
+}
+
+/* Lookup a symbol in the symbol table. The PREV and NEXT fields of
+ * symbol form the key for the lookup.
+ *
+ * If succesful, then this function returns TRUE and slot_ret will be
+ * left pointing at the result that will have the CODE field of
+ * interest.
+ *
+ * If the lookup fails, then this function returns FALSE and slot_ret
+ * will be pointing at the location in the table to which a new CODE
+ * value should be stored along with PREV and NEXT.
+ */
+static cairo_bool_t
+_lzw_symbol_table_lookup (lzw_symbol_table_t *table,
+ lzw_symbol_t symbol,
+ lzw_symbol_t **slot_ret)
+{
+ /* The algorithm here is identical to that in cairo-hash.c. We
+ * copy it here to allow for a rather more efficient
+ * implementation due to several circumstances that do not apply
+ * to the more general case:
+ *
+ * 1) We have a known bound on the total number of symbols, so we
+ * have a fixed-size table without any copying when growing
+ *
+ * 2) We never delete any entries, so we don't need to
+ * support/check for DEAD entries during lookup.
+ *
+ * 3) The object fits in 32 bits so we store each object in its
+ * entirety within the table rather than storing objects
+ * externally and putting pointers in the table, (which here
+ * would just double the storage requirements and have negative
+ * impacts on memory locality).
+ */
+ int i, idx, step, hash = symbol & LZW_SYMBOL_KEY_MASK;
+ lzw_symbol_t candidate;
+
+ idx = hash % LZW_SYMBOL_MOD1;
+ step = 0;
+
+ *slot_ret = NULL;
+ for (i = 0; i < LZW_SYMBOL_TABLE_SIZE; i++)
+ {
+ candidate = table->table[idx];
+ if (candidate == LZW_SYMBOL_FREE)
+ {
+ *slot_ret = &table->table[idx];
+ return FALSE;
+ }
+ else /* candidate is LIVE */
+ {
+ if ((candidate & LZW_SYMBOL_KEY_MASK) ==
+ (symbol & LZW_SYMBOL_KEY_MASK))
+ {
+ *slot_ret = &table->table[idx];
+ return TRUE;
+ }
+ }
+
+ if (step == 0) {
+ step = hash % LZW_SYMBOL_MOD2;
+ if (step == 0)
+ step = 1;
+ }
+
+ idx += step;
+ if (idx >= LZW_SYMBOL_TABLE_SIZE)
+ idx -= LZW_SYMBOL_TABLE_SIZE;
+ }
+
+ return FALSE;
+}
+
+/* Compress a bytestream using the LZW algorithm.
+ *
+ * This is an original implementation based on reading the
+ * specification of the LZWDecode filter in the PostScript Language
+ * Reference. The free parameters in the LZW algorithm are set to the
+ * values mandated by PostScript, (symbols encoded with widths from 9
+ * to 12 bits).
+ *
+ * This function returns a pointer to a newly allocated buffer holding
+ * the compressed data, or NULL if an out-of-memory situation
+ * occurs.
+ *
+ * Notice that any one of the _lzw_buf functions called here could
+ * trigger an out-of-memory condition. But lzw_buf_t uses cairo's
+ * shutdown-on-error idiom, so it's safe to continue to call into
+ * lzw_buf without having to check for errors, (until a final check at
+ * the end).
+ */
+cairo_public unsigned char *
+_cairo_lzw_compress (unsigned char *data, unsigned long *size_in_out)
+{
+ int bytes_remaining = *size_in_out;
+ lzw_buf_t buf;
+ lzw_symbol_table_t table;
+ lzw_symbol_t symbol, *slot;
+ int code_next = LZW_CODE_FIRST;
+ int code_bits = LZW_BITS_MIN;
+ int prev, next;
+
+ if (*size_in_out == 0)
+ return NULL;
+
+ _lzw_buf_init (&buf, *size_in_out);
+
+ _lzw_symbol_table_init (&table);
+
+ /* The LZW header is a clear table code. */
+ _lzw_buf_store_bits (&buf, LZW_CODE_CLEAR_TABLE, code_bits);
+
+ while (1) {
+
+ /* Find the longest existing code in the symbol table that
+ * matches the current input, if any. */
+ prev = *data++;
+ bytes_remaining--;
+ if (bytes_remaining) {
+ do
+ {
+ next = *data++;
+ bytes_remaining--;
+ LZW_SYMBOL_SET (symbol, prev, next);
+ if (_lzw_symbol_table_lookup (&table, symbol, &slot))
+ prev = LZW_SYMBOL_GET_CODE (*slot);
+ } while (bytes_remaining && *slot != LZW_SYMBOL_FREE);
+ if (*slot == LZW_SYMBOL_FREE) {
+ data--;
+ bytes_remaining++;
+ }
+ }
+
+ /* Write the code into the output. This is either a byte read
+ * directly from the input, or a code from the last successful
+ * lookup. */
+ _lzw_buf_store_bits (&buf, prev, code_bits);
+
+ if (bytes_remaining == 0)
+ break;
+
+ LZW_SYMBOL_SET_CODE (*slot, code_next++, prev, next);
+
+ if (code_next > LZW_BITS_BOUNDARY(code_bits))
+ {
+ code_bits++;
+ if (code_bits > LZW_BITS_MAX) {
+ _lzw_symbol_table_init (&table);
+ _lzw_buf_store_bits (&buf, LZW_CODE_CLEAR_TABLE, code_bits - 1);
+ code_bits = LZW_BITS_MIN;
+ code_next = LZW_CODE_FIRST;
+ }
+ }
+ }
+
+ /* The LZW footer is an end-of-data code. */
+ _lzw_buf_store_bits (&buf, LZW_CODE_EOD, code_bits);
+
+ _lzw_buf_store_pending (&buf);
+
+ /* See if we ever ran out of memory while writing to buf. */
+ if (buf.status == CAIRO_STATUS_NO_MEMORY) {
+ *size_in_out = 0;
+ return NULL;
+ }
+
+ assert (buf.status == CAIRO_STATUS_SUCCESS);
+
+ *size_in_out = buf.num_data;
+ return buf.data;
+}
diff --git a/src/cairo-meta-surface-private.h b/src/cairo-meta-surface-private.h
index e57150904..eafe3f441 100644
--- a/src/cairo-meta-surface-private.h
+++ b/src/cairo-meta-surface-private.h
@@ -53,7 +53,7 @@ typedef enum {
* fallbacks should never get triggered). So the plan is to
* eliminate as many of these as possible. */
- CAIRO_COMMAND_INTERSECT_CLIP_PATH,
+ CAIRO_COMMAND_INTERSECT_CLIP_PATH
} cairo_command_type_t;
diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c
index a314150bc..f7aeb719c 100644
--- a/src/cairo-meta-surface.c
+++ b/src/cairo-meta-surface.c
@@ -201,7 +201,7 @@ _init_pattern_with_snapshot (cairo_pattern_t *pattern,
{
_cairo_pattern_init_copy (pattern, other);
- if (pattern->type == CAIRO_PATTERN_SURFACE) {
+ if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern =
(cairo_surface_pattern_t *) pattern;
cairo_surface_t *surface = surface_pattern->surface;
@@ -557,6 +557,7 @@ _cairo_surface_is_meta (const cairo_surface_t *surface)
}
static const cairo_surface_backend_t cairo_meta_surface_backend = {
+ CAIRO_INTERNAL_SURFACE_TYPE_META,
_cairo_meta_surface_create_similar,
_cairo_meta_surface_finish,
_cairo_meta_surface_acquire_source_image,
diff --git a/src/cairo-operator.c b/src/cairo-operator.c
new file mode 100644
index 000000000..99c3aaaa0
--- /dev/null
+++ b/src/cairo-operator.c
@@ -0,0 +1,119 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2006 Keith Packard
+ * Copyright © 2006 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ * Carl D. Worth <cworth@cworth.org>
+ * Keith Packard <keithp@keithp.com>
+ */
+
+#include "cairoint.h"
+
+/* The analysis here assumes destination alpha semantics (that is
+ * CAIRO_CONTENT_COLOR_ALPHA). More things can be considered opaque
+ * otherwise (CAIRO_CONTENT_COLOR) so we'll probably want to add a
+ * cairo_content_t parameter to this function
+ *
+ * We also need a definition of what "opaque" means. Is it, "does not
+ * requiring 'knowing' the original contents of destination, nor does
+ * it set the destination alpha to anything but 1.0" ?
+ */
+cairo_bool_t
+_cairo_operator_always_opaque (cairo_operator_t op)
+{
+ switch (op) {
+ case CAIRO_OPERATOR_CLEAR:
+ return FALSE;
+
+ case CAIRO_OPERATOR_SOURCE:
+ return FALSE;
+
+ case CAIRO_OPERATOR_OVER:
+ case CAIRO_OPERATOR_IN:
+ case CAIRO_OPERATOR_OUT:
+ case CAIRO_OPERATOR_ATOP:
+ return FALSE;
+
+ case CAIRO_OPERATOR_DEST:
+ return TRUE;
+
+ case CAIRO_OPERATOR_DEST_OVER:
+ case CAIRO_OPERATOR_DEST_IN:
+ case CAIRO_OPERATOR_DEST_OUT:
+ case CAIRO_OPERATOR_DEST_ATOP:
+ return FALSE;
+
+ case CAIRO_OPERATOR_XOR:
+ case CAIRO_OPERATOR_ADD:
+ case CAIRO_OPERATOR_SATURATE:
+ return FALSE;
+ }
+ return FALSE;
+}
+
+/* As above, we'll probably want to add a cairo_content_t parameter to
+ * this function
+ *
+ * We also need a definition of what "translucent" means.
+ */
+cairo_bool_t
+_cairo_operator_always_translucent (cairo_operator_t op)
+{
+ switch (op) {
+ case CAIRO_OPERATOR_CLEAR:
+ return TRUE;
+
+ case CAIRO_OPERATOR_SOURCE:
+ return FALSE;
+
+ case CAIRO_OPERATOR_OVER:
+ case CAIRO_OPERATOR_IN:
+ case CAIRO_OPERATOR_OUT:
+ case CAIRO_OPERATOR_ATOP:
+ return FALSE;
+
+ case CAIRO_OPERATOR_DEST:
+ return FALSE;
+
+ case CAIRO_OPERATOR_DEST_OVER:
+ case CAIRO_OPERATOR_DEST_IN:
+ case CAIRO_OPERATOR_DEST_OUT:
+ case CAIRO_OPERATOR_DEST_ATOP:
+ return FALSE;
+
+ case CAIRO_OPERATOR_XOR:
+ case CAIRO_OPERATOR_ADD:
+ case CAIRO_OPERATOR_SATURATE:
+ return TRUE;
+ }
+ return TRUE;
+}
diff --git a/src/cairo-output-stream.c b/src/cairo-output-stream.c
index a6db09198..e9b572786 100644
--- a/src/cairo-output-stream.c
+++ b/src/cairo-output-stream.c
@@ -44,54 +44,92 @@
#endif /* _MSC_VER */
struct _cairo_output_stream {
- cairo_write_func_t write_data;
+ cairo_write_func_t write_func;
+ cairo_close_func_t close_func;
void *closure;
- cairo_bool_t owns_closure_is_file;
unsigned long position;
cairo_status_t status;
+ cairo_bool_t closed;
+};
+
+const cairo_output_stream_t cairo_output_stream_nil = {
+ NULL, /* write_func */
+ NULL, /* close_func */
+ NULL, /* closure */
+ 0, /* position */
+ CAIRO_STATUS_NO_MEMORY,
+ FALSE /* closed */
+};
+
+static const cairo_output_stream_t cairo_output_stream_nil_write_error = {
+ NULL, /* write_func */
+ NULL, /* close_func */
+ NULL, /* closure */
+ 0, /* position */
+ CAIRO_STATUS_WRITE_ERROR,
+ FALSE /* closed */
};
cairo_output_stream_t *
-_cairo_output_stream_create (cairo_write_func_t write_data,
+_cairo_output_stream_create (cairo_write_func_t write_func,
+ cairo_close_func_t close_func,
void *closure)
{
cairo_output_stream_t *stream;
stream = malloc (sizeof (cairo_output_stream_t));
if (stream == NULL)
- return NULL;
+ return (cairo_output_stream_t *) &cairo_output_stream_nil;
- stream->write_data = write_data;
+ stream->write_func = write_func;
+ stream->close_func = close_func;
stream->closure = closure;
- stream->owns_closure_is_file = FALSE;
stream->position = 0;
stream->status = CAIRO_STATUS_SUCCESS;
+ stream->closed = FALSE;
return stream;
}
void
-_cairo_output_stream_destroy (cairo_output_stream_t *stream)
+_cairo_output_stream_close (cairo_output_stream_t *stream)
{
- if (stream->owns_closure_is_file) {
- FILE *file = stream->closure;
- fflush (file);
- fclose (file);
+ cairo_status_t status;
+
+ if (stream->closed)
+ return;
+
+ if (stream->close_func) {
+ status = stream->close_func (stream->closure);
+ if (status)
+ stream->status = status;
}
+
+ stream->closed = TRUE;
+}
+
+void
+_cairo_output_stream_destroy (cairo_output_stream_t *stream)
+{
+ if (stream == NULL)
+ return;
+
+ _cairo_output_stream_close (stream);
free (stream);
}
-cairo_status_t
+void
_cairo_output_stream_write (cairo_output_stream_t *stream,
const void *data, size_t length)
{
if (length == 0)
- return CAIRO_STATUS_SUCCESS;
+ return;
- stream->status = stream->write_data (stream->closure, data, length);
- stream->position += length;
+ if (stream->status)
+ return;
- return stream->status;
+ stream->status = stream->write_func (stream->closure, data, length);
+ stream->position += length;
}
void
@@ -103,6 +141,9 @@ _cairo_output_stream_write_hex_string (cairo_output_stream_t *stream,
char buffer[2];
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);
@@ -175,8 +216,7 @@ enum {
* formatting. This functionality is only for internal use and we
* only implement the formats we actually use.
*/
-
-cairo_status_t
+void
_cairo_output_stream_vprintf (cairo_output_stream_t *stream,
const char *fmt, va_list ap)
{
@@ -185,6 +225,9 @@ _cairo_output_stream_vprintf (cairo_output_stream_t *stream,
const char *f;
int length_modifier;
+ if (stream->status)
+ return;
+
f = fmt;
p = buffer;
while (*f != '\0') {
@@ -247,24 +290,19 @@ _cairo_output_stream_vprintf (cairo_output_stream_t *stream,
}
_cairo_output_stream_write (stream, buffer, p - buffer);
-
- return stream->status;
}
-cairo_status_t
+void
_cairo_output_stream_printf (cairo_output_stream_t *stream,
const char *fmt, ...)
{
va_list ap;
- cairo_status_t status;
va_start (ap, fmt);
- status = _cairo_output_stream_vprintf (stream, fmt, ap);
+ _cairo_output_stream_vprintf (stream, fmt, ap);
va_end (ap);
-
- return status;
}
long
@@ -286,28 +324,57 @@ _cairo_output_stream_get_status (cairo_output_stream_t *stream)
static cairo_status_t
stdio_write (void *closure, const unsigned char *data, unsigned int length)
{
- FILE *fp = closure;
+ FILE *file = closure;
+
+ if (fwrite (data, 1, length, file) != length)
+ return CAIRO_STATUS_WRITE_ERROR;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+stdio_flush (void *closure)
+{
+ FILE *file = closure;
+
+ fflush (file);
- if (fwrite (data, 1, length, fp) == length)
+ if (ferror (file))
+ return CAIRO_STATUS_WRITE_ERROR;
+ else
return CAIRO_STATUS_SUCCESS;
+}
- return CAIRO_STATUS_WRITE_ERROR;
+static cairo_status_t
+stdio_close (void *closure)
+{
+ cairo_status_t status;
+ FILE *file = closure;
+
+ status = stdio_flush (closure);
+
+ fclose (file);
+
+ return status;
}
cairo_output_stream_t *
-_cairo_output_stream_create_for_file (const char *filename)
+_cairo_output_stream_create_for_file (FILE *file)
{
- FILE *fp;
- cairo_output_stream_t *stream;
+ if (file == NULL)
+ return (cairo_output_stream_t *) &cairo_output_stream_nil_write_error;
- fp = fopen (filename, "wb");
- if (fp == NULL)
- return NULL;
-
- stream = _cairo_output_stream_create (stdio_write, fp);
- if (stream == NULL)
- fclose (fp);
- stream->owns_closure_is_file = TRUE;
+ return _cairo_output_stream_create (stdio_write, stdio_flush, file);
+}
- return stream;
+cairo_output_stream_t *
+_cairo_output_stream_create_for_filename (const char *filename)
+{
+ FILE *file;
+
+ file = fopen (filename, "wb");
+ if (file == NULL)
+ return (cairo_output_stream_t *) &cairo_output_stream_nil_write_error;
+
+ return _cairo_output_stream_create (stdio_write, stdio_close, file);
}
diff --git a/src/cairo-paginated-surface-private.h b/src/cairo-paginated-surface-private.h
index 79438e4ab..b5e4d5c9b 100644
--- a/src/cairo-paginated-surface-private.h
+++ b/src/cairo-paginated-surface-private.h
@@ -38,11 +38,99 @@
#include "cairoint.h"
+typedef enum {
+ CAIRO_PAGINATED_MODE_ANALYZE, /* analyze page regions */
+ CAIRO_PAGINATED_MODE_RENDER /* render page contents */
+} cairo_paginated_mode_t;
+
+typedef struct _cairo_paginated_surface_backend {
+ /* Optional. Will be called once for each page.
+ *
+ * NOTE: With respect to the order of drawing operations as seen
+ * by the target, this call will occur before any drawing
+ * operations for the relevant page. However, with respect to the
+ * function calls as made by the user, this call will be *after*
+ * any drawing operations for the page, (that is, it will occur
+ * during the user's call to cairo_show_page or cairo_copy_page).
+ */
+ cairo_int_status_t
+ (*start_page) (void *surface);
+
+ /* Required. Will be called twice for each page, once with an
+ * argument of CAIRO_PAGINATED_MODE_ANALYZE and once with
+ * CAIRO_PAGINATED_MODE_RENDER. See more details in the
+ * documentation for _cairo_paginated_surface_create below.
+ */
+ void
+ (*set_paginated_mode) (void *surface,
+ cairo_paginated_mode_t mode);
+} cairo_paginated_surface_backend_t;
+
+/* A cairo_paginated_surface provides a very convenient wrapper that
+ * is well-suited for doing the analysis common to most surfaces that
+ * have paginated output, (that is, things directed at printers, or
+ * for saving content in files such as PostScript or PDF files).
+ *
+ * To use the paginated surface, you'll first need to create your
+ * 'real' surface using _cairo_surface_init and the standard
+ * cairo_surface_backend_t. Then you also call
+ * _cairo_paginated_surface_create which takes its own, much simpler,
+ * cairo_paginated_surface_backend. You are free to return the result
+ * of _cairo_paginated_surface_create from your public
+ * cairo_<foo>_surface_create. The paginated backend will be careful
+ * to not let the user see that they really got a "wrapped"
+ * surface. See test-paginated-surface.c for a fairly minimal example
+ * of a paginated-using surface. That should be a reasonable example
+ * to follow.
+ *
+ * What the paginated surface does is first save all drawing
+ * operations for a page into a meta-surface. Then when the user calls
+ * cairo_show_page, the paginated surface performs the following
+ * sequence of operations (using the backend functions passed to
+ * cairo_paginated_surface_create):
+ *
+ * 1. Calls start_page (if non NULL). At this point, it is appropriate
+ * for the target to emit any page-specific header information into
+ * its output.
+ *
+ * 2. Calls set_paginated_mode with an argument of CAIRO_PAGINATED_MODE_ANALYZE
+ *
+ * 3. Replays the meta-surface to the target surface, (with an
+ * analysis surface inserted between which watches the return value
+ * from each operation). This analysis stage is used to decide which
+ * operations will require fallbacks.
+ *
+ * 4. Calls set_paginated_mode with an argument of CAIRO_PAGINATED_MODE_RENDER
+ *
+ * 5. Replays a subset of the meta-surface operations to the target surface
+ *
+ * 6. Replays the remaining operations to an image surface, sets an
+ * appropriate clip on the target, then paints the resulting image
+ * surface to the target.
+ *
+ * So, the target will see drawing operations during two separate
+ * stages, (ANALYZE and RENDER). During the ANALYZE phase the target
+ * should not actually perform any rendering, (for example, if
+ * performing output to a file, no output should be generated during
+ * this stage). Instead the drawing functions simply need to return
+ * CAIRO_STATUS_SUCCESS or CAIRO_INT_STATUS_UNSUPPORTED to indicate
+ * whether rendering would be supported. And it should do this as
+ * quickly as possible.
+ *
+ * NOTE: The paginated surface layer assumes that the target surface
+ * is "blank" by default at the beginning of each page, without any
+ * need for an explicit erasea operation, (as opposed to an image
+ * surface, for example, which might have uninitialized content
+ * originally). As such, it optimizes away CLEAR operations that
+ * happen at the beginning of each page---the target surface will not
+ * even see these operations.
+ */
cairo_private cairo_surface_t *
-_cairo_paginated_surface_create (cairo_surface_t *target,
- cairo_content_t content,
- int width,
- int height);
+_cairo_paginated_surface_create (cairo_surface_t *target,
+ cairo_content_t content,
+ int width,
+ int height,
+ const cairo_paginated_surface_backend_t *backend);
cairo_private cairo_surface_t *
_cairo_paginated_surface_get_target (cairo_surface_t *surface);
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index 6317d7083..34b42e777 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -31,47 +31,27 @@
*
* Contributor(s):
* Carl Worth <cworth@cworth.org>
+ * Keith Packard <keithp@keithp.com>
*/
/* The paginated surface layer exists to provide as much code sharing
* as possible for the various paginated surface backends in cairo
- * (PostScript, PDF, etc.).
- *
- * The concept is that a surface which uses a paginated surface merely
- * needs to implement backend operations which it can accurately
- * provide, (and return CAIRO_INT_STATUS_UNSUPPORTED or leave backend
- * function pointers NULL otherwise). The paginated surface is the
- * responsible for collecting operations that aren't supported,
- * replaying them against the image surface, and then supplying the
- * resulting images to the target surface.
- *
- * When created, a paginated surface accepts the target surface to
- * which the final drawing will eventually be performed. The paginated
- * surface then uses cairo_meta_surface_t to record all drawing
- * operations up until each show_page operation.
- *
- * At the time of show_page, the paginated surface replays the meta
- * surface against the target surface and maintains regions of the
- * result that will come from the nativ surface and regions that will
- * need to come from image fallbacks. It then replays the necessary
- * portions against image surface and provides those results to the
- * target surface through existing interfaces.
- *
- * This way the target surface is never even aware of any distinction
- * between native drawing operations vs. results that are supplied by
- * image fallbacks. Instead the surface need only implement as much of
- * the surface backend interface as it can do correctly, and let the
- * paginated surface take care of all the messy details.
+ * (PostScript, PDF, etc.). See cairo-paginated-surface-private.h for
+ * more details on how it works and how to use it.
*/
#include "cairoint.h"
#include "cairo-paginated-surface-private.h"
#include "cairo-meta-surface-private.h"
+#include "cairo-analysis-surface-private.h"
typedef struct _cairo_paginated_surface {
cairo_surface_t base;
+ /* The target surface to hold the final result. */
+ cairo_surface_t *target;
+
cairo_content_t content;
/* XXX: These shouldn't actually exist. We inherit this ugliness
@@ -82,14 +62,16 @@ typedef struct _cairo_paginated_surface {
int width;
int height;
- /* The target surface to hold the final result. */
- cairo_surface_t *target;
+ /* Paginated-surface specific functions for the target */
+ const cairo_paginated_surface_backend_t *backend;
/* A cairo_meta_surface to record all operations. To be replayed
* against target, and also against image surface as necessary for
* fallbacks. */
cairo_surface_t *meta;
+ cairo_bool_t page_is_blank;
+
} cairo_paginated_surface_t;
const cairo_private cairo_surface_backend_t cairo_paginated_surface_backend;
@@ -97,11 +79,30 @@ const cairo_private cairo_surface_backend_t cairo_paginated_surface_backend;
static cairo_int_status_t
_cairo_paginated_surface_show_page (void *abstract_surface);
+/* XXX: This would seem the natural thing to do here. But currently,
+ * PDF and PS surfaces do not yet work as source surfaces. So instead,
+ * we don't implement create_similar for the paginate_surface which
+ * means that any create_similar() call on a paginated_surfacae will
+ * result in a new image surface. */
+#if 0
+static cairo_surface_t *
+_cairo_paginated_surface_create_similar (void *abstract_surface,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ cairo_paginated_surface_t *surface = abstract_surface;
+ return cairo_surface_create_similar (surface->target, content,
+ width, height);
+}
+#endif
+
cairo_surface_t *
-_cairo_paginated_surface_create (cairo_surface_t *target,
- cairo_content_t content,
- int width,
- int height)
+_cairo_paginated_surface_create (cairo_surface_t *target,
+ cairo_content_t content,
+ int width,
+ int height,
+ const cairo_paginated_surface_backend_t *backend)
{
cairo_paginated_surface_t *surface;
@@ -111,16 +112,24 @@ _cairo_paginated_surface_create (cairo_surface_t *target,
_cairo_surface_init (&surface->base, &cairo_paginated_surface_backend);
+ /* Override surface->base.type with target's type so we don't leak
+ * evidence of the paginated wrapper out to the user. */
+ surface->base.type = cairo_surface_get_type (target);
+
+ surface->target = target;
+
surface->content = content;
surface->width = width;
surface->height = height;
- surface->target = target;
+ surface->backend = backend;
surface->meta = _cairo_meta_surface_create (content, width, height);
if (cairo_surface_status (surface->meta))
goto FAIL_CLEANUP_SURFACE;
+ surface->page_is_blank = TRUE;
+
return &surface->base;
FAIL_CLEANUP_SURFACE:
@@ -191,32 +200,70 @@ _cairo_paginated_surface_release_source_image (void *abstract_surface,
cairo_surface_destroy (&image->base);
}
-static void
+static cairo_int_status_t
_paint_page (cairo_paginated_surface_t *surface)
{
+ cairo_surface_t *analysis;
cairo_surface_t *image;
cairo_pattern_t *pattern;
+ cairo_status_t status;
- image = _cairo_image_surface_create_with_content (surface->content,
- surface->width,
- surface->height);
+ analysis = _cairo_analysis_surface_create (surface->target,
+ surface->width, surface->height);
- _cairo_meta_surface_replay (surface->meta, image);
+ surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_ANALYZE);
+ _cairo_meta_surface_replay (surface->meta, analysis);
+ surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_RENDER);
+
+ if (analysis->status) {
+ status = analysis->status;
+ cairo_surface_destroy (analysis);
+ return status;
+ }
+
+ if (_cairo_analysis_surface_has_unsupported (analysis))
+ {
+ image = _cairo_image_surface_create_with_content (surface->content,
+ surface->width,
+ surface->height);
+
+ _cairo_meta_surface_replay (surface->meta, image);
- pattern = cairo_pattern_create_for_surface (image);
+ pattern = cairo_pattern_create_for_surface (image);
- _cairo_surface_paint (surface->target, CAIRO_OPERATOR_SOURCE, pattern);
+ _cairo_surface_paint (surface->target, CAIRO_OPERATOR_SOURCE, pattern);
- cairo_pattern_destroy (pattern);
+ cairo_pattern_destroy (pattern);
+
+ cairo_surface_destroy (image);
+ }
+ else
+ {
+ _cairo_meta_surface_replay (surface->meta, surface->target);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_start_page (cairo_paginated_surface_t *surface)
+{
+ if (! surface->backend->start_page)
+ return CAIRO_STATUS_SUCCESS;
- cairo_surface_destroy (image);
+ return (surface->backend->start_page) (surface->target);
}
static cairo_int_status_t
_cairo_paginated_surface_copy_page (void *abstract_surface)
{
+ cairo_status_t status;
cairo_paginated_surface_t *surface = abstract_surface;
+ status = _start_page (surface);
+ if (status)
+ return status;
+
_paint_page (surface);
/* XXX: It might make sense to add some suport here for calling
@@ -235,8 +282,13 @@ _cairo_paginated_surface_copy_page (void *abstract_surface)
static cairo_int_status_t
_cairo_paginated_surface_show_page (void *abstract_surface)
{
+ cairo_status_t status;
cairo_paginated_surface_t *surface = abstract_surface;
+ status = _start_page (surface);
+ if (status)
+ return status;
+
_paint_page (surface);
_cairo_surface_show_page (surface->target);
@@ -248,6 +300,8 @@ _cairo_paginated_surface_show_page (void *abstract_surface)
if (cairo_surface_status (surface->meta))
return cairo_surface_status (surface->meta);
+ surface->page_is_blank = TRUE;
+
return CAIRO_STATUS_SUCCESS;
}
@@ -281,6 +335,12 @@ _cairo_paginated_surface_paint (void *abstract_surface,
{
cairo_paginated_surface_t *surface = abstract_surface;
+ /* Optimize away erasing of nothing. */
+ if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
+ return CAIRO_STATUS_SUCCESS;
+
+ surface->page_is_blank = FALSE;
+
return _cairo_surface_paint (surface->meta, op, source);
}
@@ -308,6 +368,12 @@ _cairo_paginated_surface_stroke (void *abstract_surface,
{
cairo_paginated_surface_t *surface = abstract_surface;
+ /* Optimize away erasing of nothing. */
+ if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
+ return CAIRO_STATUS_SUCCESS;
+
+ surface->page_is_blank = FALSE;
+
return _cairo_surface_stroke (surface->meta, op, source,
path, style,
ctm, ctm_inverse,
@@ -325,6 +391,12 @@ _cairo_paginated_surface_fill (void *abstract_surface,
{
cairo_paginated_surface_t *surface = abstract_surface;
+ /* Optimize away erasing of nothing. */
+ if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
+ return CAIRO_STATUS_SUCCESS;
+
+ surface->page_is_blank = FALSE;
+
return _cairo_surface_fill (surface->meta, op, source,
path, fill_rule,
tolerance, antialias);
@@ -340,6 +412,12 @@ _cairo_paginated_surface_show_glyphs (void *abstract_surface,
{
cairo_paginated_surface_t *surface = abstract_surface;
+ /* Optimize away erasing of nothing. */
+ if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
+ return CAIRO_STATUS_SUCCESS;
+
+ surface->page_is_blank = FALSE;
+
return _cairo_surface_show_glyphs (surface->meta, op, source,
glyphs, num_glyphs,
scaled_font);
@@ -381,7 +459,8 @@ _cairo_paginated_surface_snapshot (void *abstract_other)
}
const cairo_surface_backend_t cairo_paginated_surface_backend = {
- NULL, /* create_similar */
+ CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED,
+ NULL, /* create_similar --- see note for _cairo_paginated_surface_create_similar */
_cairo_paginated_surface_finish,
_cairo_paginated_surface_acquire_source_image,
_cairo_paginated_surface_release_source_image,
diff --git a/src/cairo-path-stroke.c b/src/cairo-path-stroke.c
index e8170990e..7ca6ab811 100644
--- a/src/cairo-path-stroke.c
+++ b/src/cairo-path-stroke.c
@@ -115,7 +115,11 @@ _cairo_stroker_start_dash (cairo_stroker_t *stroker)
int i = 0;
offset = stroker->style->dash_offset;
- while (offset >= stroker->style->dash[i]) {
+
+ /* We stop searching for a starting point as soon as the
+ offset reaches zero. Otherwise when an initial dash
+ segment shrinks to zero it will be skipped over. */
+ while (offset > 0.0 && offset >= stroker->style->dash[i]) {
offset -= stroker->style->dash[i];
on = 1-on;
if (++i == stroker->style->num_dashes)
@@ -546,11 +550,18 @@ _compute_face (cairo_point_t *point, cairo_slope_t *slope, cairo_stroker_t *stro
static cairo_status_t
_cairo_stroker_add_sub_edge (cairo_stroker_t *stroker, cairo_point_t *p1, cairo_point_t *p2,
- cairo_stroke_face_t *start, cairo_stroke_face_t *end)
+ cairo_slope_t *slope, cairo_stroke_face_t *start,
+ cairo_stroke_face_t *end)
{
cairo_status_t status;
cairo_polygon_t polygon;
- cairo_slope_t slope;
+
+ _compute_face (p1, slope, stroker, start);
+
+ /* XXX: This could be optimized slightly by not calling
+ _compute_face again but rather translating the relevant
+ fields from start. */
+ _compute_face (p2, slope, stroker, end);
if (p1->x == p2->x && p1->y == p2->y) {
/* XXX: Need to rethink how this case should be handled, (both
@@ -559,14 +570,6 @@ _cairo_stroker_add_sub_edge (cairo_stroker_t *stroker, cairo_point_t *p1, cairo_
return CAIRO_STATUS_SUCCESS;
}
- _cairo_slope_init (&slope, p1, p2);
- _compute_face (p1, &slope, stroker, start);
-
- /* XXX: This could be optimized slightly by not calling
- _compute_face again but rather translating the relevant
- fields from start. */
- _compute_face (p2, &slope, stroker, end);
-
/* XXX: I should really check the return value of the
move_to/line_to functions here to catch out of memory
conditions. But since that would be ugly, I'd prefer to add a
@@ -613,6 +616,16 @@ _cairo_stroker_move_to (void *closure, cairo_point_t *point)
}
static cairo_status_t
+_cairo_stroker_move_to_dashed (void *closure, cairo_point_t *point)
+{
+ /* reset the dash pattern for new sub paths */
+ cairo_stroker_t *stroker = closure;
+ _cairo_stroker_start_dash (stroker);
+
+ return _cairo_stroker_move_to (closure, point);
+}
+
+static cairo_status_t
_cairo_stroker_line_to (void *closure, cairo_point_t *point)
{
cairo_status_t status;
@@ -620,6 +633,7 @@ _cairo_stroker_line_to (void *closure, cairo_point_t *point)
cairo_stroke_face_t start, end;
cairo_point_t *p1 = &stroker->current_point;
cairo_point_t *p2 = point;
+ cairo_slope_t slope;
if (p1->x == p2->x && p1->y == p2->y) {
/* XXX: Need to rethink how this case should be handled, (both
@@ -628,8 +642,10 @@ _cairo_stroker_line_to (void *closure, cairo_point_t *point)
as possible. */
return CAIRO_STATUS_SUCCESS;
}
+
+ _cairo_slope_init (&slope, p1, p2);
- status = _cairo_stroker_add_sub_edge (stroker, p1, p2, &start, &end);
+ status = _cairo_stroker_add_sub_edge (stroker, p1, p2, &slope, &start, &end);
if (status)
return status;
@@ -667,6 +683,17 @@ _cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point)
cairo_stroke_face_t sub_start, sub_end;
cairo_point_t *p1 = &stroker->current_point;
cairo_point_t *p2 = point;
+ cairo_slope_t slope;
+
+ if (p1->x == p2->x && p1->y == p2->y) {
+ /* XXX: Need to rethink how this case should be handled, (both
+ here and in cairo_stroker_add_sub_edge and in _compute_face). The
+ key behavior is that degenerate paths should draw as much
+ as possible. */
+ return CAIRO_STATUS_SUCCESS;
+ }
+
+ _cairo_slope_init (&slope, p1, p2);
dx = _cairo_fixed_to_double (p2->x - p1->x);
dy = _cairo_fixed_to_double (p2->y - p1->y);
@@ -692,7 +719,7 @@ _cairo_stroker_line_to_dashed (void *closure, cairo_point_t *point)
* XXX simplify this case analysis
*/
if (stroker->dash_on) {
- status = _cairo_stroker_add_sub_edge (stroker, &fd1, &fd2, &sub_start, &sub_end);
+ status = _cairo_stroker_add_sub_edge (stroker, &fd1, &fd2, &slope, &sub_start, &sub_end);
if (status)
return status;
if (!first) {
@@ -942,7 +969,7 @@ _cairo_path_fixed_stroke_to_traps (cairo_path_fixed_t *path,
if (stroker.style->dash)
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
- _cairo_stroker_move_to,
+ _cairo_stroker_move_to_dashed,
_cairo_stroker_line_to_dashed,
_cairo_stroker_curve_to_dashed,
_cairo_stroker_close_path,
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index d7b73693b..3f0b5e457 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -30,7 +30,7 @@
#include "cairoint.h"
const cairo_solid_pattern_t cairo_pattern_nil = {
- { CAIRO_PATTERN_SOLID, /* type */
+ { CAIRO_PATTERN_TYPE_SOLID, /* type */
(unsigned int)-1, /* ref_count */
CAIRO_STATUS_NO_MEMORY, /* status */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
@@ -39,7 +39,7 @@ const cairo_solid_pattern_t cairo_pattern_nil = {
};
static const cairo_solid_pattern_t cairo_pattern_nil_null_pointer = {
- { CAIRO_PATTERN_SOLID, /* type */
+ { CAIRO_PATTERN_TYPE_SOLID, /* type */
(unsigned int)-1, /* ref_count */
CAIRO_STATUS_NULL_POINTER,/* status */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
@@ -48,7 +48,7 @@ static const cairo_solid_pattern_t cairo_pattern_nil_null_pointer = {
};
static const cairo_solid_pattern_t cairo_pattern_nil_file_not_found = {
- { CAIRO_PATTERN_SOLID, /* type */
+ { CAIRO_PATTERN_TYPE_SOLID, /* type */
(unsigned int)-1, /* ref_count */
CAIRO_STATUS_FILE_NOT_FOUND, /* status */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
@@ -57,7 +57,7 @@ static const cairo_solid_pattern_t cairo_pattern_nil_file_not_found = {
};
static const cairo_solid_pattern_t cairo_pattern_nil_read_error = {
- { CAIRO_PATTERN_SOLID, /* type */
+ { CAIRO_PATTERN_TYPE_SOLID, /* type */
(unsigned int)-1, /* ref_count */
CAIRO_STATUS_READ_ERROR, /* status */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */
@@ -117,7 +117,7 @@ _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
pattern->ref_count = 1;
pattern->status = CAIRO_STATUS_SUCCESS;
- if (type == CAIRO_PATTERN_SURFACE)
+ if (type == CAIRO_PATTERN_TYPE_SURFACE)
pattern->extend = CAIRO_EXTEND_SURFACE_DEFAULT;
else
pattern->extend = CAIRO_EXTEND_GRADIENT_DEFAULT;
@@ -131,7 +131,7 @@ static void
_cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern,
const cairo_gradient_pattern_t *other)
{
- if (other->base.type == CAIRO_PATTERN_LINEAR)
+ if (other->base.type == CAIRO_PATTERN_TYPE_LINEAR)
{
cairo_linear_pattern_t *dst = (cairo_linear_pattern_t *) pattern;
cairo_linear_pattern_t *src = (cairo_linear_pattern_t *) other;
@@ -170,21 +170,21 @@ _cairo_pattern_init_copy (cairo_pattern_t *pattern,
}
switch (other->type) {
- case CAIRO_PATTERN_SOLID: {
+ case CAIRO_PATTERN_TYPE_SOLID: {
cairo_solid_pattern_t *dst = (cairo_solid_pattern_t *) pattern;
cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) other;
*dst = *src;
} break;
- case CAIRO_PATTERN_SURFACE: {
+ case CAIRO_PATTERN_TYPE_SURFACE: {
cairo_surface_pattern_t *dst = (cairo_surface_pattern_t *) pattern;
cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) other;
*dst = *src;
cairo_surface_reference (dst->surface);
} break;
- case CAIRO_PATTERN_LINEAR:
- case CAIRO_PATTERN_RADIAL: {
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ case CAIRO_PATTERN_TYPE_RADIAL: {
cairo_gradient_pattern_t *dst = (cairo_gradient_pattern_t *) pattern;
cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) other;
@@ -199,16 +199,16 @@ void
_cairo_pattern_fini (cairo_pattern_t *pattern)
{
switch (pattern->type) {
- case CAIRO_PATTERN_SOLID:
+ case CAIRO_PATTERN_TYPE_SOLID:
break;
- case CAIRO_PATTERN_SURFACE: {
+ case CAIRO_PATTERN_TYPE_SURFACE: {
cairo_surface_pattern_t *surface_pattern =
(cairo_surface_pattern_t *) pattern;
cairo_surface_destroy (surface_pattern->surface);
} break;
- case CAIRO_PATTERN_LINEAR:
- case CAIRO_PATTERN_RADIAL: {
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ case CAIRO_PATTERN_TYPE_RADIAL: {
cairo_gradient_pattern_t *gradient =
(cairo_gradient_pattern_t *) pattern;
@@ -222,7 +222,7 @@ void
_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
const cairo_color_t *color)
{
- _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_SOLID);
+ _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SOLID);
pattern->color = *color;
}
@@ -232,12 +232,12 @@ _cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern,
{
if (surface->status) {
/* Force to solid to simplify the pattern_fini process. */
- pattern->base.type = CAIRO_PATTERN_SOLID;
+ pattern->base.type = CAIRO_PATTERN_TYPE_SOLID;
_cairo_pattern_set_error (&pattern->base, surface->status);
return;
}
- _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_SURFACE);
+ _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SURFACE);
pattern->surface = cairo_surface_reference (surface);
}
@@ -256,7 +256,7 @@ void
_cairo_pattern_init_linear (cairo_linear_pattern_t *pattern,
double x0, double y0, double x1, double y1)
{
- _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_LINEAR);
+ _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_LINEAR);
pattern->gradient.p1.x = _cairo_fixed_from_double (x0);
pattern->gradient.p1.y = _cairo_fixed_from_double (y0);
@@ -269,7 +269,7 @@ _cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
double cx0, double cy0, double radius0,
double cx1, double cy1, double radius1)
{
- _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_RADIAL);
+ _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_RADIAL);
pattern->gradient.inner.x = _cairo_fixed_from_double (cx0);
pattern->gradient.inner.y = _cairo_fixed_from_double (cy0);
@@ -525,6 +525,18 @@ cairo_pattern_reference (cairo_pattern_t *pattern)
}
/**
+ * cairo_pattern_get_type:
+ * @pattern: a #cairo_pattern_t
+ *
+ * Return value: The type of @pattern. See #cairo_pattern_type_t.
+ **/
+cairo_pattern_type_t
+cairo_pattern_get_type (cairo_pattern_t *pattern)
+{
+ return pattern->type;
+}
+
+/**
* cairo_pattern_status:
* @pattern: a #cairo_pattern_t
*
@@ -641,8 +653,8 @@ cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern,
if (pattern->status)
return;
- if (pattern->type != CAIRO_PATTERN_LINEAR &&
- pattern->type != CAIRO_PATTERN_RADIAL)
+ if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR &&
+ pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
{
_cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
return;
@@ -689,8 +701,8 @@ cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern,
if (pattern->status)
return;
- if (pattern->type != CAIRO_PATTERN_LINEAR &&
- pattern->type != CAIRO_PATTERN_RADIAL)
+ if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR &&
+ pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
{
_cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
return;
@@ -894,7 +906,7 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
cairo_status_t status;
cairo_bool_t repeat = FALSE;
- if (pattern->base.type == CAIRO_PATTERN_LINEAR)
+ if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR)
{
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
@@ -936,7 +948,7 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
return CAIRO_STATUS_SUCCESS;
}
- if (pattern->base.type == CAIRO_PATTERN_LINEAR) {
+ if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
cairo_bool_t is_horizontal;
cairo_bool_t is_vertical;
@@ -1038,7 +1050,6 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern,
return CAIRO_STATUS_SUCCESS;
}
-
/**
* _cairo_pattern_is_opaque_solid
*
@@ -1051,11 +1062,11 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern,
* Return value: %TRUE if the pattern is an opaque, solid color.
**/
cairo_bool_t
-_cairo_pattern_is_opaque_solid (cairo_pattern_t *pattern)
+_cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern)
{
cairo_solid_pattern_t *solid;
- if (pattern->type != CAIRO_PATTERN_SOLID)
+ if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
return FALSE;
solid = (cairo_solid_pattern_t *) pattern;
@@ -1063,6 +1074,47 @@ _cairo_pattern_is_opaque_solid (cairo_pattern_t *pattern)
return CAIRO_ALPHA_IS_OPAQUE (solid->color.alpha);
}
+static cairo_bool_t
+_gradient_is_opaque (const cairo_gradient_pattern_t *gradient)
+{
+ int i;
+
+ for (i = 0; i < gradient->n_stops; i++)
+ if (! CAIRO_ALPHA_IS_OPAQUE (gradient->stops[i].color.alpha))
+ return FALSE;
+
+ return TRUE;
+}
+
+/**
+ * _cairo_pattern_is_opaque
+ *
+ * Convenience function to determine whether a pattern is an opaque
+ * pattern (of any type). The same caveats that apply to
+ * _cairo_pattern_is_opaque_solid apply here as well.
+ *
+ * Return value: %TRUE if the pattern is a opaque.
+ **/
+cairo_bool_t
+_cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern)
+{
+ const cairo_pattern_union_t *pattern;
+
+ pattern = (cairo_pattern_union_t *) abstract_pattern;
+ switch (pattern->base.type) {
+ case CAIRO_PATTERN_TYPE_SOLID:
+ return _cairo_pattern_is_opaque_solid (abstract_pattern);
+ case CAIRO_PATTERN_TYPE_SURFACE:
+ return _cairo_surface_is_opaque (pattern->surface.surface);
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ case CAIRO_PATTERN_TYPE_RADIAL:
+ return _gradient_is_opaque (&pattern->gradient.base);
+ }
+
+ ASSERT_NOT_REACHED;
+ return FALSE;
+}
+
static cairo_int_status_t
_cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern,
cairo_surface_t *dst,
@@ -1151,7 +1203,7 @@ _cairo_pattern_acquire_surface (cairo_pattern_t *pattern,
}
switch (pattern->type) {
- case CAIRO_PATTERN_SOLID: {
+ case CAIRO_PATTERN_TYPE_SOLID: {
cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) pattern;
status = _cairo_pattern_acquire_surface_for_solid (src, dst,
@@ -1159,8 +1211,8 @@ _cairo_pattern_acquire_surface (cairo_pattern_t *pattern,
surface_out,
attributes);
} break;
- case CAIRO_PATTERN_LINEAR:
- case CAIRO_PATTERN_RADIAL: {
+ case CAIRO_PATTERN_TYPE_LINEAR:
+ case CAIRO_PATTERN_TYPE_RADIAL: {
cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) pattern;
/* fast path for gradients with less than 2 color stops */
@@ -1203,7 +1255,7 @@ _cairo_pattern_acquire_surface (cairo_pattern_t *pattern,
attributes);
}
} break;
- case CAIRO_PATTERN_SURFACE: {
+ case CAIRO_PATTERN_TYPE_SURFACE: {
cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) pattern;
status = _cairo_pattern_acquire_surface_for_surface (src, dst,
@@ -1235,7 +1287,7 @@ _cairo_pattern_release_surface (cairo_pattern_t *pattern,
{
cairo_surface_pattern_t *surface_pattern;
- assert (pattern->type == CAIRO_PATTERN_SURFACE);
+ assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
surface_pattern = (cairo_surface_pattern_t *) pattern;
_cairo_surface_release_source_image (surface_pattern->surface,
@@ -1277,8 +1329,8 @@ _cairo_pattern_acquire_surfaces (cairo_pattern_t *src,
/* XXX: This optimization assumes that there is no color
* information in mask, so this will need to change when we
* support RENDER-style 4-channel masks. */
- if (src->type == CAIRO_PATTERN_SOLID &&
- mask && mask->type == CAIRO_PATTERN_SOLID)
+ if (src->type == CAIRO_PATTERN_TYPE_SOLID &&
+ mask && mask->type == CAIRO_PATTERN_TYPE_SOLID)
{
cairo_color_t combined;
cairo_solid_pattern_t *src_solid = (cairo_solid_pattern_t *) src;
@@ -1346,7 +1398,7 @@ _cairo_pattern_get_extents (cairo_pattern_t *pattern,
cairo_rectangle_t *extents)
{
if (pattern->extend == CAIRO_EXTEND_NONE &&
- pattern->type == CAIRO_PATTERN_SURFACE)
+ pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
{
cairo_status_t status;
cairo_rectangle_t surface_extents;
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 0c024a26b..68c027151 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -140,6 +140,8 @@ struct cairo_pdf_surface {
cairo_array_t alphas;
cairo_array_t fonts;
cairo_bool_t has_clip;
+
+ cairo_paginated_mode_t paginated_mode;
};
#define DEFAULT_DPI 300
@@ -186,6 +188,7 @@ static void
_cairo_pdf_surface_ensure_stream (cairo_pdf_surface_t *surface);
static const cairo_surface_backend_t cairo_pdf_surface_backend;
+static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend;
static unsigned int
_cairo_pdf_document_new_object (cairo_pdf_document_t *document)
@@ -306,7 +309,8 @@ _cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *stream,
return _cairo_paginated_surface_create (target,
CAIRO_CONTENT_COLOR_ALPHA,
- width, height);
+ width, height,
+ &cairo_pdf_surface_paginated_backend);
}
/**
@@ -333,11 +337,13 @@ cairo_pdf_surface_create_for_stream (cairo_write_func_t write,
double width_in_points,
double height_in_points)
{
+ cairo_status_t status;
cairo_output_stream_t *stream;
- stream = _cairo_output_stream_create (write, closure);
- if (stream == NULL) {
- _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ stream = _cairo_output_stream_create (write, NULL, closure);
+ status = _cairo_output_stream_get_status (stream);
+ if (status) {
+ _cairo_error (status);
return (cairo_surface_t*) &_cairo_surface_nil;
}
@@ -368,11 +374,13 @@ cairo_pdf_surface_create (const char *filename,
double width_in_points,
double height_in_points)
{
+ cairo_status_t status;
cairo_output_stream_t *stream;
- stream = _cairo_output_stream_create_for_file (filename);
- if (stream == NULL) {
- _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ stream = _cairo_output_stream_create_for_filename (filename);
+ status = _cairo_output_stream_get_status (stream);
+ if (status) {
+ _cairo_error (status);
return (cairo_surface_t*) &_cairo_surface_nil;
}
@@ -388,7 +396,7 @@ _cairo_surface_is_pdf (cairo_surface_t *surface)
}
/**
- * cairo__surface_set_dpi:
+ * cairo_pdf_surface_set_dpi:
* @surface: a postscript cairo_surface_t
* @x_dpi: horizontal dpi
* @y_dpi: vertical dpi
@@ -451,6 +459,8 @@ _cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document,
_cairo_array_init (&surface->fonts, sizeof (cairo_pdf_resource_t));
surface->has_clip = FALSE;
+ surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
+
return &surface->base;
}
@@ -654,8 +664,10 @@ emit_image_rgb_data (cairo_pdf_document_t *document,
opaque = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
image->width,
image->height);
- if (opaque->status)
+ if (opaque->status) {
+ free (rgb);
return 0;
+ }
_cairo_pattern_init_for_surface (&pattern.surface, &image->base);
@@ -841,7 +853,7 @@ _cairo_pdf_surface_composite (cairo_operator_t op,
if (mask_pattern)
return CAIRO_STATUS_SUCCESS;
- if (src_pattern->type != CAIRO_PATTERN_SURFACE)
+ if (src_pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
return CAIRO_STATUS_SUCCESS;
if (src->surface->backend == &cairo_pdf_surface_backend)
@@ -1237,16 +1249,16 @@ static cairo_status_t
emit_pattern (cairo_pdf_surface_t *surface, cairo_pattern_t *pattern)
{
switch (pattern->type) {
- case CAIRO_PATTERN_SOLID:
+ case CAIRO_PATTERN_TYPE_SOLID:
return emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
- case CAIRO_PATTERN_SURFACE:
+ case CAIRO_PATTERN_TYPE_SURFACE:
return emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern);
- case CAIRO_PATTERN_LINEAR:
+ case CAIRO_PATTERN_TYPE_LINEAR:
return emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern);
- case CAIRO_PATTERN_RADIAL:
+ case CAIRO_PATTERN_TYPE_RADIAL:
return emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern);
}
@@ -1321,55 +1333,6 @@ _cairo_pdf_path_close_path (void *closure)
}
static cairo_int_status_t
-_cairo_pdf_surface_fill (void *abstract_surface,
- cairo_operator_t op,
- cairo_pattern_t *pattern,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias)
-{
- cairo_pdf_surface_t *surface = abstract_surface;
- cairo_pdf_document_t *document = surface->document;
- const char *pdf_operator;
- cairo_status_t status;
-
- status = emit_pattern (surface, pattern);
- if (status)
- return status;
-
- /* After the above switch the current stream should belong to this
- * surface, so no need to _cairo_pdf_surface_ensure_stream() */
- assert (document->current_stream != NULL &&
- document->current_stream == surface->current_stream);
-
- status = _cairo_path_fixed_interpret (path,
- CAIRO_DIRECTION_FORWARD,
- _cairo_pdf_path_move_to,
- _cairo_pdf_path_line_to,
- _cairo_pdf_path_curve_to,
- _cairo_pdf_path_close_path,
- document->output_stream);
-
- switch (fill_rule) {
- case CAIRO_FILL_RULE_WINDING:
- pdf_operator = "f";
- break;
- case CAIRO_FILL_RULE_EVEN_ODD:
- pdf_operator = "f*";
- break;
- default:
- ASSERT_NOT_REACHED;
- }
-
- _cairo_output_stream_printf (document->output_stream,
- "%s\r\n",
- pdf_operator);
-
- return status;
-}
-
-static cairo_int_status_t
_cairo_pdf_surface_composite_trapezoids (cairo_operator_t op,
cairo_pattern_t *pattern,
void *abstract_dst,
@@ -1632,38 +1595,6 @@ _cairo_pdf_surface_get_font_options (void *abstract_surface,
cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
}
-static const cairo_surface_backend_t cairo_pdf_surface_backend = {
- _cairo_pdf_surface_create_similar,
- _cairo_pdf_surface_finish,
- NULL, /* acquire_source_image */
- NULL, /* release_source_image */
- NULL, /* acquire_dest_image */
- NULL, /* release_dest_image */
- NULL, /* clone_similar */
- _cairo_pdf_surface_composite,
- _cairo_pdf_surface_fill_rectangles,
- _cairo_pdf_surface_composite_trapezoids,
- _cairo_pdf_surface_copy_page,
- _cairo_pdf_surface_show_page,
- NULL, /* set_clip_region */
- _cairo_pdf_surface_intersect_clip_path,
- _cairo_pdf_surface_get_extents,
- _cairo_pdf_surface_old_show_glyphs,
- _cairo_pdf_surface_get_font_options,
- NULL, /* flush */
- NULL, /* mark_dirty_rectangle */
- NULL, /* scaled_font_fini */
- NULL, /* scaled_glyph_fini */
-
- /* Here are the drawing functions */
-
- NULL, /* paint */
- NULL, /* mask */
- NULL, /* stroke */
- _cairo_pdf_surface_fill,
- NULL /* show_glyphs */
-};
-
static cairo_pdf_document_t *
_cairo_pdf_document_create (cairo_output_stream_t *output_stream,
double width,
@@ -2086,3 +2017,229 @@ _cairo_pdf_document_add_page (cairo_pdf_document_t *document,
return CAIRO_STATUS_SUCCESS;
}
+
+static cairo_bool_t
+_surface_pattern_supported (const cairo_surface_pattern_t *pattern)
+{
+ if (pattern->surface->backend->acquire_source_image != NULL)
+ return TRUE;
+
+ return FALSE;
+}
+
+static cairo_bool_t
+_pattern_supported (const cairo_pattern_t *pattern)
+{
+ if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
+ return TRUE;
+
+ if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
+ return _surface_pattern_supported ((const cairo_surface_pattern_t *) pattern);
+
+ return FALSE;
+}
+
+static cairo_int_status_t
+_operation_supported (cairo_pdf_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern)
+{
+ if (! _pattern_supported (pattern))
+ return FALSE;
+
+ if (_cairo_operator_always_opaque (op))
+ return TRUE;
+
+ if (_cairo_operator_always_translucent (op))
+ return FALSE;
+
+ return _cairo_pattern_is_opaque (pattern);
+}
+
+static cairo_int_status_t
+_analyze_operation (cairo_pdf_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern)
+{
+ if (_operation_supported (surface, op, pattern))
+ return CAIRO_STATUS_SUCCESS;
+ else
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_paint (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* One would think that since we analyzed this away as unsupported
+ * that it would never be called after analyzing. But in fact,
+ * paint is called to paint the actual fallback surface. So we
+ * must not ASSERT_NOT_REACHED as we do for the other drawing
+ * operations. */
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_mask (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source,
+ cairo_pattern_t *mask)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ ASSERT_NOT_REACHED;
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_stroke (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_stroke_style_t *style,
+ cairo_matrix_t *ctm,
+ cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ ASSERT_NOT_REACHED;
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_fill (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+ cairo_pdf_document_t *document = surface->document;
+ const char *pdf_operator;
+ cairo_status_t status;
+
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ return _analyze_operation (surface, op, source);
+
+ assert (_operation_supported (surface, op, source));
+
+ status = emit_pattern (surface, source);
+ if (status)
+ return status;
+
+ /* After emitting the pattern the current stream should belong to
+ * this surface, so no need to _cairo_pdf_surface_ensure_stream()
+ */
+ assert (document->current_stream != NULL &&
+ document->current_stream == surface->current_stream);
+
+ status = _cairo_path_fixed_interpret (path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_pdf_path_move_to,
+ _cairo_pdf_path_line_to,
+ _cairo_pdf_path_curve_to,
+ _cairo_pdf_path_close_path,
+ document->output_stream);
+
+ switch (fill_rule) {
+ case CAIRO_FILL_RULE_WINDING:
+ pdf_operator = "f";
+ break;
+ case CAIRO_FILL_RULE_EVEN_ODD:
+ pdf_operator = "f*";
+ break;
+ default:
+ ASSERT_NOT_REACHED;
+ }
+
+ _cairo_output_stream_printf (document->output_stream,
+ "%s\r\n",
+ pdf_operator);
+
+ return status;
+}
+
+static cairo_int_status_t
+_cairo_pdf_surface_show_glyphs (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ ASSERT_NOT_REACHED;
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+static void
+_cairo_pdf_surface_set_paginated_mode (void *abstract_surface,
+ cairo_paginated_mode_t paginated_mode)
+{
+ cairo_pdf_surface_t *surface = abstract_surface;
+
+ surface->paginated_mode = paginated_mode;
+}
+
+static const cairo_surface_backend_t cairo_pdf_surface_backend = {
+ CAIRO_SURFACE_TYPE_PDF,
+ _cairo_pdf_surface_create_similar,
+ _cairo_pdf_surface_finish,
+ NULL, /* acquire_source_image */
+ NULL, /* release_source_image */
+ NULL, /* acquire_dest_image */
+ NULL, /* release_dest_image */
+ NULL, /* clone_similar */
+ _cairo_pdf_surface_composite,
+ _cairo_pdf_surface_fill_rectangles,
+ _cairo_pdf_surface_composite_trapezoids,
+ _cairo_pdf_surface_copy_page,
+ _cairo_pdf_surface_show_page,
+ NULL, /* set_clip_region */
+ _cairo_pdf_surface_intersect_clip_path,
+ _cairo_pdf_surface_get_extents,
+ _cairo_pdf_surface_old_show_glyphs,
+ _cairo_pdf_surface_get_font_options,
+ NULL, /* flush */
+ NULL, /* mark_dirty_rectangle */
+ NULL, /* scaled_font_fini */
+ NULL, /* scaled_glyph_fini */
+
+ /* Here are the drawing functions */
+
+ _cairo_pdf_surface_paint,
+ _cairo_pdf_surface_mask,
+ _cairo_pdf_surface_stroke,
+ _cairo_pdf_surface_fill,
+ _cairo_pdf_surface_show_glyphs,
+ NULL, /* snapshot */
+};
+
+static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend = {
+ NULL, /* start_page */
+ _cairo_pdf_surface_set_paginated_mode
+};
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 37053e965..29b6882b8 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -41,6 +41,7 @@
#include "cairo-ps.h"
#include "cairo-font-subset-private.h"
#include "cairo-paginated-surface-private.h"
+#include "cairo-meta-surface-private.h"
#include "cairo-ft-private.h"
#include <time.h>
@@ -50,17 +51,44 @@
*
* - Add document structure convention comments where appropriate.
*
- * - Fix image compression.
- *
* - Create a set of procs to use... specifically a trapezoid proc.
*/
static const cairo_surface_backend_t cairo_ps_surface_backend;
+static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend;
+
+/*
+ * Type1 and Type3 PS fonts can hold only 256 glyphs.
+ *
+ * XXX Work around this by placing each set of 256 glyphs in a separate
+ * font. No separate data structure is kept for this; the font name is
+ * generated from all but the low 8 bits of the output glyph id.
+ */
+
+typedef struct cairo_ps_glyph {
+ cairo_hash_entry_t base; /* font glyph index */
+ unsigned int output_glyph; /* PS sub-font glyph index */
+} cairo_ps_glyph_t;
+
+typedef struct cairo_ps_font {
+ cairo_hash_entry_t base;
+ cairo_scaled_font_t *scaled_font;
+ unsigned int output_font;
+ cairo_hash_table_t *glyphs;
+ unsigned int max_glyph;
+} cairo_ps_font_t;
typedef struct cairo_ps_surface {
cairo_surface_t base;
- /* PS-specific fields */
+ /* Here final_stream corresponds to the stream/file passed to
+ * cairo_ps_surface_create surface is built. Meanwhile stream is a
+ * temporary stream in which the file output is built, (so that
+ * the header can be built and inserted into the target stream
+ * before the contents of the temporary stream are copied). */
+ cairo_output_stream_t *final_stream;
+
+ FILE *tmpfile;
cairo_output_stream_t *stream;
double width;
@@ -68,20 +96,73 @@ typedef struct cairo_ps_surface {
double x_dpi;
double y_dpi;
- cairo_bool_t need_start_page;
int num_pages;
-#if DONE_ADDING_FONTS_SUPPORT_BACK_AFTER_SWITCHING_TO_PAGINATED
- cairo_array_t fonts;
-#endif
+ cairo_paginated_mode_t paginated_mode;
+
+ cairo_hash_table_t *fonts;
+ unsigned int max_font;
+
} cairo_ps_surface_t;
#define PS_SURFACE_DPI_DEFAULT 300.0
-#if DONE_ADDING_FONTS_SUPPORT_BACK_AFTER_SWITCHING_TO_PAGINATED
-static cairo_int_status_t
-_cairo_ps_surface_write_font_subsets (cairo_ps_surface_t *surface);
-#endif
+static cairo_status_t
+_cairo_ps_surface_path_move_to (void *closure, cairo_point_t *point)
+{
+ cairo_output_stream_t *output_stream = closure;
+
+ _cairo_output_stream_printf (output_stream,
+ "%f %f moveto ",
+ _cairo_fixed_to_double (point->x),
+ _cairo_fixed_to_double (point->y));
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_ps_surface_path_line_to (void *closure, cairo_point_t *point)
+{
+ cairo_output_stream_t *output_stream = closure;
+
+ _cairo_output_stream_printf (output_stream,
+ "%f %f lineto ",
+ _cairo_fixed_to_double (point->x),
+ _cairo_fixed_to_double (point->y));
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_ps_surface_path_curve_to (void *closure,
+ cairo_point_t *b,
+ cairo_point_t *c,
+ cairo_point_t *d)
+{
+ cairo_output_stream_t *output_stream = closure;
+
+ _cairo_output_stream_printf (output_stream,
+ "%f %f %f %f %f %f curveto ",
+ _cairo_fixed_to_double (b->x),
+ _cairo_fixed_to_double (b->y),
+ _cairo_fixed_to_double (c->x),
+ _cairo_fixed_to_double (c->y),
+ _cairo_fixed_to_double (d->x),
+ _cairo_fixed_to_double (d->y));
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_ps_surface_path_close_path (void *closure)
+{
+ cairo_output_stream_t *output_stream = closure;
+
+ _cairo_output_stream_printf (output_stream,
+ "closepath\n");
+
+ return CAIRO_STATUS_SUCCESS;
+}
static void
_cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
@@ -90,34 +171,341 @@ _cairo_ps_surface_emit_header (cairo_ps_surface_t *surface)
now = time (NULL);
- _cairo_output_stream_printf (surface->stream,
+ _cairo_output_stream_printf (surface->final_stream,
"%%!PS-Adobe-3.0\n"
"%%%%Creator: cairo (http://cairographics.org)\n"
"%%%%CreationDate: %s"
- "%%%%Pages: (atend)\n"
+ "%%%%Pages: %d\n"
"%%%%BoundingBox: %f %f %f %f\n",
ctime (&now),
+ surface->num_pages,
0.0, 0.0,
surface->width,
surface->height);
- /* The "/FlateDecode filter" currently used is a feature of
- * LanguageLevel 3 */
- _cairo_output_stream_printf (surface->stream,
- "%%%%DocumentData: Binary\n"
- "%%%%LanguageLevel: 3\n"
+ _cairo_output_stream_printf (surface->final_stream,
+ "%%%%DocumentData: Clean7Bit\n"
+ "%%%%LanguageLevel: 2\n"
"%%%%Orientation: Portrait\n"
"%%%%EndComments\n");
+
+ _cairo_output_stream_printf (surface->final_stream,
+ "%%%%BeginProlog\n"
+ "/C{curveto}bind def\n"
+ "/F{fill}bind def\n"
+ "/G{setgray}bind def\n"
+ "/L{lineto}bind def\n"
+ "/M{moveto}bind def\n"
+ "/P{closepath}bind def\n"
+ "/R{setrgbcolor}bind def\n"
+ "/S{show}bind def\n"
+ "%%%%EndProlog\n");
+}
+
+static cairo_bool_t
+_cairo_ps_glyph_equal (const void *key_a, const void *key_b)
+{
+ const cairo_ps_glyph_t *ps_glyph_a = key_a;
+ const cairo_ps_glyph_t *ps_glyph_b = key_b;
+
+ return ps_glyph_a->base.hash == ps_glyph_b->base.hash;
+}
+
+static void
+_cairo_ps_glyph_key_init (cairo_ps_glyph_t *ps_glyph,
+ unsigned long index)
+{
+ ps_glyph->base.hash = index;
+}
+
+static cairo_ps_glyph_t *
+_cairo_ps_glyph_create (cairo_ps_font_t *ps_font,
+ unsigned long index)
+{
+ cairo_ps_glyph_t *ps_glyph = malloc (sizeof (cairo_ps_glyph_t));
+
+ if (!ps_glyph)
+ return NULL;
+ _cairo_ps_glyph_key_init (ps_glyph, index);
+ ps_glyph->output_glyph = ps_font->max_glyph++;
+ return ps_glyph;
+}
+
+static void
+_cairo_ps_glyph_destroy (cairo_ps_glyph_t *ps_glyph)
+{
+ free (ps_glyph);
+}
+
+static cairo_status_t
+_cairo_ps_glyph_find (cairo_ps_font_t *font,
+ cairo_scaled_font_t *scaled_font,
+ unsigned long index,
+ cairo_ps_glyph_t **result)
+{
+ cairo_ps_glyph_t key;
+ cairo_ps_glyph_t *ps_glyph;
+ cairo_status_t status;
+
+ _cairo_ps_glyph_key_init (&key, index);
+ if (!_cairo_hash_table_lookup (font->glyphs,
+ &key.base,
+ (cairo_hash_entry_t **) &ps_glyph)) {
+ ps_glyph = _cairo_ps_glyph_create (font, index);
+ if (!ps_glyph)
+ return CAIRO_STATUS_NO_MEMORY;
+ status = _cairo_hash_table_insert (font->glyphs, &ps_glyph->base);
+ if (status)
+ return status;
+ }
+ *result = ps_glyph;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_bool_t
+_cairo_ps_font_equal (const void *key_a, const void *key_b)
+{
+ const cairo_ps_font_t *ps_font_a = key_a;
+ const cairo_ps_font_t *ps_font_b = key_b;
+
+ return ps_font_a->scaled_font == ps_font_b->scaled_font;
+}
+
+static void
+_cairo_ps_font_key_init (cairo_ps_font_t *ps_font,
+ cairo_scaled_font_t *scaled_font)
+{
+ ps_font->base.hash = (unsigned long) scaled_font;
+ ps_font->scaled_font = scaled_font;
+}
+
+static cairo_ps_font_t *
+_cairo_ps_font_create (cairo_ps_surface_t *surface,
+ cairo_scaled_font_t *scaled_font)
+{
+ cairo_ps_font_t *ps_font = malloc (sizeof (cairo_ps_font_t));
+ if (!ps_font)
+ return NULL;
+ _cairo_ps_font_key_init (ps_font, scaled_font);
+ ps_font->glyphs = _cairo_hash_table_create (_cairo_ps_glyph_equal);
+ if (!ps_font->glyphs) {
+ free (ps_font);
+ return NULL;
+ }
+ ps_font->max_glyph = 0;
+ ps_font->output_font = surface->max_font++;
+ cairo_scaled_font_reference (ps_font->scaled_font);
+ return ps_font;
+}
+
+static void
+_cairo_ps_font_destroy_glyph (void *entry, void *closure)
+{
+ cairo_ps_glyph_t *ps_glyph = entry;
+ cairo_ps_font_t *ps_font = closure;
+
+ _cairo_hash_table_remove (ps_font->glyphs, &ps_glyph->base);
+ _cairo_ps_glyph_destroy (ps_glyph);
+}
+
+static void
+_cairo_ps_font_destroy (cairo_ps_font_t *ps_font)
+{
+ _cairo_hash_table_foreach (ps_font->glyphs,
+ _cairo_ps_font_destroy_glyph,
+ ps_font);
+ _cairo_hash_table_destroy (ps_font->glyphs);
+ cairo_scaled_font_destroy (ps_font->scaled_font);
+ free (ps_font);
+}
+
+static void
+_cairo_ps_surface_destroy_font (cairo_ps_surface_t *surface,
+ cairo_ps_font_t *ps_font)
+{
+ _cairo_hash_table_remove (surface->fonts, &ps_font->base);
+ _cairo_ps_font_destroy (ps_font);
+}
+
+static cairo_status_t
+_cairo_ps_font_find (cairo_ps_surface_t *surface,
+ cairo_scaled_font_t *scaled_font,
+ cairo_ps_font_t **result)
+{
+ cairo_ps_font_t key;
+ cairo_ps_font_t *ps_font;
+ cairo_status_t status;
+
+ _cairo_ps_font_key_init (&key, scaled_font);
+ if (!_cairo_hash_table_lookup (surface->fonts, &key.base,
+ (cairo_hash_entry_t **) &ps_font))
+ {
+ ps_font = _cairo_ps_font_create (surface, scaled_font);
+ if (!ps_font)
+ return CAIRO_STATUS_NO_MEMORY;
+ status = _cairo_hash_table_insert (surface->fonts,
+ &ps_font->base);
+ if (status)
+ return status;
+ }
+ *result = ps_font;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+typedef struct _cairo_ps_font_glyph_select {
+ cairo_ps_glyph_t **glyphs;
+ int subfont;
+ int numglyph;
+} cairo_ps_font_glyph_select_t;
+
+static void
+_cairo_ps_font_select_glyphs (void *entry, void *closure)
+{
+ cairo_ps_glyph_t *ps_glyph = entry;
+ cairo_ps_font_glyph_select_t *ps_glyph_select = closure;
+
+ if (ps_glyph->output_glyph >> 8 == ps_glyph_select->subfont) {
+ unsigned long sub_glyph = ps_glyph->output_glyph & 0xff;
+ ps_glyph_select->glyphs[sub_glyph] = ps_glyph;
+ if (sub_glyph >= ps_glyph_select->numglyph)
+ ps_glyph_select->numglyph = sub_glyph + 1;
+ }
+}
+
+static cairo_status_t
+_cairo_ps_surface_emit_glyph (cairo_ps_surface_t *surface,
+ cairo_ps_font_t *ps_font,
+ cairo_ps_glyph_t *ps_glyph)
+{
+ cairo_scaled_glyph_t *scaled_glyph;
+ cairo_status_t status;
+
+ _cairo_output_stream_printf (surface->final_stream,
+ "\t\t{ %% %d\n", ps_glyph->output_glyph);
+ status = _cairo_scaled_glyph_lookup (ps_font->scaled_font,
+ ps_glyph->base.hash,
+ CAIRO_SCALED_GLYPH_INFO_METRICS|
+ CAIRO_SCALED_GLYPH_INFO_PATH,
+ &scaled_glyph);
+ /*
+ * If that fails, try again but ask for an image instead
+ */
+ if (status)
+ status = _cairo_scaled_glyph_lookup (ps_font->scaled_font,
+ ps_glyph->base.hash,
+ CAIRO_SCALED_GLYPH_INFO_METRICS|
+ CAIRO_SCALED_GLYPH_INFO_SURFACE,
+ &scaled_glyph);
+ if (status) {
+ _cairo_output_stream_printf (surface->final_stream, "\t\t}\n");
+ return status;
+ }
+ _cairo_output_stream_printf (surface->final_stream,
+ "%f %f %f %f 0 0 setcachedevice\n",
+ _cairo_fixed_to_double (scaled_glyph->bbox.p1.x),
+ -_cairo_fixed_to_double (scaled_glyph->bbox.p2.y),
+ _cairo_fixed_to_double (scaled_glyph->bbox.p2.x),
+ -_cairo_fixed_to_double (scaled_glyph->bbox.p1.y));
+
+ status = _cairo_path_fixed_interpret (scaled_glyph->path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_ps_surface_path_move_to,
+ _cairo_ps_surface_path_line_to,
+ _cairo_ps_surface_path_curve_to,
+ _cairo_ps_surface_path_close_path,
+ surface->final_stream);
+
+ _cairo_output_stream_printf (surface->final_stream,
+ "F\n");
+
+ _cairo_output_stream_printf (surface->final_stream,
+ "\t\t}\n");
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_ps_surface_emit_font (void *entry, void *closure)
+{
+ cairo_ps_font_t *ps_font = entry;
+ cairo_ps_surface_t *surface = closure;
+ cairo_ps_font_glyph_select_t glyph_select;
+ cairo_ps_glyph_t *ps_glyphs[256], *ps_glyph;
+ int glyph, numglyph;
+ int subfont, nsubfont;
+
+ _cairo_output_stream_printf (surface->final_stream,
+ "%% _cairo_ps_surface_emit_font\n");
+ nsubfont = (ps_font->max_glyph >> 8) + 1;
+ for (subfont = 0; subfont < nsubfont; subfont++) {
+ _cairo_output_stream_printf (surface->final_stream,
+ "/CairoFont-%d-%d <<\n",
+ ps_font->output_font,
+ subfont);
+ memset (ps_glyphs, '\0', sizeof (ps_glyphs));
+ glyph_select.glyphs = ps_glyphs;
+ glyph_select.numglyph = 0;
+ glyph_select.subfont = subfont;
+ _cairo_hash_table_foreach (ps_font->glyphs,
+ _cairo_ps_font_select_glyphs,
+ &glyph_select);
+ _cairo_output_stream_printf (surface->final_stream,
+ "\t/FontType\t3\n"
+ "\t/FontMatrix\t[1 0 0 1 0 0]\n"
+ "\t/Encoding\t[0]\n"
+ "\t/FontBBox\t[0 0 10 10]\n"
+ "\t/Glyphs [\n");
+ numglyph = glyph_select.numglyph;
+ for (glyph = 0; glyph < numglyph; glyph++) {
+ ps_glyph = ps_glyphs[glyph];
+ if (ps_glyph) {
+ _cairo_ps_surface_emit_glyph (surface,
+ ps_font,
+ ps_glyph);
+ } else {
+ _cairo_output_stream_printf (surface->final_stream,
+ "\t\t{ } %% %d\n", glyph);
+ }
+ _cairo_ps_font_destroy_glyph (ps_glyph, ps_font);
+ }
+ _cairo_output_stream_printf (surface->final_stream,
+ "\t]\n"
+ "\t/BuildChar {\n"
+ "\t\texch /Glyphs get\n"
+ "\t\texch get exec\n"
+ "\t}\n"
+ ">> definefont pop\n");
+ }
+ _cairo_ps_surface_destroy_font (surface, ps_font);
+}
+
+
+static void
+_cairo_ps_surface_emit_fonts (cairo_ps_surface_t *surface)
+{
+ _cairo_hash_table_foreach (surface->fonts,
+ _cairo_ps_surface_emit_font,
+ surface);
+ _cairo_hash_table_destroy (surface->fonts);
+ surface->fonts = NULL;
+}
+
+static void
+_cairo_ps_surface_emit_body (cairo_ps_surface_t *surface)
+{
+ char buf[4096];
+ int n;
+
+ rewind (surface->tmpfile);
+ while ((n = fread (buf, 1, sizeof (buf), surface->tmpfile)) > 0)
+ _cairo_output_stream_write (surface->final_stream, buf, n);
}
static void
_cairo_ps_surface_emit_footer (cairo_ps_surface_t *surface)
{
- _cairo_output_stream_printf (surface->stream,
+ _cairo_output_stream_printf (surface->final_stream,
"%%%%Trailer\n"
- "%%%%Pages: %d\n"
- "%%%%EOF\n",
- surface->num_pages);
+ "%%%%EOF\n");
}
static cairo_surface_t *
@@ -125,6 +513,7 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
double width,
double height)
{
+ cairo_status_t status;
cairo_ps_surface_t *surface;
surface = malloc (sizeof (cairo_ps_surface_t));
@@ -135,29 +524,40 @@ _cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream,
_cairo_surface_init (&surface->base, &cairo_ps_surface_backend);
- surface->stream = stream;
+ surface->final_stream = stream;
+ surface->tmpfile = tmpfile ();
+ surface->stream = _cairo_output_stream_create_for_file (surface->tmpfile);
+ status = _cairo_output_stream_get_status (surface->stream);
+ if (status) {
+ fclose (surface->tmpfile);
+ free (surface);
+ _cairo_error (status);
+ return (cairo_surface_t*) &_cairo_surface_nil;
+ }
+
+ surface->fonts = _cairo_hash_table_create (_cairo_ps_font_equal);
+ if (!surface->fonts) {
+ _cairo_output_stream_destroy (surface->stream);
+ fclose (surface->tmpfile);
+ free (surface);
+ _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ return (cairo_surface_t*) &_cairo_surface_nil;
+ }
+ surface->max_font = 0;
+
surface->width = width;
surface->height = height;
surface->x_dpi = PS_SURFACE_DPI_DEFAULT;
surface->y_dpi = PS_SURFACE_DPI_DEFAULT;
-#if DONE_ADDING_DEVICE_SCALE_SUPPORT_AFTER_SWITCHING_TO_PAGINATED
- surface->base.device_x_scale = surface->x_dpi / 72.0;
- surface->base.device_y_scale = surface->y_dpi / 72.0;
-#endif
+ surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE;
- surface->need_start_page = TRUE;
surface->num_pages = 0;
-#if DONE_ADDING_FONTS_SUPPORT_BACK_AFTER_SWITCHING_TO_PAGINATED
- _cairo_array_init (&surface->fonts, sizeof (cairo_font_subset_t *));
-#endif
-
- _cairo_ps_surface_emit_header (surface);
-
return _cairo_paginated_surface_create (&surface->base,
CAIRO_CONTENT_COLOR_ALPHA,
- width, height);
+ width, height,
+ &cairo_ps_surface_paginated_backend);
}
/**
@@ -182,11 +582,13 @@ cairo_ps_surface_create (const char *filename,
double width_in_points,
double height_in_points)
{
+ cairo_status_t status;
cairo_output_stream_t *stream;
- stream = _cairo_output_stream_create_for_file (filename);
- if (stream == NULL) {
- _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ stream = _cairo_output_stream_create_for_filename (filename);
+ status = _cairo_output_stream_get_status (stream);
+ if (status) {
+ _cairo_error (status);
return (cairo_surface_t*) &_cairo_surface_nil;
}
@@ -220,11 +622,13 @@ cairo_ps_surface_create_for_stream (cairo_write_func_t write_func,
double width_in_points,
double height_in_points)
{
+ cairo_status_t status;
cairo_output_stream_t *stream;
- stream = _cairo_output_stream_create (write_func, closure);
- if (stream == NULL) {
- _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ stream = _cairo_output_stream_create (write_func, NULL, closure);
+ status = _cairo_output_stream_get_status (stream);
+ if (status) {
+ _cairo_error (status);
return (cairo_surface_t*) &_cairo_surface_nil;
}
@@ -276,44 +680,156 @@ cairo_ps_surface_set_dpi (cairo_surface_t *surface,
ps_surface->x_dpi = x_dpi;
ps_surface->y_dpi = y_dpi;
-#if DONE_ADDING_DEVICE_SCALE_SUPPORT_AFTER_SWITCHING_TO_PAGINATED
- ps_surface->base.device_x_scale = ps_surface->x_dpi / 72.0;
- ps_surface->base.device_y_scale = ps_surface->y_dpi / 72.0;
-#endif
}
-/* XXX */
+/* A word wrap stream can be used as a filter to do word wrapping on
+ * top of an existing output stream. The word wrapping is quite
+ * simple, using isspace to determine characters that separate
+ * words. Any word that will cause the column count exceeed the given
+ * max_column will have a '\n' character emitted before it.
+ *
+ * The stream is careful to maintain integrity for words that cross
+ * the boundary from one call to write to the next.
+ *
+ * Note: This stream does not guarantee that the output will never
+ * exceed max_column. In particular, if a single word is larger than
+ * max_column it will not be broken up.
+ */
+typedef struct _word_wrap_stream {
+ cairo_output_stream_t *output;
+ int max_column;
+ int column;
+ cairo_bool_t last_write_was_space;
+} word_wrap_stream_t;
+
+static int
+_count_word_up_to (const unsigned char *s, int length)
+{
+ int word = 0;
+
+ while (length--) {
+ if (! isspace (*s++))
+ word++;
+ else
+ return word;
+ }
+
+ return word;
+}
+
+static cairo_status_t
+_word_wrap_stream_write (void *closure,
+ const unsigned char *data,
+ unsigned int length)
+{
+ word_wrap_stream_t *stream = closure;
+ cairo_bool_t newline;
+ int word;
+
+ while (length) {
+ if (isspace (*data)) {
+ newline = (*data == '\n' || *data == '\r');
+ if (! newline && stream->column >= stream->max_column) {
+ _cairo_output_stream_printf (stream->output, "\n");
+ stream->column = 0;
+ }
+ _cairo_output_stream_write (stream->output, data, 1);
+ data++;
+ length--;
+ if (newline)
+ stream->column = 0;
+ else
+ stream->column++;
+ stream->last_write_was_space = TRUE;
+ } else {
+ word = _count_word_up_to (data, length);
+ /* Don't wrap if this word is a continuation of a word
+ * from a previous call to write. */
+ if (stream->column + word >= stream->max_column &&
+ stream->last_write_was_space)
+ {
+ _cairo_output_stream_printf (stream->output, "\n");
+ stream->column = 0;
+ }
+ _cairo_output_stream_write (stream->output, data, word);
+ data += word;
+ length -= word;
+ stream->column += word;
+ stream->last_write_was_space = FALSE;
+ }
+ }
+
+ return _cairo_output_stream_get_status (stream->output);
+}
+
+static cairo_output_stream_t *
+_word_wrap_stream_create (cairo_output_stream_t *output, int max_column)
+{
+ word_wrap_stream_t *stream;
+
+ stream = malloc (sizeof (word_wrap_stream_t));
+ if (stream == NULL)
+ return (cairo_output_stream_t *) &cairo_output_stream_nil;
+
+ stream->output = output;
+ stream->max_column = max_column;
+ stream->column = 0;
+ stream->last_write_was_space = FALSE;
+
+ return _cairo_output_stream_create (_word_wrap_stream_write,
+ NULL, stream);
+}
+
static cairo_status_t
_cairo_ps_surface_finish (void *abstract_surface)
{
+ cairo_status_t status;
cairo_ps_surface_t *surface = abstract_surface;
+ cairo_output_stream_t *final_stream, *word_wrap;
-#if DONE_ADDING_FONTS_SUPPORT_BACK_AFTER_SWITCHING_TO_PAGINATED
- _cairo_ps_surface_write_font_subsets (surface);
-#endif
+ /* Save final_stream to be restored later. */
+ final_stream = surface->final_stream;
- _cairo_ps_surface_emit_footer (surface);
+ word_wrap = _word_wrap_stream_create (final_stream, 79);
+ surface->final_stream = word_wrap;
+
+ _cairo_ps_surface_emit_header (surface);
+
+ _cairo_ps_surface_emit_fonts (surface);
-#if DONE_ADDING_FONTS_SUPPORT_BACK_AFTER_SWITCHING_TO_PAGINATED
- for (i = 0; i < surface->fonts.num_elements; i++) {
- _cairo_array_copy_element (&surface->fonts, i, &subset);
- _cairo_font_subset_destroy (subset);
- }
- _cairo_array_fini (&surface->fonts);
-#endif
+ _cairo_ps_surface_emit_body (surface);
+ _cairo_ps_surface_emit_footer (surface);
+
+ _cairo_output_stream_close (surface->stream);
+ status = _cairo_output_stream_get_status (surface->stream);
_cairo_output_stream_destroy (surface->stream);
- return CAIRO_STATUS_SUCCESS;
+ fclose (surface->tmpfile);
+
+ /* Restore final stream before final cleanup. */
+ _cairo_output_stream_destroy (word_wrap);
+ surface->final_stream = final_stream;
+
+ _cairo_output_stream_close (surface->final_stream);
+ if (status == CAIRO_STATUS_SUCCESS)
+ status = _cairo_output_stream_get_status (surface->final_stream);
+ _cairo_output_stream_destroy (surface->final_stream);
+
+ return status;
}
-static void
-_cairo_ps_surface_start_page (cairo_ps_surface_t *surface)
+static cairo_int_status_t
+_cairo_ps_surface_start_page (void *abstract_surface)
{
- _cairo_output_stream_printf (surface->stream,
- "%%%%Page: %d\n",
- ++surface->num_pages);
+ cairo_ps_surface_t *surface = abstract_surface;
+ /* Increment before print so page numbers start at 1. */
+ surface->num_pages++;
+ _cairo_output_stream_printf (surface->stream,
+ "%%%%Page: %d %d\n",
+ surface->num_pages,
+ surface->num_pages);
_cairo_output_stream_printf (surface->stream,
"gsave %f %f translate %f %f scale \n",
@@ -321,7 +837,7 @@ _cairo_ps_surface_start_page (cairo_ps_surface_t *surface)
1.0/surface->base.device_x_scale,
-1.0/surface->base.device_y_scale);
- surface->need_start_page = FALSE;
+ return _cairo_output_stream_get_status (surface->stream);
}
static void
@@ -329,8 +845,6 @@ _cairo_ps_surface_end_page (cairo_ps_surface_t *surface)
{
_cairo_output_stream_printf (surface->stream,
"grestore\n");
-
- surface->need_start_page = TRUE;
}
static cairo_int_status_t
@@ -354,132 +868,6 @@ _cairo_ps_surface_show_page (void *abstract_surface)
_cairo_output_stream_printf (surface->stream, "showpage\n");
- surface->need_start_page = TRUE;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-#if DONE_ADDING_FONTS_SUPPORT_BACK_AFTER_SWITCHING_TO_PAGINATED
-static cairo_font_subset_t *
-_cairo_ps_surface_get_font (cairo_ps_surface_t *surface,
- cairo_scaled_font_t *scaled_font)
-{
- cairo_status_t status;
- cairo_unscaled_font_t *unscaled_font;
- cairo_font_subset_t *subset;
- unsigned int num_fonts, i;
-
- /* XXX: Need to fix this to work with a general cairo_scaled_font_t. */
- if (! _cairo_scaled_font_is_ft (scaled_font))
- return NULL;
-
- /* XXX Why is this an ft specific function? */
- unscaled_font = _cairo_ft_scaled_font_get_unscaled_font (scaled_font);
-
- num_fonts = _cairo_array_num_elements (&surface->fonts);
- for (i = 0; i < num_fonts; i++) {
- _cairo_array_copy_element (&surface->fonts, i, &subset);
- if (subset->unscaled_font == unscaled_font)
- return subset;
- }
-
- subset = _cairo_font_subset_create (unscaled_font);
- if (subset == NULL)
- return NULL;
-
- subset->font_id = surface->fonts.num_elements;
-
- status = _cairo_array_append (&surface->fonts, &subset);
- if (status) {
- _cairo_font_subset_destroy (subset);
- return NULL;
- }
-
- return subset;
-}
-
-static cairo_int_status_t
-_cairo_ps_surface_write_type42_dict (cairo_ps_surface_t *surface,
- cairo_font_subset_t *subset)
-{
- const char *data;
- unsigned long data_size;
- cairo_status_t status;
- int i;
-
- status = CAIRO_STATUS_SUCCESS;
-
- /* FIXME: Figure out document structure convention for fonts */
-
- _cairo_output_stream_printf (surface->stream,
- "11 dict begin\n"
- "/FontType 42 def\n"
- "/FontName /f%d def\n"
- "/PaintType 0 def\n"
- "/FontMatrix [ 1 0 0 1 0 0 ] def\n"
- "/FontBBox [ 0 0 0 0 ] def\n"
- "/Encoding 256 array def\n"
- "0 1 255 { Encoding exch /.notdef put } for\n",
- subset->font_id);
-
- /* FIXME: Figure out how subset->x_max etc maps to the /FontBBox */
-
- for (i = 1; i < subset->num_glyphs; i++)
- _cairo_output_stream_printf (surface->stream,
- "Encoding %d /g%d put\n", i, i);
-
- _cairo_output_stream_printf (surface->stream,
- "/CharStrings %d dict dup begin\n"
- "/.notdef 0 def\n",
- subset->num_glyphs);
-
- for (i = 1; i < subset->num_glyphs; i++)
- _cairo_output_stream_printf (surface->stream,
- "/g%d %d def\n", i, i);
-
- _cairo_output_stream_printf (surface->stream,
- "end readonly def\n");
-
- status = _cairo_font_subset_generate (subset, &data, &data_size);
-
- /* FIXME: We need to break up fonts bigger than 64k so we don't
- * exceed string size limitation. At glyph boundaries. Stupid
- * postscript. */
- _cairo_output_stream_printf (surface->stream,
- "/sfnts [<");
-
- _cairo_output_stream_write_hex_string (surface->stream, data, data_size);
-
- _cairo_output_stream_printf (surface->stream,
- ">] def\n"
- "FontName currentdict end definefont pop\n");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_ps_surface_write_font_subsets (cairo_ps_surface_t *surface)
-{
- cairo_font_subset_t *subset;
- int i;
-
- for (i = 0; i < surface->fonts.num_elements; i++) {
- _cairo_array_copy_element (&surface->fonts, i, &subset);
- _cairo_ps_surface_write_type42_dict (surface, subset);
- }
-
- return CAIRO_STATUS_SUCCESS;
-}
-#endif
-
-/* XXX: This function wil go away in favor of the new "analysis mode"
- * of cairo_paginated_surface_t */
-static cairo_int_status_t
-_cairo_ps_surface_add_fallback_area (cairo_ps_surface_t *surface,
- int x, int y,
- unsigned int width,
- unsigned int height)
-{
return CAIRO_STATUS_SUCCESS;
}
@@ -493,192 +881,174 @@ color_is_gray (cairo_color_t *color)
}
static cairo_bool_t
-color_is_translucent (const cairo_color_t *color)
-{
- return color->alpha < 0.999;
-}
-
-static cairo_bool_t
-format_is_translucent (cairo_format_t format)
+surface_pattern_supported (const cairo_surface_pattern_t *pattern)
{
- switch (format) {
- case CAIRO_FORMAT_ARGB32:
- return TRUE;
- case CAIRO_FORMAT_RGB24:
- return FALSE;
- case CAIRO_FORMAT_A8:
- return TRUE;
- case CAIRO_FORMAT_A1:
+ if (pattern->surface->backend->acquire_source_image != NULL)
return TRUE;
- }
- return TRUE;
-}
-
-static cairo_bool_t
-surface_is_translucent (const cairo_surface_t *surface)
-{
- if (_cairo_surface_is_image (surface)) {
- const cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
- return format_is_translucent (image_surface->format);
- }
- return TRUE;
-}
-
-static cairo_bool_t
-gradient_is_translucent (const cairo_gradient_pattern_t *gradient)
-{
- return TRUE; /* XXX no gradient support */
-#if 0
- int i;
-
- for (i = 0; i < gradient->n_stops; i++)
- if (color_is_translucent (&gradient->stops[i].color))
- return TRUE;
return FALSE;
-#endif
}
static cairo_bool_t
-pattern_is_translucent (const cairo_pattern_t *abstract_pattern)
+pattern_supported (const cairo_pattern_t *pattern)
{
- const cairo_pattern_union_t *pattern;
-
- pattern = (cairo_pattern_union_t *) abstract_pattern;
- switch (pattern->base.type) {
- case CAIRO_PATTERN_SOLID:
- return color_is_translucent (&pattern->solid.color);
- case CAIRO_PATTERN_SURFACE:
- return surface_is_translucent (pattern->surface.surface);
- case CAIRO_PATTERN_LINEAR:
- case CAIRO_PATTERN_RADIAL:
- return gradient_is_translucent (&pattern->gradient.base);
- }
-
- ASSERT_NOT_REACHED;
+ if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
+ return TRUE;
+
+ if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
+ return surface_pattern_supported ((const cairo_surface_pattern_t *) pattern);
+
return FALSE;
}
-static cairo_bool_t
-operator_always_opaque (cairo_operator_t op)
+static cairo_int_status_t
+operation_supported (cairo_ps_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern)
{
- switch (op) {
- case CAIRO_OPERATOR_CLEAR:
-
- case CAIRO_OPERATOR_SOURCE:
- return TRUE;
-
- case CAIRO_OPERATOR_OVER:
- case CAIRO_OPERATOR_IN:
- case CAIRO_OPERATOR_OUT:
- case CAIRO_OPERATOR_ATOP:
+ if (! pattern_supported (pattern))
return FALSE;
- case CAIRO_OPERATOR_DEST:
+ if (_cairo_operator_always_opaque (op))
return TRUE;
-
- case CAIRO_OPERATOR_DEST_OVER:
- case CAIRO_OPERATOR_DEST_IN:
- case CAIRO_OPERATOR_DEST_OUT:
- case CAIRO_OPERATOR_DEST_ATOP:
- return FALSE;
- case CAIRO_OPERATOR_XOR:
- case CAIRO_OPERATOR_ADD:
- case CAIRO_OPERATOR_SATURATE:
+ if (_cairo_operator_always_translucent (op))
return FALSE;
- }
- return FALSE;
+
+ return _cairo_pattern_is_opaque (pattern);
}
-static cairo_bool_t
-operator_always_translucent (cairo_operator_t op)
+static cairo_int_status_t
+_analyze_operation (cairo_ps_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *pattern)
{
- switch (op) {
- case CAIRO_OPERATOR_CLEAR:
+ if (operation_supported (surface, op, pattern))
+ return CAIRO_STATUS_SUCCESS;
+ else
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+}
- case CAIRO_OPERATOR_SOURCE:
- return FALSE;
-
- case CAIRO_OPERATOR_OVER:
- case CAIRO_OPERATOR_IN:
- case CAIRO_OPERATOR_OUT:
- case CAIRO_OPERATOR_ATOP:
- return FALSE;
+/* The "standard" implementation limit for PostScript string sizes is
+ * 65535 characters (see PostScript Language Reference, Appendix
+ * B). We go one short of that because we sometimes need two
+ * characters in a string to represent a single ASCII85 byte, (for the
+ * escape sequences "\\", "\(", and "\)") and we must not split these
+ * across two strings. So we'd be in trouble if we went right to the
+ * limit and one of these escape sequences just happened to land at
+ * the end.
+ */
+#define STRING_ARRAY_MAX_STRING_SIZE (65535-1)
+#define STRING_ARRAY_MAX_COLUMN 72
- case CAIRO_OPERATOR_DEST:
- return FALSE;
-
- case CAIRO_OPERATOR_DEST_OVER:
- case CAIRO_OPERATOR_DEST_IN:
- case CAIRO_OPERATOR_DEST_OUT:
- case CAIRO_OPERATOR_DEST_ATOP:
- return FALSE;
+typedef struct _string_array_stream {
+ cairo_output_stream_t *output;
+ int column;
+ int string_size;
+} string_array_stream_t;
- case CAIRO_OPERATOR_XOR:
- case CAIRO_OPERATOR_ADD:
- case CAIRO_OPERATOR_SATURATE:
- return TRUE;
+static cairo_status_t
+_string_array_stream_write (void *closure,
+ const unsigned char *data,
+ unsigned int length)
+{
+ string_array_stream_t *stream = closure;
+ unsigned char c;
+ const unsigned char backslash = '\\';
+
+ if (length == 0)
+ return CAIRO_STATUS_SUCCESS;
+
+ while (length--) {
+ if (stream->string_size == 0) {
+ _cairo_output_stream_printf (stream->output, "(");
+ stream->column++;
+ }
+
+ c = *data++;
+ switch (c) {
+ case '\\':
+ case '(':
+ case ')':
+ _cairo_output_stream_write (stream->output, &backslash, 1);
+ stream->column++;
+ stream->string_size++;
+ break;
+ }
+ _cairo_output_stream_write (stream->output, &c, 1);
+ stream->column++;
+ stream->string_size++;
+
+ if (stream->string_size >= STRING_ARRAY_MAX_STRING_SIZE) {
+ _cairo_output_stream_printf (stream->output, ")\n");
+ stream->string_size = 0;
+ stream->column = 0;
+ }
+ if (stream->column >= STRING_ARRAY_MAX_COLUMN) {
+ _cairo_output_stream_printf (stream->output, "\n ");
+ stream->string_size += 2;
+ stream->column = 1;
+ }
}
- return TRUE;
-}
-static cairo_bool_t
-color_operation_needs_fallback (cairo_operator_t op,
- const cairo_color_t *color)
-{
- if (operator_always_opaque (op))
- return FALSE;
- if (operator_always_translucent (op))
- return TRUE;
- return color_is_translucent (color);
+ return _cairo_output_stream_get_status (stream->output);
}
-static cairo_bool_t
-pattern_type_supported (const cairo_pattern_t *pattern)
+static cairo_status_t
+_string_array_stream_close (void *closure)
{
- if (pattern->type == CAIRO_PATTERN_SOLID)
- return TRUE;
- return FALSE;
-}
+ cairo_status_t status;
+ string_array_stream_t *stream = closure;
-static cairo_bool_t
-pattern_operation_needs_fallback (cairo_operator_t op,
- const cairo_pattern_t *pattern)
-{
- if (! pattern_type_supported (pattern))
- return TRUE;
- if (operator_always_opaque (op))
- return FALSE;
- if (operator_always_translucent (op))
- return TRUE;
- return pattern_is_translucent (pattern);
-}
+ _cairo_output_stream_printf (stream->output, ")\n");
-/* PS Output - this section handles output of the parts of the meta
- * surface we can render natively in PS. */
+ status = _cairo_output_stream_get_status (stream->output);
+
+ free (stream);
-static void *
-compress_dup (const void *data, unsigned long data_size,
- unsigned long *compressed_size)
+ return status;
+}
+
+/* A string_array_stream wraps an existing output stream. It takes the
+ * data provided to it and output one or more consecutive string
+ * objects, each within the standard PostScript implementation limit
+ * of 65k characters.
+ *
+ * The strings are each separated by a space character for easy
+ * inclusion within an array object, (but the array delimiters are not
+ * added by the string_array_stream).
+ *
+ * The string array stream is also careful to wrap the output within
+ * STRING_ARRAY_MAX_COLUMN columns (+/- 1). The stream also adds
+ * necessary escaping for special characters within a string,
+ * (specifically '\', '(', and ')').
+ */
+static cairo_output_stream_t *
+_string_array_stream_create (cairo_output_stream_t *output)
{
- void *compressed;
+ string_array_stream_t *stream;
- /* Bound calculation taken from zlib. */
- *compressed_size = data_size + (data_size >> 12) + (data_size >> 14) + 11;
- compressed = malloc (*compressed_size);
- if (compressed == NULL)
- return NULL;
+ stream = malloc (sizeof (string_array_stream_t));
+ if (stream == NULL)
+ return (cairo_output_stream_t *) &cairo_output_stream_nil;
- compress (compressed, compressed_size, data, data_size);
+ stream->output = output;
+ stream->column = 0;
+ stream->string_size = 0;
- return compressed;
+ return _cairo_output_stream_create (_string_array_stream_write,
+ _string_array_stream_close,
+ stream);
}
+/* PS Output - this section handles output of the parts of the meta
+ * surface we can render natively in PS. */
+
static cairo_status_t
emit_image (cairo_ps_surface_t *surface,
cairo_image_surface_t *image,
- cairo_matrix_t *matrix)
+ cairo_matrix_t *matrix,
+ char *name)
{
cairo_status_t status;
unsigned char *rgb, *compressed;
@@ -688,6 +1058,7 @@ emit_image (cairo_ps_surface_t *surface,
cairo_pattern_union_t pattern;
cairo_matrix_t d2i;
int x, y, i;
+ cairo_output_stream_t *base85_stream, *string_array_stream;
/* PostScript can not represent the alpha channel, so we blend the
current image over a white RGB surface to eliminate it. */
@@ -745,12 +1116,33 @@ emit_image (cairo_ps_surface_t *surface,
}
}
- compressed = compress_dup (rgb, rgb_size, &compressed_size);
+ /* XXX: Should fix cairo-lzw to provide a stream-based interface
+ * instead. */
+ compressed_size = rgb_size;
+ compressed = _cairo_lzw_compress (rgb, &compressed_size);
if (compressed == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
goto bail2;
}
+ /* First emit the image data as a base85-encoded string which will
+ * be used as the data source for the image operator later. */
+ _cairo_output_stream_printf (surface->stream,
+ "/%sData [\n", name);
+
+ string_array_stream = _string_array_stream_create (surface->stream);
+ base85_stream = _cairo_base85_stream_create (string_array_stream);
+
+ _cairo_output_stream_write (base85_stream, compressed, compressed_size);
+
+ _cairo_output_stream_destroy (base85_stream);
+ _cairo_output_stream_destroy (string_array_stream);
+
+ _cairo_output_stream_printf (surface->stream,
+ "] def\n");
+ _cairo_output_stream_printf (surface->stream,
+ "/%sDataIndex 0 def\n", name);
+
/* matrix transforms from user space to image space. We need to
* transform from device space to image space to compensate for
* postscripts coordinate system. */
@@ -758,30 +1150,33 @@ emit_image (cairo_ps_surface_t *surface,
cairo_matrix_multiply (&d2i, &d2i, matrix);
_cairo_output_stream_printf (surface->stream,
- "/DeviceRGB setcolorspace\n"
- "<<\n"
+ "/%s {\n"
+ " /DeviceRGB setcolorspace\n"
+ " <<\n"
" /ImageType 1\n"
" /Width %d\n"
" /Height %d\n"
" /BitsPerComponent 8\n"
" /Decode [ 0 1 0 1 0 1 ]\n"
- " /DataSource currentfile\n"
+ " /DataSource {\n"
+ " %sData %sDataIndex get\n"
+ " /%sDataIndex %sDataIndex 1 add def\n"
+ " %sDataIndex %sData length 1 sub gt { /%sDataIndex 0 def } if\n"
+ " } /ASCII85Decode filter /LZWDecode filter\n"
" /ImageMatrix [ %f %f %f %f %f %f ]\n"
- ">>\n"
- "image\n",
+ " >>\n"
+ " image\n"
+ "} def\n",
+ name,
opaque_image->width,
opaque_image->height,
+ name, name, name, name, name, name, name,
d2i.xx, d2i.yx,
d2i.xy, d2i.yy,
d2i.x0, d2i.y0);
- /* Compressed image data */
- _cairo_output_stream_write (surface->stream, rgb, rgb_size);
status = CAIRO_STATUS_SUCCESS;
- _cairo_output_stream_printf (surface->stream,
- "\n");
-
free (compressed);
bail2:
free (rgb);
@@ -798,11 +1193,11 @@ emit_solid_pattern (cairo_ps_surface_t *surface,
{
if (color_is_gray (&pattern->color))
_cairo_output_stream_printf (surface->stream,
- "%f setgray\n",
+ "%f G\n",
pattern->color.red);
else
_cairo_output_stream_printf (surface->stream,
- "%f %f %f setrgbcolor\n",
+ "%f %f %f R\n",
pattern->color.red,
pattern->color.green,
pattern->color.blue);
@@ -812,7 +1207,41 @@ static void
emit_surface_pattern (cairo_ps_surface_t *surface,
cairo_surface_pattern_t *pattern)
{
- /* XXX: NYI */
+ cairo_rectangle_t extents;
+
+ if (_cairo_surface_is_meta (pattern->surface)) {
+ _cairo_output_stream_printf (surface->stream, "/MyPattern {\n");
+ _cairo_meta_surface_replay (pattern->surface, &surface->base);
+ extents.width = surface->width;
+ extents.height = surface->height;
+ _cairo_output_stream_printf (surface->stream, "} bind def\n");
+ } else {
+ cairo_image_surface_t *image;
+ void *image_extra;
+ cairo_status_t status;
+
+ status = _cairo_surface_acquire_source_image (pattern->surface,
+ &image,
+ &image_extra);
+ _cairo_surface_get_extents (&image->base, &extents);
+ assert (status == CAIRO_STATUS_SUCCESS);
+ emit_image (surface, image, &pattern->base.matrix, "MyPattern");
+ _cairo_surface_release_source_image (pattern->surface, image,
+ image_extra);
+ }
+ _cairo_output_stream_printf (surface->stream,
+ "<< /PatternType 1\n"
+ " /PaintType 1\n"
+ " /TilingType 1\n");
+ _cairo_output_stream_printf (surface->stream,
+ " /BBox [0 0 %d %d]\n",
+ extents.width, extents.height);
+ _cairo_output_stream_printf (surface->stream,
+ " /XStep %d /YStep %d\n",
+ extents.width, extents.height);
+ _cairo_output_stream_printf (surface->stream,
+ " /PaintProc { MyPattern } bind\n"
+ ">> matrix makepattern setpattern\n");
}
static void
@@ -837,276 +1266,24 @@ emit_pattern (cairo_ps_surface_t *surface, cairo_pattern_t *pattern)
* different pattern. */
switch (pattern->type) {
- case CAIRO_PATTERN_SOLID:
+ case CAIRO_PATTERN_TYPE_SOLID:
emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern);
break;
- case CAIRO_PATTERN_SURFACE:
+ case CAIRO_PATTERN_TYPE_SURFACE:
emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern);
break;
- case CAIRO_PATTERN_LINEAR:
+ case CAIRO_PATTERN_TYPE_LINEAR:
emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern);
break;
- case CAIRO_PATTERN_RADIAL:
+ case CAIRO_PATTERN_TYPE_RADIAL:
emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern);
break;
}
}
-
-static cairo_int_status_t
-_cairo_ps_surface_composite (cairo_operator_t op,
- cairo_pattern_t *src_pattern,
- cairo_pattern_t *mask_pattern,
- 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_ps_surface_t *surface = abstract_dst;
- cairo_output_stream_t *stream = surface->stream;
- cairo_surface_pattern_t *surface_pattern;
- cairo_status_t status;
- cairo_image_surface_t *image;
- void *image_extra;
-
- if (surface->need_start_page)
- _cairo_ps_surface_start_page (surface);
-
- if (mask_pattern) {
- /* FIXME: Investigate how this can be done... we'll probably
- * need pixmap fallbacks for this, though. */
- _cairo_output_stream_printf (stream,
- "%% _cairo_ps_surface_composite: with mask\n");
- goto bail;
- }
-
- status = CAIRO_STATUS_SUCCESS;
- switch (src_pattern->type) {
- case CAIRO_PATTERN_SOLID:
- _cairo_output_stream_printf (stream,
- "%% _cairo_ps_surface_composite: solid\n");
- goto bail;
-
- case CAIRO_PATTERN_SURFACE:
- surface_pattern = (cairo_surface_pattern_t *) src_pattern;
-
- if (src_pattern->extend != CAIRO_EXTEND_NONE) {
- _cairo_output_stream_printf (stream,
- "%% _cairo_ps_surface_composite: repeating image\n");
- goto bail;
- }
-
-
- status = _cairo_surface_acquire_source_image (surface_pattern->surface,
- &image,
- &image_extra);
- if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
- _cairo_output_stream_printf (stream,
- "%% _cairo_ps_surface_composite: src_pattern not available as image\n");
- goto bail;
- } else if (status) {
- break;
- }
- status = emit_image (surface, image, &src_pattern->matrix);
- _cairo_surface_release_source_image (surface_pattern->surface,
- image, image_extra);
- break;
-
- case CAIRO_PATTERN_LINEAR:
- case CAIRO_PATTERN_RADIAL:
- _cairo_output_stream_printf (stream,
- "%% _cairo_ps_surface_composite: gradient\n");
- goto bail;
- }
-
- return status;
-bail:
- return _cairo_ps_surface_add_fallback_area (surface, dst_x, dst_y, width, height);
-}
-
-static cairo_int_status_t
-_cairo_ps_surface_fill_rectangles (void *abstract_surface,
- cairo_operator_t op,
- const cairo_color_t *color,
- cairo_rectangle_t *rects,
- int num_rects)
-{
- cairo_ps_surface_t *surface = abstract_surface;
- cairo_output_stream_t *stream = surface->stream;
- cairo_solid_pattern_t solid;
- int i;
-
- if (!num_rects)
- return CAIRO_STATUS_SUCCESS;
-
- if (surface->need_start_page)
- _cairo_ps_surface_start_page (surface);
-
- if (color_operation_needs_fallback (op, color)) {
- int min_x = rects[0].x;
- int min_y = rects[0].y;
- int max_x = rects[0].x + rects[0].width;
- int max_y = rects[0].y + rects[0].height;
-
- for (i = 1; i < num_rects; i++) {
- if (rects[i].x < min_x) min_x = rects[i].x;
- if (rects[i].y < min_y) min_y = rects[i].y;
- if (rects[i].x + rects[i].width > max_x) max_x = rects[i].x + rects[i].width;
- if (rects[i].y + rects[i].height > max_y) max_y = rects[i].y + rects[i].height;
- }
- return _cairo_ps_surface_add_fallback_area (surface, min_x, min_y, max_x - min_x, max_y - min_y);
- }
-
- _cairo_output_stream_printf (stream,
- "%% _cairo_ps_surface_fill_rectangles\n");
-
- _cairo_pattern_init_solid (&solid, color);
- emit_pattern (surface, &solid.base);
- _cairo_pattern_fini (&solid.base);
-
- _cairo_output_stream_printf (stream, "[");
- for (i = 0; i < num_rects; i++) {
- _cairo_output_stream_printf (stream,
- " %d %d %d %d",
- rects[i].x, rects[i].y,
- rects[i].width, rects[i].height);
- }
-
- _cairo_output_stream_printf (stream, " ] rectfill\n");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static double
-intersect (cairo_line_t *line, cairo_fixed_t y)
-{
- return _cairo_fixed_to_double (line->p1.x) +
- _cairo_fixed_to_double (line->p2.x - line->p1.x) *
- _cairo_fixed_to_double (y - line->p1.y) /
- _cairo_fixed_to_double (line->p2.y - line->p1.y);
-}
-
-static cairo_int_status_t
-_cairo_ps_surface_composite_trapezoids (cairo_operator_t op,
- cairo_pattern_t *pattern,
- void *abstract_dst,
- cairo_antialias_t antialias,
- int x_src,
- int y_src,
- int x_dst,
- int y_dst,
- unsigned int width,
- unsigned int height,
- cairo_trapezoid_t *traps,
- int num_traps)
-{
- cairo_ps_surface_t *surface = abstract_dst;
- cairo_output_stream_t *stream = surface->stream;
- int i;
-
- if (pattern_operation_needs_fallback (op, pattern))
- return _cairo_ps_surface_add_fallback_area (surface, x_dst, y_dst, width, height);
-
- if (surface->need_start_page)
- _cairo_ps_surface_start_page (surface);
-
- _cairo_output_stream_printf (stream,
- "%% _cairo_ps_surface_composite_trapezoids\n");
-
- emit_pattern (surface, pattern);
-
- for (i = 0; i < num_traps; i++) {
- double left_x1, left_x2, right_x1, right_x2, top, bottom;
-
- left_x1 = intersect (&traps[i].left, traps[i].top);
- left_x2 = intersect (&traps[i].left, traps[i].bottom);
- right_x1 = intersect (&traps[i].right, traps[i].top);
- right_x2 = intersect (&traps[i].right, traps[i].bottom);
- top = _cairo_fixed_to_double (traps[i].top);
- bottom = _cairo_fixed_to_double (traps[i].bottom);
-
- _cairo_output_stream_printf
- (stream,
- "%f %f moveto %f %f lineto %f %f lineto %f %f lineto "
- "closepath\n",
- left_x1, top,
- left_x2, bottom,
- right_x2, bottom,
- right_x1, top);
- }
-
- _cairo_output_stream_printf (stream,
- "fill\n");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-
-static cairo_status_t
-_cairo_ps_surface_path_move_to (void *closure, cairo_point_t *point)
-{
- cairo_output_stream_t *output_stream = closure;
-
- _cairo_output_stream_printf (output_stream,
- "%f %f moveto ",
- _cairo_fixed_to_double (point->x),
- _cairo_fixed_to_double (point->y));
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_ps_surface_path_line_to (void *closure, cairo_point_t *point)
-{
- cairo_output_stream_t *output_stream = closure;
-
- _cairo_output_stream_printf (output_stream,
- "%f %f lineto ",
- _cairo_fixed_to_double (point->x),
- _cairo_fixed_to_double (point->y));
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_ps_surface_path_curve_to (void *closure,
- cairo_point_t *b,
- cairo_point_t *c,
- cairo_point_t *d)
-{
- cairo_output_stream_t *output_stream = closure;
-
- _cairo_output_stream_printf (output_stream,
- "%f %f %f %f %f %f curveto ",
- _cairo_fixed_to_double (b->x),
- _cairo_fixed_to_double (b->y),
- _cairo_fixed_to_double (c->x),
- _cairo_fixed_to_double (c->y),
- _cairo_fixed_to_double (d->x),
- _cairo_fixed_to_double (d->y));
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_status_t
-_cairo_ps_surface_path_close_path (void *closure)
-{
- cairo_output_stream_t *output_stream = closure;
-
- _cairo_output_stream_printf (output_stream,
- "closepath\n");
-
- return CAIRO_STATUS_SUCCESS;
-}
-
static cairo_int_status_t
_cairo_ps_surface_intersect_clip_path (void *abstract_surface,
cairo_path_fixed_t *path,
@@ -1119,6 +1296,9 @@ _cairo_ps_surface_intersect_clip_path (void *abstract_surface,
cairo_status_t status;
const char *ps_operator;
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ return CAIRO_STATUS_SUCCESS;
+
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_intersect_clip_path\n");
@@ -1172,81 +1352,144 @@ _cairo_ps_surface_get_extents (void *abstract_surface,
return CAIRO_STATUS_SUCCESS;
}
-#if DONE_ADDING_FONTS_SUPPORT_BACK_AFTER_SWITCHING_TO_PAGINATED
static cairo_int_status_t
-_cairo_ps_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
- cairo_operator_t op,
- cairo_pattern_t *pattern,
- void *abstract_surface,
- int source_x,
- int source_y,
- int dest_x,
- int dest_y,
- unsigned int width,
- unsigned int height,
- const cairo_glyph_t *glyphs,
- int num_glyphs)
+_cairo_ps_surface_paint (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source)
{
cairo_ps_surface_t *surface = abstract_surface;
cairo_output_stream_t *stream = surface->stream;
- cairo_font_subset_t *subset;
- int i, subset_index;
- if (surface->fallback)
- return CAIRO_STATUS_SUCCESS;
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ return _analyze_operation (surface, op, source);
+
+ /* XXX: It would be nice to be able to assert this condition
+ * here. But, we actually allow one 'cheat' that is used when
+ * painting the final image-based fallbacks. The final fallbacks
+ * do have alpha which we support by blending with white. This is
+ * possible only because there is nothing between the fallback
+ * images and the paper, nor is anything painted above. */
+ /*
+ assert (pattern_operation_supported (op, source));
+ */
+
+ _cairo_output_stream_printf (stream,
+ "%% _cairo_ps_surface_paint\n");
- if (surface->need_start_page)
- _cairo_ps_surface_start_page (surface);
+ emit_pattern (surface, source);
- /* XXX: Need to fix this to work with a general cairo_scaled_font_t. */
- if (! _cairo_scaled_font_is_ft (scaled_font))
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ _cairo_output_stream_printf (stream, "0 0 M\n");
+ _cairo_output_stream_printf (stream, "%f 0 L\n", surface->width);
+ _cairo_output_stream_printf (stream, "%f %f L\n",
+ surface->width, surface->height);
+ _cairo_output_stream_printf (stream, "0 %f L\n", surface->height);
+ _cairo_output_stream_printf (stream, "P F\n");
+ return CAIRO_STATUS_SUCCESS;
+}
- if (surface->fallback)
- return CAIRO_STATUS_SUCCESS;
+static int
+_cairo_ps_line_cap (cairo_line_cap_t cap)
+{
+ switch (cap) {
+ case CAIRO_LINE_CAP_BUTT:
+ return 0;
+ case CAIRO_LINE_CAP_ROUND:
+ return 1;
+ case CAIRO_LINE_CAP_SQUARE:
+ return 2;
+ default:
+ ASSERT_NOT_REACHED;
+ return 0;
+ }
+}
- if (pattern_operation_needs_fallback (op, pattern))
- return _cairo_ps_surface_add_fallback_area (surface, dest_x, dest_y, width, height);
+static int
+_cairo_ps_line_join (cairo_line_join_t join)
+{
+ switch (join) {
+ case CAIRO_LINE_JOIN_MITER:
+ return 0;
+ case CAIRO_LINE_JOIN_ROUND:
+ return 1;
+ case CAIRO_LINE_JOIN_BEVEL:
+ return 2;
+ default:
+ ASSERT_NOT_REACHED;
+ return 0;
+ }
+}
- _cairo_output_stream_printf (stream,
- "%% _cairo_ps_surface_old_show_glyphs\n");
+static cairo_int_status_t
+_cairo_ps_surface_stroke (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_stroke_style_t *style,
+ cairo_matrix_t *ctm,
+ cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ cairo_ps_surface_t *surface = abstract_surface;
+ cairo_output_stream_t *stream = surface->stream;
+ cairo_int_status_t status;
- emit_pattern (surface, pattern);
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ return _analyze_operation (surface, op, source);
- /* FIXME: Need to optimize this so we only do this sequence if the
- * font isn't already set. */
+ assert (operation_supported (surface, op, source));
+
+ _cairo_output_stream_printf (stream,
+ "%% _cairo_ps_surface_stroke\n");
+
+ emit_pattern (surface, source);
- subset = _cairo_ps_surface_get_font (surface, scaled_font);
_cairo_output_stream_printf (stream,
- "/f%d findfont\n"
- "[ %f %f %f %f 0 0 ] makefont\n"
- "setfont\n",
- subset->font_id,
- scaled_font->scale.xx,
- scaled_font->scale.yx,
- scaled_font->scale.xy,
- -scaled_font->scale.yy);
-
- /* FIXME: Need to optimize per glyph code. Should detect when
- * glyphs share the same baseline and when the spacing corresponds
- * to the glyph widths. */
+ "gsave\n");
+ status = _cairo_path_fixed_interpret (path,
+ CAIRO_DIRECTION_FORWARD,
+ _cairo_ps_surface_path_move_to,
+ _cairo_ps_surface_path_line_to,
+ _cairo_ps_surface_path_curve_to,
+ _cairo_ps_surface_path_close_path,
+ stream);
- for (i = 0; i < num_glyphs; i++) {
- subset_index = _cairo_font_subset_use_glyph (subset, glyphs[i].index);
- _cairo_output_stream_printf (stream,
- "%f %f moveto (\\%o) show\n",
- glyphs[i].x,
- glyphs[i].y,
- subset_index);
-
+ /*
+ * Switch to user space to set line parameters
+ */
+ _cairo_output_stream_printf (stream,
+ "[%f %f %f %f 0 0] concat\n",
+ ctm->xx, ctm->yx, ctm->xy, ctm->yy);
+ /* line width */
+ _cairo_output_stream_printf (stream, "%f setlinewidth\n",
+ style->line_width);
+ /* line cap */
+ _cairo_output_stream_printf (stream, "%d setlinecap\n",
+ _cairo_ps_line_cap (style->line_cap));
+ /* line join */
+ _cairo_output_stream_printf (stream, "%d setlinejoin\n",
+ _cairo_ps_line_join (style->line_join));
+ /* dashes */
+ if (style->num_dashes) {
+ int d;
+ _cairo_output_stream_printf (stream, "[");
+ for (d = 0; d < style->num_dashes; d++)
+ _cairo_output_stream_printf (stream, " %f", style->dash[d]);
+ _cairo_output_stream_printf (stream, "] %f setdash\n",
+ style->dash_offset);
}
-
- return CAIRO_STATUS_SUCCESS;
+ /* miter limit */
+ _cairo_output_stream_printf (stream, "%f setmiterlimit\n",
+ style->miter_limit);
+ _cairo_output_stream_printf (stream,
+ "stroke\n");
+ _cairo_output_stream_printf (stream,
+ "grestore\n");
+ return status;
}
-#endif
static cairo_int_status_t
-_cairo_ps_surface_fill (void *abstract_surface,
+_cairo_ps_surface_fill (void *abstract_surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_path_fixed_t *path,
@@ -1259,15 +1502,11 @@ _cairo_ps_surface_fill (void *abstract_surface,
cairo_int_status_t status;
const char *ps_operator;
- if (pattern_operation_needs_fallback (op, source))
- return _cairo_ps_surface_add_fallback_area (surface,
- 0, 0,
- surface->width,
- surface->height);
-
- if (surface->need_start_page)
- _cairo_ps_surface_start_page (surface);
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ return _analyze_operation (surface, op, source);
+ assert (operation_supported (surface, op, source));
+
_cairo_output_stream_printf (stream,
"%% _cairo_ps_surface_fill\n");
@@ -1283,7 +1522,7 @@ _cairo_ps_surface_fill (void *abstract_surface,
switch (fill_rule) {
case CAIRO_FILL_RULE_WINDING:
- ps_operator = "fill";
+ ps_operator = "F";
break;
case CAIRO_FILL_RULE_EVEN_ODD:
ps_operator = "eofill";
@@ -1298,7 +1537,93 @@ _cairo_ps_surface_fill (void *abstract_surface,
return status;
}
+static char
+hex_digit (int i)
+{
+ i &= 0xf;
+ if (i < 10) return '0' + i;
+ return 'a' + (i - 10);
+}
+
+static cairo_int_status_t
+_cairo_ps_surface_show_glyphs (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font)
+{
+ cairo_ps_surface_t *surface = abstract_surface;
+ cairo_output_stream_t *stream = surface->stream;
+ cairo_int_status_t status;
+ cairo_path_fixed_t *path;
+ int i;
+ int cur_subfont = -1, subfont;
+ cairo_ps_font_t *ps_font;
+ cairo_ps_glyph_t *ps_glyph;
+
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ return _analyze_operation (surface, op, source);
+
+ assert (operation_supported (surface, op, source));
+
+ _cairo_output_stream_printf (stream,
+ "%% _cairo_ps_surface_show_glyphs\n");
+ status = _cairo_ps_font_find (surface, scaled_font, &ps_font);
+ if (status)
+ goto fallback;
+
+ if (num_glyphs)
+ emit_pattern (surface, source);
+
+ for (i = 0; i < num_glyphs; i++) {
+ status = _cairo_ps_glyph_find (ps_font, scaled_font,
+ glyphs[i].index, &ps_glyph);
+ if (status) {
+ glyphs += i;
+ num_glyphs -= i;
+ goto fallback;
+ }
+ subfont = ps_glyph->output_glyph >> 8;
+ if (subfont != cur_subfont) {
+ _cairo_output_stream_printf (surface->stream,
+ "/CairoFont-%d-%d 1 selectfont\n",
+ ps_font->output_font,
+ subfont);
+ cur_subfont = subfont;
+ }
+ _cairo_output_stream_printf (surface->stream,
+ "%f %f M <%c%c> S\n",
+ glyphs[i].x, glyphs[i].y,
+ hex_digit (ps_glyph->output_glyph >> 4),
+ hex_digit (ps_glyph->output_glyph));
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+
+fallback:
+
+ path = _cairo_path_fixed_create ();
+ _cairo_scaled_font_glyph_path (scaled_font, glyphs, num_glyphs, path);
+ status = _cairo_ps_surface_fill (abstract_surface, op, source,
+ path, CAIRO_FILL_RULE_WINDING,
+ 0.1, scaled_font->options.antialias);
+ _cairo_path_fixed_destroy (path);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_ps_surface_set_paginated_mode (void *abstract_surface,
+ cairo_paginated_mode_t paginated_mode)
+{
+ cairo_ps_surface_t *surface = abstract_surface;
+
+ surface->paginated_mode = paginated_mode;
+}
+
static const cairo_surface_backend_t cairo_ps_surface_backend = {
+ CAIRO_SURFACE_TYPE_PS,
NULL, /* create_similar */
_cairo_ps_surface_finish,
NULL, /* acquire_source_image */
@@ -1306,19 +1631,15 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = {
NULL, /* acquire_dest_image */
NULL, /* release_dest_image */
NULL, /* clone_similar */
- _cairo_ps_surface_composite,
- _cairo_ps_surface_fill_rectangles,
- _cairo_ps_surface_composite_trapezoids,
+ NULL, /* composite */
+ NULL, /* fill_rectangles */
+ NULL, /* composite_trapezoids */
_cairo_ps_surface_copy_page,
_cairo_ps_surface_show_page,
NULL, /* set_clip_region */
_cairo_ps_surface_intersect_clip_path,
_cairo_ps_surface_get_extents,
-#if DONE_ADDING_FONTS_SUPPORT_BACK_AFTER_SWITCHING_TO_PAGINATED
- _cairo_ps_surface_old_show_glyphs,
-#else
NULL, /* old_show_glyphs */
-#endif
NULL, /* get_font_options */
NULL, /* flush */
NULL, /* mark_dirty_rectangle */
@@ -1327,9 +1648,15 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = {
/* Here are the drawing functions */
- NULL, /* paint */
+ _cairo_ps_surface_paint, /* paint */
NULL, /* mask */
- NULL, /* stroke */
+ _cairo_ps_surface_stroke,
_cairo_ps_surface_fill,
- NULL /* show_glyphs */
+ _cairo_ps_surface_show_glyphs,
+ NULL, /* snapshot */
+};
+
+static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend = {
+ _cairo_ps_surface_start_page,
+ _cairo_ps_surface_set_paginated_mode
};
diff --git a/src/cairo-quartz-private.h b/src/cairo-quartz-private.h
index d291c7666..8b901352b 100644
--- a/src/cairo-quartz-private.h
+++ b/src/cairo-quartz-private.h
@@ -44,15 +44,11 @@ typedef struct cairo_quartz_surface {
CGContextRef context;
- cairo_bool_t flipped;
+ cairo_bool_t y_grows_down;
- int width;
- int height;
+ cairo_rectangle_t extents;
- cairo_image_surface_t *image;
- pixman_region16_t *clip_region;
-
- CGImageRef cgImage;
+ pixman_region16_t *clip_region;
} cairo_quartz_surface_t;
cairo_bool_t
diff --git a/src/cairo-quartz-surface.c b/src/cairo-quartz-surface.c
index d7defc98e..e5b683ac4 100644
--- a/src/cairo-quartz-surface.c
+++ b/src/cairo-quartz-surface.c
@@ -37,27 +37,13 @@
#include "cairo-private.h"
#include "cairo-quartz-private.h"
-static void
-ImageDataReleaseFunc(void *info, const void *data, size_t size)
-{
- if (data != NULL) {
- free((void *) data);
- }
-}
-
static cairo_status_t
_cairo_quartz_surface_finish(void *abstract_surface)
{
cairo_quartz_surface_t *surface = abstract_surface;
- if (surface->image)
- cairo_surface_destroy(&surface->image->base);
-
- if (surface->cgImage)
- CGImageRelease(surface->cgImage);
-
- if (surface->clip_region)
- pixman_region_destroy (surface->clip_region);
+ if (surface->clip_region)
+ pixman_region_destroy (surface->clip_region);
return CAIRO_STATUS_SUCCESS;
}
@@ -67,63 +53,13 @@ _cairo_quartz_surface_acquire_source_image(void *abstract_surface,
cairo_image_surface_t **image_out,
void **image_extra)
{
- cairo_quartz_surface_t *surface = abstract_surface;
- CGColorSpaceRef colorSpace;
- void *imageData;
- UInt32 imageDataSize, rowBytes;
- CGDataProviderRef dataProvider;
-
- // We keep a cached (cairo_image_surface_t *) in the cairo_quartz_surface_t
- // struct. If the window is ever drawn to without going through Cairo, then
- // we would need to refetch the pixel data from the window into the cached
- // image surface.
- if (surface->image) {
- cairo_surface_reference(&surface->image->base);
-
- *image_out = surface->image;
- return CAIRO_STATUS_SUCCESS;
- }
-
- colorSpace = CGColorSpaceCreateDeviceRGB();
-
-
- rowBytes = surface->width * 4;
- imageDataSize = rowBytes * surface->height;
- imageData = malloc(imageDataSize);
-
- dataProvider =
- CGDataProviderCreateWithData(NULL, imageData, imageDataSize,
- ImageDataReleaseFunc);
-
- surface->cgImage = CGImageCreate(surface->width,
- surface->height,
- 8,
- 32,
- rowBytes,
- colorSpace,
- kCGImageAlphaPremultipliedFirst,
- dataProvider,
- NULL,
- false, kCGRenderingIntentDefault);
-
- CGColorSpaceRelease(colorSpace);
- CGDataProviderRelease(dataProvider);
-
- surface->image = (cairo_image_surface_t *)
- cairo_image_surface_create_for_data(imageData,
- CAIRO_FORMAT_ARGB32,
- surface->width,
- surface->height, rowBytes);
- if (surface->image->base.status) {
- if (surface->cgImage)
- CGImageRelease(surface->cgImage);
- return CAIRO_STATUS_NO_MEMORY;
- }
+ cairo_quartz_surface_t *surface = abstract_surface;
- *image_out = surface->image;
- *image_extra = NULL;
+ if (CGBitmapContextGetBitmapInfo (surface->context) != 0) {
+ /* XXX: We can create an image out of the bitmap here */
+ }
- return CAIRO_STATUS_SUCCESS;
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
static cairo_status_t
@@ -135,19 +71,79 @@ _cairo_quartz_surface_acquire_dest_image(void *abstract_surface,
void **image_extra)
{
cairo_quartz_surface_t *surface = abstract_surface;
+ cairo_surface_t *image_surface;
+ unsigned char *data;
+ int x1, y1, x2, y2;
+
+ x1 = surface->extents.x;
+ x2 = surface->extents.x + surface->extents.width;
+ y1 = surface->extents.y;
+ y2 = surface->extents.y + surface->extents.height;
+
+ if (interest_rect->x > x1)
+ x1 = interest_rect->x;
+ if (interest_rect->y > y1)
+ y1 = interest_rect->y;
+ if (interest_rect->x + interest_rect->width < x2)
+ x2 = interest_rect->x + interest_rect->width;
+ if (interest_rect->y + interest_rect->height < y2)
+ y2 = interest_rect->y + interest_rect->height;
+
+ if (x1 >= x2 || y1 >= y2) {
+ *image_out = NULL;
+ *image_extra = NULL;
+
+ return CAIRO_STATUS_SUCCESS;
+ }
- image_rect->x = 0;
- image_rect->y = 0;
- image_rect->width = surface->image->width;
- image_rect->height = surface->image->height;
+ image_rect->x = x1;
+ image_rect->y = y1;
+ image_rect->width = x2 - x1;
+ image_rect->height = y2 - y1;
- *image_out = surface->image;
- if (image_extra)
- *image_extra = NULL;
+ data = calloc (image_rect->width * image_rect->height * 4, 1);
+ image_surface = cairo_image_surface_create_for_data (data,
+ CAIRO_FORMAT_ARGB32,
+ image_rect->width,
+ image_rect->height,
+ image_rect->width * 4);
+
+ *image_out = (cairo_image_surface_t *)image_surface;
+ *image_extra = data;
return CAIRO_STATUS_SUCCESS;
+
+ return CAIRO_INT_STATUS_UNSUPPORTED;
}
+static CGImageRef
+create_image_from_surface (cairo_image_surface_t *image_surface, void *data)
+{
+ CGImageRef image;
+ CGColorSpaceRef color_space;
+ CGDataProviderRef data_provider;
+ int width, height;
+
+ width = cairo_image_surface_get_width ((cairo_surface_t *)image_surface);
+ height = cairo_image_surface_get_height ((cairo_surface_t *)image_surface);
+
+ color_space = CGColorSpaceCreateDeviceRGB();
+ data_provider = CGDataProviderCreateWithData (NULL, data,
+ width * height * 4, NULL);
+ image = CGImageCreate (width, height,
+ 8, 32,
+ width * 4,
+ color_space,
+ kCGImageAlphaPremultipliedFirst,
+ data_provider,
+ NULL,
+ FALSE, kCGRenderingIntentDefault);
+
+ CGColorSpaceRelease (color_space);
+ CGDataProviderRelease (data_provider);
+
+ return image;
+}
static void
_cairo_quartz_surface_release_dest_image(void *abstract_surface,
@@ -158,25 +154,28 @@ _cairo_quartz_surface_release_dest_image(void *abstract_surface,
void *image_extra)
{
cairo_quartz_surface_t *surface = abstract_surface;
+ CGImageRef image_ref;
+ CGRect rect;
+
+ image_ref = create_image_from_surface (image, image_extra);
- if (surface->image == image) {
- CGRect rect;
-
- rect = CGRectMake(0, 0, surface->width, surface->height);
-
- if (surface->flipped) {
- CGContextSaveGState (surface->context);
- CGContextTranslateCTM (surface->context, 0, surface->height);
- CGContextScaleCTM (surface->context, 1, -1);
- }
-
- CGContextDrawImage(surface->context, rect, surface->cgImage);
+ rect = CGRectMake (image_rect->x, image_rect->y, image_rect->width, image_rect->height);
- if (surface->flipped)
- CGContextRestoreGState (surface->context);
+ if (surface->y_grows_down) {
+ CGContextSaveGState (surface->context);
+ CGContextTranslateCTM (surface->context, 0, image_rect->height + 2 * image_rect->y);
+ CGContextScaleCTM (surface->context, 1, -1);
+ }
- memset(surface->image->data, 0, surface->width * surface->height * 4);
+ CGContextDrawImage(surface->context, rect, image_ref);
+ CFRelease (image_ref);
+
+ if (surface->y_grows_down) {
+ CGContextRestoreGState (surface->context);
}
+
+ cairo_surface_destroy ((cairo_surface_t *)image);
+ free (image_extra);
}
static cairo_int_status_t
@@ -184,21 +183,17 @@ _cairo_quartz_surface_set_clip_region(void *abstract_surface,
pixman_region16_t * region)
{
cairo_quartz_surface_t *surface = abstract_surface;
- unsigned int serial;
-
- serial = _cairo_surface_allocate_clip_serial (&surface->image->base);
- if (surface->clip_region)
- pixman_region_destroy (surface->clip_region);
+ if (surface->clip_region)
+ pixman_region_destroy (surface->clip_region);
- if (region) {
- surface->clip_region = pixman_region_create ();
- pixman_region_copy (surface->clip_region, region);
- } else
- surface->clip_region = NULL;
-
- return _cairo_surface_set_clip_region(&surface->image->base,
- region, serial);
+ if (region) {
+ surface->clip_region = pixman_region_create ();
+ pixman_region_copy (surface->clip_region, region);
+ } else
+ surface->clip_region = NULL;
+
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
@@ -207,15 +202,13 @@ _cairo_quartz_surface_get_extents (void *abstract_surface,
{
cairo_quartz_surface_t *surface = abstract_surface;
- rectangle->x = 0;
- rectangle->y = 0;
- rectangle->width = surface->width;
- rectangle->height = surface->height;
+ *rectangle = surface->extents;
return CAIRO_STATUS_SUCCESS;
}
static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
+ CAIRO_SURFACE_TYPE_QUARTZ,
NULL, /* create_similar */
_cairo_quartz_surface_finish,
_cairo_quartz_surface_acquire_source_image,
@@ -236,10 +229,12 @@ static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
cairo_surface_t *cairo_quartz_surface_create(CGContextRef context,
- cairo_bool_t flipped,
- int width, int height)
+ int width,
+ int height,
+ cairo_bool_t y_grows_down)
{
cairo_quartz_surface_t *surface;
+ CGRect clip_box;
surface = malloc(sizeof(cairo_quartz_surface_t));
if (surface == NULL) {
@@ -250,16 +245,14 @@ cairo_surface_t *cairo_quartz_surface_create(CGContextRef context,
_cairo_surface_init(&surface->base, &cairo_quartz_surface_backend);
surface->context = context;
- surface->width = width;
- surface->height = height;
- surface->image = NULL;
- surface->cgImage = NULL;
- surface->clip_region = NULL;
- surface->flipped = flipped;
-
- // Set up the image surface which Cairo draws into and we blit to & from.
- void *foo;
- _cairo_quartz_surface_acquire_source_image(surface, &surface->image, &foo);
+ surface->clip_region = NULL;
+ surface->y_grows_down = y_grows_down;
+
+ clip_box = CGContextGetClipBoundingBox (context);
+ surface->extents.x = clip_box.origin.x;
+ surface->extents.y = clip_box.origin.y;
+ surface->extents.width = clip_box.size.width;
+ surface->extents.height = clip_box.size.height;
return (cairo_surface_t *) surface;
}
diff --git a/src/cairo-quartz.h b/src/cairo-quartz.h
index 9ef537ed3..b3072df76 100644
--- a/src/cairo-quartz.h
+++ b/src/cairo-quartz.h
@@ -47,9 +47,9 @@ CAIRO_BEGIN_DECLS
cairo_public cairo_surface_t *
cairo_quartz_surface_create (CGContextRef context,
- cairo_bool_t flipped,
int width,
- int height);
+ int height,
+ cairo_bool_t y_grows_down);
CAIRO_END_DECLS
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 8ebbf455f..91e62578f 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -39,10 +39,10 @@
#include "cairoint.h"
static cairo_bool_t
-_cairo_scaled_glyph_keys_equal (void *abstract_key_a, void *abstract_key_b)
+_cairo_scaled_glyph_keys_equal (const void *abstract_key_a, const void *abstract_key_b)
{
- cairo_scaled_glyph_t *key_a = abstract_key_a;
- cairo_scaled_glyph_t *key_b = abstract_key_b;
+ const cairo_scaled_glyph_t *key_a = abstract_key_a;
+ const cairo_scaled_glyph_t *key_b = abstract_key_b;
return (_cairo_scaled_glyph_index (key_a) ==
_cairo_scaled_glyph_index (key_b));
@@ -119,6 +119,18 @@ _cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
}
/**
+ * cairo_scaled_font_get_type:
+ * @scaled_font: a #cairo_scaled_font_t
+ *
+ * Return value: The type of @scaled_font. See #cairo_font_type_t.
+ **/
+cairo_font_type_t
+cairo_scaled_font_get_type (cairo_scaled_font_t *scaled_font)
+{
+ return scaled_font->backend->type;
+}
+
+/**
* cairo_scaled_font_status:
* @scaled_font: a #cairo_scaled_font_t
*
@@ -168,7 +180,7 @@ static cairo_scaled_font_map_t *cairo_scaled_font_map = NULL;
CAIRO_MUTEX_DECLARE (cairo_scaled_font_map_mutex);
static int
-_cairo_scaled_font_keys_equal (void *abstract_key_a, void *abstract_key_b);
+_cairo_scaled_font_keys_equal (const void *abstract_key_a, const void *abstract_key_b);
static cairo_scaled_font_map_t *
_cairo_scaled_font_map_lock (void)
@@ -286,10 +298,10 @@ _cairo_scaled_font_init_key (cairo_scaled_font_t *scaled_font,
}
static cairo_bool_t
-_cairo_scaled_font_keys_equal (void *abstract_key_a, void *abstract_key_b)
+_cairo_scaled_font_keys_equal (const void *abstract_key_a, const void *abstract_key_b)
{
- cairo_scaled_font_t *key_a = abstract_key_a;
- cairo_scaled_font_t *key_b = abstract_key_b;
+ const cairo_scaled_font_t *key_a = abstract_key_a;
+ const cairo_scaled_font_t *key_b = abstract_key_b;
return (key_a->font_face == key_b->font_face &&
memcmp ((unsigned char *)(&key_a->font_matrix.xx),
@@ -1008,7 +1020,7 @@ _scaled_glyph_path_close_path (void *abstract_closure)
cairo_status_t
_cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
- cairo_glyph_t *glyphs,
+ const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_path_fixed_t *path)
{
diff --git a/src/cairo-surface-fallback.c b/src/cairo-surface-fallback.c
index 8f18ca33b..a5c723f15 100644
--- a/src/cairo-surface-fallback.c
+++ b/src/cairo-surface-fallback.c
@@ -451,6 +451,10 @@ _composite_trap_region (cairo_clip_t *clip,
extents->x, extents->y,
extents->width, extents->height);
+ /* Restore the original clip if we modified it temporarily. */
+ if (num_rects >1)
+ _cairo_surface_set_clip (dst, clip);
+
if (clip_surface)
_cairo_pattern_fini (&mask.base);
@@ -549,6 +553,9 @@ _clip_and_composite_trapezoids (cairo_pattern_t *src,
return status;
clear_region = _cairo_region_create_from_rectangle (&extents);
+ if (clear_region == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
status = _cairo_clip_intersect_to_region (clip, clear_region);
if (status)
return status;
@@ -576,7 +583,7 @@ _clip_and_composite_trapezoids (cairo_pattern_t *src,
{
cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
- if ((src->type == CAIRO_PATTERN_SOLID || op == CAIRO_OPERATOR_CLEAR) &&
+ if ((src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR) &&
!clip_surface)
{
const cairo_color_t *color;
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 29820173e..9a15db4f6 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -43,6 +43,7 @@
const cairo_surface_t _cairo_surface_nil = {
&cairo_image_surface_backend, /* backend */
+ CAIRO_SURFACE_TYPE_IMAGE,
-1, /* ref_count */
CAIRO_STATUS_NO_MEMORY, /* status */
FALSE, /* finished */
@@ -59,6 +60,7 @@ const cairo_surface_t _cairo_surface_nil = {
const cairo_surface_t _cairo_surface_nil_file_not_found = {
&cairo_image_surface_backend, /* backend */
+ CAIRO_SURFACE_TYPE_IMAGE,
-1, /* ref_count */
CAIRO_STATUS_FILE_NOT_FOUND, /* status */
FALSE, /* finished */
@@ -75,6 +77,7 @@ const cairo_surface_t _cairo_surface_nil_file_not_found = {
const cairo_surface_t _cairo_surface_nil_read_error = {
&cairo_image_surface_backend, /* backend */
+ CAIRO_SURFACE_TYPE_IMAGE,
-1, /* ref_count */
CAIRO_STATUS_READ_ERROR, /* status */
FALSE, /* finished */
@@ -119,6 +122,22 @@ _cairo_surface_set_error (cairo_surface_t *surface,
}
/**
+ * cairo_surface_get_type:
+ * @surface: a #cairo_surface_t
+ *
+ * Return value: The type of @surface. See #cairo_surface_type_t.
+ **/
+cairo_surface_type_t
+cairo_surface_get_type (cairo_surface_t *surface)
+{
+ /* We don't use surface->backend->type here so that some of the
+ * special "wrapper" surfaces such as cairo_paginated_surface_t
+ * can override surface->type with the type of the "child"
+ * surface. */
+ return surface->type;
+}
+
+/**
* cairo_surface_status:
* @surface: a #cairo_surface_t
*
@@ -141,6 +160,8 @@ _cairo_surface_init (cairo_surface_t *surface,
const cairo_surface_backend_t *backend)
{
surface->backend = backend;
+
+ surface->type = backend->type;
surface->ref_count = 1;
surface->status = CAIRO_STATUS_SUCCESS;
@@ -186,7 +207,8 @@ _cairo_surface_create_similar_scratch (cairo_surface_t *other,
*
* Create a new surface that is as compatible as possible with an
* existing surface. The new surface will use the same backend as
- * @other unless that is not possible for some reason.
+ * @other unless that is not possible for some reason. The type of the
+ * returned surface may be examined with cairo_surface_get_type().
*
* Return value: a pointer to the newly allocated surface. The caller
* owns the surface and should call cairo_surface_destroy when done
@@ -502,6 +524,10 @@ cairo_surface_mark_dirty (cairo_surface_t *surface)
* Like cairo_surface_mark_dirty(), but drawing has been done only to
* the specified rectangle, so that cairo can retain cached contents
* for other parts of the surface.
+ *
+ * Any cached clip set on the surface will be reset by this function,
+ * to make sure that future cairo calls have the clip set that they
+ * expect.
*/
void
cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
@@ -520,6 +546,13 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
return;
}
+ /* Always reset the clip here, to avoid having external calls to
+ * clip manipulation functions of the underlying device clip result
+ * in a desync between the cairo clip and the backend clip, due to
+ * the clip caching.
+ */
+ surface->current_clip_serial = -1;
+
if (surface->backend->mark_dirty_rectangle) {
cairo_status_t status;
@@ -1329,6 +1362,12 @@ _cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip)
if (!surface)
return CAIRO_STATUS_NULL_POINTER;
+ if (surface->status)
+ return surface->status;
+
+ if (surface->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
if (clip) {
serial = clip->serial;
if (serial == 0)
@@ -1336,7 +1375,7 @@ _cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip)
}
surface->clip = clip;
-
+
if (serial == _cairo_surface_get_current_clip_serial (surface))
return CAIRO_STATUS_SUCCESS;
@@ -1654,3 +1693,39 @@ _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst,
return _cairo_surface_composite_fixup_unbounded_internal (dst, src_rectangle, mask_rectangle,
dst_x, dst_y, width, height);
}
+
+static cairo_bool_t
+_format_is_opaque (cairo_format_t format)
+{
+ switch (format) {
+ case CAIRO_FORMAT_ARGB32:
+ return FALSE;
+ case CAIRO_FORMAT_RGB24:
+ return TRUE;
+ case CAIRO_FORMAT_A8:
+ return FALSE;
+ case CAIRO_FORMAT_A1:
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* XXX: This function is funny in a couple of ways. First it seems to
+ * be computing something like "not translucent" rather than "opaque"
+ * since it returns TRUE for an A1 image surface. Second, it just
+ * gives up on anything other than an image surface.
+ *
+ * I imagine something that might be more useful here (or in addition)
+ * would be cairo_surface_get_content.
+ */
+cairo_bool_t
+_cairo_surface_is_opaque (const cairo_surface_t *surface)
+{
+ if (_cairo_surface_is_image (surface)) {
+ const cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
+
+ return _format_is_opaque (image_surface->format);
+ }
+
+ return FALSE;
+}
diff --git a/src/cairo-svg-surface.c b/src/cairo-svg-surface.c
index 929700569..90a053a6f 100644
--- a/src/cairo-svg-surface.c
+++ b/src/cairo-svg-surface.c
@@ -75,11 +75,15 @@ struct cairo_svg_document {
unsigned int filter_id;
unsigned int clip_id;
unsigned int mask_id;
+
+ cairo_bool_t alpha_filter;
};
struct cairo_svg_surface {
cairo_surface_t base;
+ cairo_content_t content;
+
unsigned int id;
double width;
@@ -88,8 +92,12 @@ struct cairo_svg_surface {
cairo_svg_document_t *document;
xmlNodePtr xml_node;
+ xmlNodePtr xml_root_node;
unsigned int clip_level;
+
+ cairo_bool_t modified;
+ unsigned int previous_id;
};
static cairo_svg_document_t *
@@ -108,8 +116,9 @@ _cairo_svg_document_reference (cairo_svg_document_t *document);
static cairo_surface_t *
_cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
- double width,
- double height);
+ cairo_content_t content,
+ double width,
+ double height);
static const cairo_surface_backend_t cairo_svg_surface_backend;
@@ -125,7 +134,8 @@ _cairo_svg_surface_create_for_stream_internal (cairo_output_stream_t *stream,
if (document == NULL)
return NULL;
- surface = _cairo_svg_surface_create_for_document (document, width, height);
+ surface = _cairo_svg_surface_create_for_document (document, CAIRO_CONTENT_COLOR_ALPHA,
+ width, height);
document->owner = surface;
_cairo_svg_document_destroy (document);
@@ -133,35 +143,90 @@ _cairo_svg_surface_create_for_stream_internal (cairo_output_stream_t *stream,
return surface;
}
+/**
+ * cairo_svg_surface_create_for_stream:
+ * @write: a #cairo_write_func_t to accept the output data
+ * @closure: the closure argument for @write
+ * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
+ * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
+ *
+ * Creates a SVG surface of the specified size in points to be written
+ * incrementally to the stream represented by @write and @closure.
+ *
+ * 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.
+ */
cairo_surface_t *
cairo_svg_surface_create_for_stream (cairo_write_func_t write,
void *closure,
double width,
double height)
{
+ cairo_status_t status;
cairo_output_stream_t *stream;
- stream = _cairo_output_stream_create (write, closure);
- if (stream == NULL)
- return NULL;
+ stream = _cairo_output_stream_create (write, NULL, closure);
+ status = _cairo_output_stream_get_status (stream);
+ if (status) {
+ _cairo_error (status);
+ return (cairo_surface_t *) &_cairo_surface_nil;
+ }
return _cairo_svg_surface_create_for_stream_internal (stream, width, height);
}
+/**
+ * cairo_svg_surface_create:
+ * @filename: a filename for the SVG output (must be writable)
+ * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch)
+ * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch)
+ *
+ * Creates a SVG surface of the specified size in points to be written
+ * to @filename.
+ *
+ * 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.
+ **/
cairo_surface_t *
cairo_svg_surface_create (const char *filename,
double width,
double height)
{
+ cairo_status_t status;
cairo_output_stream_t *stream;
- stream = _cairo_output_stream_create_for_file (filename);
- if (stream == NULL)
- return NULL;
+ stream = _cairo_output_stream_create_for_filename (filename);
+ status = _cairo_output_stream_get_status (stream);
+ if (status) {
+ _cairo_error (status);
+ return (cairo_surface_t *) &_cairo_surface_nil;
+ }
return _cairo_svg_surface_create_for_stream_internal (stream, width, height);
}
+/**
+ * cairo_svg_surface_set_dpi:
+ * @surface: a svg cairo_surface_t
+ * @x_dpi: horizontal dpi
+ * @y_dpi: vertical dpi
+ *
+ * Set the horizontal and vertical resolution for image fallbacks.
+ * When the svg backend needs to fall back to image overlays, it will
+ * use this resolution. These DPI values are not used for any other
+ * purpose, (in particular, they do not have any bearing on the size
+ * passed to cairo_svg_surface_create() nor on the CTM).
+ **/
void
cairo_svg_surface_set_dpi (cairo_surface_t *surface,
double x_dpi,
@@ -175,11 +240,12 @@ cairo_svg_surface_set_dpi (cairo_surface_t *surface,
static cairo_surface_t *
_cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
- double width,
- double height)
+ cairo_content_t content,
+ double width,
+ double height)
{
cairo_svg_surface_t *surface;
- xmlNodePtr clip, clip_rect;
+ xmlNodePtr clip, rect;
int clip_id;
char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
@@ -203,22 +269,33 @@ _cairo_svg_surface_create_for_document (cairo_svg_document_t *document,
clip = xmlNewChild (document->xml_node_defs, NULL, CC2XML ("clipPath"), NULL);
snprintf (buffer, sizeof buffer, "clip%d", clip_id);
xmlSetProp (clip, CC2XML ("id"), C2XML (buffer));
- clip_rect = xmlNewChild (clip, NULL, CC2XML ("rect"), NULL);
+ rect = xmlNewChild (clip, NULL, CC2XML ("rect"), NULL);
_cairo_dtostr (buffer, sizeof buffer, width);
- xmlSetProp (clip_rect, CC2XML ("width"), C2XML (buffer));
+ xmlSetProp (rect, CC2XML ("width"), C2XML (buffer));
_cairo_dtostr (buffer, sizeof buffer, height);
- xmlSetProp (clip_rect, CC2XML ("height"), C2XML (buffer));
+ xmlSetProp (rect, CC2XML ("height"), C2XML (buffer));
- surface->xml_node = xmlNewChild (surface->id == 0 ?
- document->xml_node_main :
- document->xml_node_defs,
- NULL, CC2XML ("g"), NULL);
+ surface->xml_node = xmlNewNode (NULL, CC2XML ("g"));
+ surface->xml_root_node = surface->xml_node;
snprintf (buffer, sizeof buffer, "surface%d", surface->id);
xmlSetProp (surface->xml_node, CC2XML ("id"), C2XML (buffer));
snprintf (buffer, sizeof buffer, "url(#clip%d)", clip_id);
xmlSetProp (surface->xml_node, CC2XML ("clip-path"), C2XML (buffer));
-
+
+ if (content == CAIRO_CONTENT_COLOR) {
+ rect = xmlNewChild (surface->xml_node, NULL, CC2XML ("rect"), NULL);
+ _cairo_dtostr (buffer, sizeof buffer, width);
+ xmlSetProp (rect, CC2XML ("width"), C2XML (buffer));
+ _cairo_dtostr (buffer, sizeof buffer, height);
+ xmlSetProp (rect, CC2XML ("height"), C2XML (buffer));
+ xmlSetProp (rect, CC2XML ("style"), CC2XML ("opacity:1; stroke:none; fill:rgb(0,0,0);"));
+ }
+
+ surface->modified = TRUE;
+ surface->previous_id = surface->id;
+ surface->content = content;
+
return &surface->base;
}
@@ -231,7 +308,7 @@ _cairo_svg_surface_create_similar (void *abstract_src,
cairo_svg_surface_t *template = abstract_src;
return _cairo_svg_surface_create_for_document (template->document,
- width, height);
+ content, width, height);
}
static cairo_status_t
@@ -240,18 +317,46 @@ _cairo_svg_surface_finish (void *abstract_surface)
cairo_status_t status;
cairo_svg_surface_t *surface = abstract_surface;
cairo_svg_document_t *document = surface->document;
+
- if (document->owner == &surface->base)
+ if (document->owner == &surface->base) {
+ xmlAddChild (document->xml_node_main, xmlCopyNode (surface->xml_root_node, 1));
status = _cairo_svg_document_finish (document);
- else
+ } else
status = CAIRO_STATUS_SUCCESS;
_cairo_svg_document_destroy (document);
+ xmlFreeNode (surface->xml_root_node);
+ surface->xml_node = NULL;
+
return status;
}
static void
+emit_alpha_filter (cairo_svg_document_t *document)
+{
+ if (!document->alpha_filter) {
+ xmlNodePtr node;
+ xmlNodePtr child;
+
+ node = xmlNewChild (document->xml_node_defs, NULL,
+ CC2XML ("filter"), NULL);
+ xmlSetProp (node, CC2XML ("id"), CC2XML ("alpha"));
+ xmlSetProp (node, CC2XML ("filterUnits"), CC2XML ("objectBoundingBox"));
+ xmlSetProp (node, CC2XML ("x"), CC2XML ("0%"));
+ xmlSetProp (node, CC2XML ("y"), CC2XML ("0%"));
+ xmlSetProp (node, CC2XML ("width"), CC2XML ("100%"));
+ xmlSetProp (node, CC2XML ("height"), CC2XML ("100%"));
+ child = xmlNewChild (node, NULL, CC2XML ("feColorMatrix"), NULL);
+ xmlSetProp (child, CC2XML("type"), CC2XML ("matrix"));
+ xmlSetProp (child, CC2XML("in"), CC2XML ("SourceGraphic"));
+ xmlSetProp (child, CC2XML("values"), CC2XML ("0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"));
+ document->alpha_filter = TRUE;
+ }
+}
+
+static void
emit_transform (xmlNodePtr node,
char const *attribute_str,
cairo_matrix_t *matrix)
@@ -263,22 +368,22 @@ emit_transform (xmlNodePtr node,
xmlBufferCat (matrix_buffer, CC2XML ("matrix("));
_cairo_dtostr (buffer, sizeof buffer, matrix->xx);
xmlBufferCat (matrix_buffer, C2XML (buffer));
- xmlBufferCat (matrix_buffer, ",");
+ xmlBufferCat (matrix_buffer, CC2XML (","));
_cairo_dtostr (buffer, sizeof buffer, matrix->yx);
xmlBufferCat (matrix_buffer, C2XML (buffer));
- xmlBufferCat (matrix_buffer, ",");
+ xmlBufferCat (matrix_buffer, CC2XML (","));
_cairo_dtostr (buffer, sizeof buffer, matrix->xy);
xmlBufferCat (matrix_buffer, C2XML (buffer));
- xmlBufferCat (matrix_buffer, ",");
+ xmlBufferCat (matrix_buffer, CC2XML (","));
_cairo_dtostr (buffer, sizeof buffer, matrix->yy);
xmlBufferCat (matrix_buffer, C2XML (buffer));
- xmlBufferCat (matrix_buffer, ",");
+ xmlBufferCat (matrix_buffer, CC2XML (","));
_cairo_dtostr (buffer, sizeof buffer, matrix->x0);
xmlBufferCat (matrix_buffer, C2XML (buffer));
- xmlBufferCat (matrix_buffer, ",");
+ xmlBufferCat (matrix_buffer, CC2XML(","));
_cairo_dtostr (buffer, sizeof buffer, matrix->y0);
xmlBufferCat (matrix_buffer, C2XML (buffer));
- xmlBufferCat (matrix_buffer, ")");
+ xmlBufferCat (matrix_buffer, CC2XML (")"));
xmlSetProp (node, CC2XML (attribute_str), C2XML (xmlBufferContent (matrix_buffer)));
xmlBufferFree (matrix_buffer);
}
@@ -288,11 +393,10 @@ typedef struct {
unsigned int in_mem;
unsigned char src[3];
unsigned char dst[5];
- unsigned int count;
unsigned int trailing;
} base64_write_closure_t;
-static unsigned char const *base64_table =
+static char const *base64_table =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static cairo_status_t
@@ -322,11 +426,6 @@ base64_write_func (void *closure,
data++;
length--;
}
- info->count++;
- if (info->count >= 18) {
- info->count = 0;
- xmlBufferCat (info->buffer, "\r\n");
- }
dst[0] = base64_table[src[0] >> 2];
dst[1] = base64_table[(src[0] & 0x03) << 4 | src[1] >> 4];
dst[2] = base64_table[(src[1] & 0x0f) << 2 | src[2] >> 6];
@@ -366,7 +465,6 @@ _cairo_surface_base64_encode (cairo_surface_t *surface,
info.buffer = xmlBufferCreate();
info.in_mem = 0;
- info.count = 0;
info.trailing = 0;
memset (info.dst, '\x0', 5);
*buffer = info.buffer;
@@ -450,16 +548,22 @@ emit_composite_svg_pattern (xmlNodePtr node,
cairo_bool_t is_pattern)
{
cairo_svg_surface_t *surface = (cairo_svg_surface_t *) pattern->surface;
+ cairo_svg_document_t *document = surface->document;
cairo_matrix_t p2u;
xmlNodePtr child;
char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
- /* FIXME: self copy is not supported yet */
- if (surface->id == 0)
- return NULL;
+ if (surface->modified) {
+ if (surface->content == CAIRO_CONTENT_ALPHA)
+ emit_alpha_filter (document);
+ child = xmlAddChild (document->xml_node_defs, xmlCopyNode (surface->xml_root_node, 1));
+ if (surface->content == CAIRO_CONTENT_ALPHA)
+ xmlSetProp (child, CC2XML ("filter"), CC2XML("url(#alpha)"));
+ }
child = xmlNewChild (node, NULL, CC2XML("use"), NULL);
- snprintf (buffer, sizeof buffer, "#surface%d", surface->id);
+ snprintf (buffer, sizeof buffer, "#surface%d",
+ surface->modified ? surface->id : surface->previous_id);
xmlSetProp (child, CC2XML ("xlink:href"), C2XML (buffer));
if (!is_pattern) {
@@ -473,6 +577,14 @@ emit_composite_svg_pattern (xmlNodePtr node,
if (height != NULL)
*height = surface->height;
+ if (surface->modified) {
+ surface->modified = FALSE;
+ surface->previous_id = surface->id;
+ surface->id = document->surface_id++;
+ snprintf (buffer, sizeof buffer, "surface%d", surface->id);
+ xmlSetProp (surface->xml_root_node, CC2XML ("id"), C2XML (buffer));
+ }
+
return child;
}
@@ -762,19 +874,19 @@ emit_pattern (cairo_svg_surface_t *surface, cairo_pattern_t *pattern,
xmlBufferPtr style, int is_stroke)
{
switch (pattern->type) {
- case CAIRO_PATTERN_SOLID:
+ case CAIRO_PATTERN_TYPE_SOLID:
emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern, style, is_stroke);
break;
- case CAIRO_PATTERN_SURFACE:
+ case CAIRO_PATTERN_TYPE_SURFACE:
emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern, style, is_stroke);
break;
- case CAIRO_PATTERN_LINEAR:
+ case CAIRO_PATTERN_TYPE_LINEAR:
emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern, style, is_stroke);
break;
- case CAIRO_PATTERN_RADIAL:
+ case CAIRO_PATTERN_TYPE_RADIAL:
emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern, style, is_stroke);
break;
}
@@ -887,9 +999,9 @@ _cairo_svg_surface_fill (void *abstract_surface,
style = xmlBufferCreate ();
emit_pattern (surface, source, style, 0);
- xmlBufferCat (style, " stroke: none;");
- xmlBufferCat (style, " fill-rule: ");
- xmlBufferCat (style, fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd;" : "nonzero;");
+ xmlBufferCat (style, CC2XML (" stroke: none;"));
+ xmlBufferCat (style, CC2XML (" fill-rule: "));
+ xmlBufferCat (style, fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? CC2XML("evenodd;") : CC2XML ("nonzero;"));
status = _cairo_path_fixed_interpret (path,
CAIRO_DIRECTION_FORWARD,
@@ -907,6 +1019,7 @@ _cairo_svg_surface_fill (void *abstract_surface,
xmlBufferFree (info.path);
xmlBufferFree (style);
+ surface->modified = TRUE;
return status;
}
@@ -939,14 +1052,15 @@ emit_paint (xmlNodePtr node,
xmlBufferPtr style;
char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
- if (source->type == CAIRO_PATTERN_SURFACE)
+ if (source->type == CAIRO_PATTERN_TYPE_SURFACE &&
+ source->extend == CAIRO_EXTEND_NONE)
return emit_composite_pattern (node,
(cairo_surface_pattern_t *) source,
NULL, NULL, FALSE);
style = xmlBufferCreate ();
emit_pattern (surface, source, style, 0);
- xmlBufferCat (style, " stroke: none;");
+ xmlBufferCat (style, CC2XML (" stroke: none;"));
child = xmlNewChild (node, NULL, CC2XML ("rect"), NULL);
xmlSetProp (child, CC2XML ("x"), CC2XML ("0"));
@@ -970,7 +1084,40 @@ _cairo_svg_surface_paint (void *abstract_surface,
{
cairo_svg_surface_t *surface = abstract_surface;
+ /* Emulation of clear and source operators, when no clipping region
+ * is defined. We just delete existing content of surface root node,
+ * and exit early if operator is clear. */
+ if (surface->clip_level == 0 &&
+ (op == CAIRO_OPERATOR_CLEAR ||
+ op == CAIRO_OPERATOR_SOURCE)) {
+ xmlNodePtr child = surface->xml_root_node->children;
+
+ while (child != NULL) {
+ xmlUnlinkNode (child);
+ xmlFreeNode (child);
+ child = surface->xml_root_node->children;
+ }
+
+ if (op == CAIRO_OPERATOR_CLEAR) {
+ if (surface->content == CAIRO_CONTENT_COLOR) {
+ xmlNodePtr rect;
+ char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
+
+ rect = xmlNewChild (surface->xml_node, NULL, CC2XML ("rect"), NULL);
+ _cairo_dtostr (buffer, sizeof buffer, surface->width);
+ xmlSetProp (rect, CC2XML ("width"), C2XML (buffer));
+ _cairo_dtostr (buffer, sizeof buffer, surface->height);
+ xmlSetProp (rect, CC2XML ("height"), C2XML (buffer));
+ xmlSetProp (rect, CC2XML ("style"), CC2XML ("opacity:1; stroke:none; fill:rgb(0,0,0);"));
+ }
+ surface->modified = TRUE;
+ return CAIRO_STATUS_SUCCESS;
+ }
+ }
+
emit_paint (surface->xml_node, surface, op, source);
+
+ surface->modified = TRUE;
return CAIRO_STATUS_SUCCESS;
}
@@ -985,10 +1132,16 @@ _cairo_svg_surface_mask (void *abstract_surface,
xmlNodePtr child, mask_node;
char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
- mask_node = xmlNewChild (document->xml_node_defs, NULL, CC2XML ("mask"), NULL);
+ emit_alpha_filter (document);
+
+ mask_node = xmlNewNode (NULL, CC2XML ("mask"));
snprintf (buffer, sizeof buffer, "mask%d", document->mask_id);
xmlSetProp (mask_node, CC2XML ("id"), C2XML (buffer));
- emit_paint (mask_node, surface, op, mask);
+ child = xmlNewChild (mask_node, NULL, CC2XML ("g"), NULL);
+ xmlSetProp (child, CC2XML ("filter"), CC2XML ("url(#alpha)"));
+ emit_paint (child, surface, op, mask);
+
+ xmlAddChild (document->xml_node_defs, mask_node);
child = emit_paint (surface->xml_node, surface, op, source);
@@ -999,6 +1152,7 @@ _cairo_svg_surface_mask (void *abstract_surface,
document->mask_id++;
+ surface->modified = TRUE;
return CAIRO_STATUS_SUCCESS;
}
@@ -1064,21 +1218,21 @@ _cairo_svg_surface_stroke (void *abstract_dst,
xmlBufferCat (style, CC2XML (" stroke-dasharray: "));
for (i = 0; i < stroke_style->num_dashes; i++) {
if (i != 0)
- xmlBufferCat (style, ",");
+ xmlBufferCat (style, CC2XML (","));
/* FIXME: Is is really what we want ? */
rx = ry = stroke_style->dash[i];
cairo_matrix_transform_distance (ctm, &rx, &ry);
_cairo_dtostr (buffer, sizeof buffer, sqrt ((rx * rx + ry * ry) / 2.0));
xmlBufferCat (style, C2XML (buffer));
}
- xmlBufferCat (style, ";");
+ xmlBufferCat (style, CC2XML (";"));
if (stroke_style->dash_offset != 0.0) {
xmlBufferCat (style, CC2XML (" stroke-dashoffset: "));
rx = ry = stroke_style->dash_offset;
cairo_matrix_transform_distance (ctm, &rx, &ry);
_cairo_dtostr (buffer, sizeof buffer, sqrt ((rx * rx + ry * ry) / 2.0));
xmlBufferCat (style, C2XML (buffer));
- xmlBufferCat (style, ";");
+ xmlBufferCat (style, CC2XML (";"));
}
}
@@ -1103,6 +1257,7 @@ _cairo_svg_surface_stroke (void *abstract_dst,
xmlBufferFree (info.path);
xmlBufferFree (style);
+ surface->modified = TRUE;
return status;
}
@@ -1114,6 +1269,7 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
int num_glyphs,
cairo_scaled_font_t *scaled_font)
{
+ cairo_svg_surface_t *surface = abstract_surface;
cairo_path_fixed_t path;
cairo_status_t status;
@@ -1137,6 +1293,7 @@ _cairo_svg_surface_show_glyphs (void *abstract_surface,
_cairo_path_fixed_fini (&path);
+ surface->modified = TRUE;
return status;
}
@@ -1155,10 +1312,8 @@ _cairo_svg_surface_intersect_clip_path (void *dst,
char buffer[CAIRO_SVG_DTOSTR_BUFFER_LEN];
if (path == NULL) {
- while (surface->clip_level > 0) {
- surface->xml_node = surface->xml_node->parent;
- surface->clip_level--;
- }
+ surface->xml_node = surface->xml_root_node;
+ surface->clip_level = 0;
return CAIRO_STATUS_SUCCESS;
}
@@ -1208,6 +1363,7 @@ _cairo_svg_surface_get_font_options (void *abstract_surface,
static const cairo_surface_backend_t cairo_svg_surface_backend = {
+ CAIRO_SURFACE_TYPE_SVG,
_cairo_svg_surface_create_similar,
_cairo_svg_surface_finish,
NULL, /* acquire_source_image */
@@ -1284,6 +1440,8 @@ _cairo_svg_document_create (cairo_output_stream_t *output_stream,
xmlSetProp (node, CC2XML ("xmlns:xlink"), CC2XML ("http://www.w3.org/1999/xlink"));
xmlSetProp (node, CC2XML ("version"), CC2XML ("1.2"));
+ document->alpha_filter = FALSE;
+
return document;
}
@@ -1305,21 +1463,39 @@ _cairo_svg_document_destroy (cairo_svg_document_t *document)
free (document);
}
+static int
+_cairo_svg_document_write (cairo_output_stream_t *output_stream,
+ const char * buffer,
+ int len)
+{
+ cairo_status_t status;
+
+ _cairo_output_stream_write (output_stream, buffer, len);
+ status = _cairo_output_stream_get_status (output_stream);
+ if (status) {
+ _cairo_error (status);
+ return -1;
+ }
+
+ return len;
+}
+
static cairo_status_t
_cairo_svg_document_finish (cairo_svg_document_t *document)
{
cairo_status_t status;
cairo_output_stream_t *output = document->output_stream;
- xmlChar *xml_buffer;
- int xml_buffer_size;
+ xmlOutputBufferPtr xml_output_buffer;
if (document->finished)
return CAIRO_STATUS_SUCCESS;
- /* FIXME: Dumping xml tree in memory is silly. */
- xmlDocDumpFormatMemoryEnc (document->xml_doc, &xml_buffer, &xml_buffer_size, "UTF-8", 1);
- _cairo_output_stream_write (document->output_stream, xml_buffer, xml_buffer_size);
- xmlFree(xml_buffer);
+ xml_output_buffer = xmlOutputBufferCreateIO ((xmlOutputWriteCallback) _cairo_svg_document_write,
+ (xmlOutputCloseCallback) NULL,
+ (void *) document->output_stream,
+ NULL);
+ xmlSaveFormatFileTo (xml_output_buffer, document->xml_doc, "UTF-8", 1);
+
xmlFreeDoc (document->xml_doc);
status = _cairo_output_stream_get_status (output);
diff --git a/src/cairo-wideint.c b/src/cairo-wideint.c
index 9e4914e61..89df00b37 100644
--- a/src/cairo-wideint.c
+++ b/src/cairo-wideint.c
@@ -1,5 +1,4 @@
-/*
- * $Id: cairo-wideint.c,v 1.6 2005-07-30 19:57:54 keithp Exp $
+/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Keith Packard
*
diff --git a/src/cairo-wideint.h b/src/cairo-wideint.h
index b008b5d5a..795cde73d 100644
--- a/src/cairo-wideint.h
+++ b/src/cairo-wideint.h
@@ -1,5 +1,4 @@
-/*
- * $Id: cairo-wideint.h,v 1.12 2005-08-05 14:48:19 cworth Exp $
+/* cairo - a vector graphics library with display and print output
*
* Copyright © 2004 Keith Packard
*
diff --git a/src/cairo-win32-font.c b/src/cairo-win32-font.c
index 3343abfd4..e7c671390 100644
--- a/src/cairo-win32-font.c
+++ b/src/cairo-win32-font.c
@@ -1159,7 +1159,7 @@ _cairo_win32_scaled_font_show_glyphs (void *abstract_font,
cairo_surface_pattern_t mask;
RECT r;
- tmp_surface = (cairo_win32_surface_t *)_cairo_win32_surface_create_dib (CAIRO_FORMAT_ARGB32, width, height);
+ tmp_surface = (cairo_win32_surface_t *)cairo_win32_surface_create_with_dib (CAIRO_FORMAT_ARGB32, width, height);
if (tmp_surface->base.status)
return CAIRO_STATUS_NO_MEMORY;
@@ -1355,6 +1355,7 @@ CLEANUP_FONT:
}
const cairo_scaled_font_backend_t cairo_win32_scaled_font_backend = {
+ CAIRO_FONT_TYPE_WIN32,
_cairo_win32_scaled_font_create_toy,
_cairo_win32_scaled_font_fini,
_cairo_win32_scaled_font_glyph_init,
@@ -1398,6 +1399,7 @@ _cairo_win32_font_face_scaled_font_create (void *abstract_face,
}
static const cairo_font_face_backend_t _cairo_win32_font_face_backend = {
+ CAIRO_FONT_TYPE_WIN32,
_cairo_win32_font_face_destroy,
_cairo_win32_font_face_scaled_font_create
};
diff --git a/src/cairo-win32-private.h b/src/cairo-win32-private.h
index a229147c7..fd6642413 100644
--- a/src/cairo-win32-private.h
+++ b/src/cairo-win32-private.h
@@ -62,19 +62,14 @@ typedef struct _cairo_win32_surface {
cairo_rectangle_t clip_rect;
- int set_clip;
HRGN saved_clip;
+ cairo_rectangle_t extents;
} cairo_win32_surface_t;
cairo_status_t
_cairo_win32_print_gdi_error (const char *context);
-cairo_surface_t *
-_cairo_win32_surface_create_dib (cairo_format_t format,
- int width,
- int height);
-
cairo_bool_t
_cairo_surface_is_win32 (cairo_surface_t *surface);
diff --git a/src/cairo-win32-surface.c b/src/cairo-win32-surface.c
index b1811a134..310561a82 100644
--- a/src/cairo-win32-surface.c
+++ b/src/cairo-win32-surface.c
@@ -31,6 +31,8 @@
*
* Contributor(s):
* Owen Taylor <otaylor@redhat.com>
+ * Stuart Parmenter <stuart@mozilla.com>
+ * Vladimir Vukicevic <vladimir@pobox.com>
*/
#include <stdio.h>
@@ -274,9 +276,14 @@ _cairo_win32_surface_create_for_dc (HDC original_dc,
surface->clip_rect.width = width;
surface->clip_rect.height = height;
- surface->set_clip = 0;
- surface->saved_clip = NULL;
-
+ surface->saved_clip = CreateRectRgn (0, 0, 0, 0);
+ if (GetClipRgn (surface->dc, surface->saved_clip) == 0) {
+ DeleteObject(surface->saved_clip);
+ surface->saved_clip = NULL;
+ }
+
+ surface->extents = surface->clip_rect;
+
_cairo_surface_init (&surface->base, &cairo_win32_surface_backend);
return (cairo_surface_t *)surface;
@@ -311,27 +318,6 @@ _cairo_win32_surface_create_similar (void *abstract_src,
return _cairo_win32_surface_create_for_dc (src->dc, format, width, height);
}
-/**
- * _cairo_win32_surface_create_dib:
- * @format: format of pixels in the surface to create
- * @width: width of the surface, in pixels
- * @height: height of the surface, in pixels
- *
- * Creates a device-independent-bitmap surface not associated with
- * any particular existing surface or device context. The created
- * bitmap will be unititialized.
- *
- * Return value: the newly created surface, or %NULL if it couldn't
- * be created (probably because of lack of memory)
- **/
-cairo_surface_t *
-_cairo_win32_surface_create_dib (cairo_format_t format,
- int width,
- int height)
-{
- return _cairo_win32_surface_create_for_dc (NULL, format, width, height);
-}
-
static cairo_status_t
_cairo_win32_surface_finish (void *abstract_surface)
{
@@ -340,9 +326,8 @@ _cairo_win32_surface_finish (void *abstract_surface)
if (surface->image)
cairo_surface_destroy (surface->image);
- if (surface->saved_clip) {
+ if (surface->saved_clip)
DeleteObject (surface->saved_clip);
- }
/* If we created the Bitmap and DC, destroy them */
if (surface->bitmap) {
@@ -379,8 +364,18 @@ _cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface,
width, height,
surface->dc,
x, y,
- SRCCOPY))
- goto FAIL;
+ SRCCOPY)) {
+ /* If we fail to BitBlt here, most likely the source is a printer.
+ * You can't reliably get bits from a printer DC, so just fill in
+ * the surface as white (common case for printing).
+ */
+
+ RECT r;
+ r.left = r.top = 0;
+ r.right = width;
+ r.bottom = height;
+ FillRect(local->dc, &r, (HBRUSH)GetStockObject(WHITE_BRUSH));
+ }
*local_out = local;
@@ -403,7 +398,7 @@ _cairo_win32_surface_acquire_source_image (void *abstract_sur
cairo_win32_surface_t *surface = abstract_surface;
cairo_win32_surface_t *local = NULL;
cairo_status_t status;
-
+
if (surface->image) {
*image_out = (cairo_image_surface_t *)surface->image;
*image_extra = NULL;
@@ -446,7 +441,7 @@ _cairo_win32_surface_acquire_dest_image (void *abstract_surfa
cairo_status_t status;
RECT clip_box;
int x1, y1, x2, y2;
-
+
if (surface->image) {
image_rect->x = 0;
image_rect->y = 0;
@@ -461,12 +456,12 @@ _cairo_win32_surface_acquire_dest_image (void *abstract_surfa
if (GetClipBox (surface->dc, &clip_box) == ERROR)
return _cairo_win32_print_gdi_error ("_cairo_win3_surface_acquire_dest_image");
-
+
x1 = clip_box.left;
x2 = clip_box.right;
y1 = clip_box.top;
y2 = clip_box.bottom;
-
+
if (interest_rect->x > x1)
x1 = interest_rect->x;
if (interest_rect->y > y1)
@@ -595,6 +590,8 @@ _composite_alpha_blend (cairo_win32_surface_t *dst,
if (alpha_blend == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
+ if (GetDeviceCaps(dst->dc, SHADEBLENDCAPS) == SB_NONE)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
blend_function.BlendOp = AC_SRC_OVER;
blend_function.BlendFlags = 0;
@@ -634,7 +631,7 @@ _cairo_win32_surface_composite (cairo_operator_t op,
int integer_transform;
int itx, ity;
- if (pattern->type != CAIRO_PATTERN_SURFACE ||
+ if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE ||
pattern->extend != CAIRO_EXTEND_NONE)
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -642,7 +639,7 @@ _cairo_win32_surface_composite (cairo_operator_t op,
/* FIXME: When we fully support RENDER style 4-channel
* masks we need to check r/g/b != 1.0.
*/
- if (mask_pattern->type != CAIRO_PATTERN_SOLID)
+ if (mask_pattern->type != CAIRO_PATTERN_TYPE_SOLID)
return CAIRO_INT_STATUS_UNSUPPORTED;
alpha = ((cairo_solid_pattern_t *)mask_pattern)->color.alpha_short >> 8;
@@ -660,6 +657,33 @@ _cairo_win32_surface_composite (cairo_operator_t op,
if (!integer_transform)
return CAIRO_INT_STATUS_UNSUPPORTED;
+ /* Fix up src coordinates; the src coords and size must be within the
+ * bounds of the source surface.
+ * XXX the region not covered should be appropriately rendered!
+ * - for OVER/SOURCE with RGB24 source -> opaque black
+ * - for SOURCE with ARGB32 source -> 100% transparent black
+ */
+ src_x += itx;
+ src_y += ity;
+
+ if (src_x < 0) {
+ width += src_x;
+ dst_x -= src_x;
+ src_x = 0;
+ }
+
+ if (src_y < 0) {
+ height += src_y;
+ dst_y -= src_y;
+ src_y = 0;
+ }
+
+ if (src_x + width > src->extents.width)
+ width = src->extents.width - src_x;
+
+ if (src_y + height > src->extents.height)
+ height = src->extents.height - src_y;
+
if (alpha == 255 &&
src->format == dst->format &&
(op == CAIRO_OPERATOR_SOURCE ||
@@ -669,7 +693,7 @@ _cairo_win32_surface_composite (cairo_operator_t op,
dst_x, dst_y,
width, height,
src->dc,
- src_x + itx, src_y + ity,
+ src_x, src_y,
SRCCOPY))
return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite");
@@ -681,7 +705,7 @@ _cairo_win32_surface_composite (cairo_operator_t op,
op == CAIRO_OPERATOR_OVER) {
return _composite_alpha_blend (dst, src, alpha,
- src_x + itx, src_y + ity,
+ src_x, src_y,
dst_x, dst_y, width, height);
}
@@ -855,19 +879,9 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
if (region == NULL) {
/* Clear any clip set by cairo, return to the original */
-
- if (surface->set_clip) {
- if (SelectClipRgn (surface->dc, surface->saved_clip) == ERROR)
- return _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
-
- if (surface->saved_clip) {
- DeleteObject (surface->saved_clip);
- surface->saved_clip = NULL;
- }
+ if (SelectClipRgn (surface->dc, surface->saved_clip) == ERROR)
+ return _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region (reset)");
- surface->set_clip = 0;
- }
-
return CAIRO_STATUS_SUCCESS;
} else {
@@ -910,36 +924,16 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
if (!gdi_region)
return CAIRO_STATUS_NO_MEMORY;
- if (surface->set_clip) {
- /* Combine the new region with the original clip */
-
- if (surface->saved_clip) {
- if (CombineRgn (gdi_region, gdi_region, surface->saved_clip, RGN_AND) == ERROR)
- goto FAIL;
- }
+ /* Combine the new region with the original clip */
- if (SelectClipRgn (surface->dc, gdi_region) == ERROR)
+ if (surface->saved_clip) {
+ if (CombineRgn (gdi_region, gdi_region, surface->saved_clip, RGN_AND) == ERROR)
goto FAIL;
-
- } else {
- /* Save the the current region */
-
- surface->saved_clip = CreateRectRgn (0, 0, 0, 0);
- if (!surface->saved_clip) {
- goto FAIL; }
-
- /* This function has no error return! */
- if (GetClipRgn (surface->dc, surface->saved_clip) == 0) { /* No clip */
- DeleteObject (surface->saved_clip);
- surface->saved_clip = NULL;
- }
-
- if (ExtSelectClipRgn (surface->dc, gdi_region, RGN_AND) == ERROR)
- goto FAIL;
-
- surface->set_clip = 1;
}
+ if (SelectClipRgn (surface->dc, gdi_region) == ERROR)
+ goto FAIL;
+
DeleteObject (gdi_region);
return CAIRO_STATUS_SUCCESS;
@@ -955,15 +949,8 @@ _cairo_win32_surface_get_extents (void *abstract_surface,
cairo_rectangle_t *rectangle)
{
cairo_win32_surface_t *surface = abstract_surface;
- RECT clip_box;
-
- if (GetClipBox (surface->dc, &clip_box) == ERROR)
- return _cairo_win32_print_gdi_error ("_cairo_win3_surface_acquire_dest_image");
- rectangle->x = clip_box.left;
- rectangle->y = clip_box.top;
- rectangle->width = clip_box.right - clip_box.left;
- rectangle->height = clip_box.bottom - clip_box.top;
+ *rectangle = surface->extents;
return CAIRO_STATUS_SUCCESS;
}
@@ -974,11 +961,25 @@ _cairo_win32_surface_flush (void *abstract_surface)
return _cairo_surface_reset_clip (abstract_surface);
}
+/**
+ * cairo_win32_surface_create:
+ * @hdc: the DC to create a surface for
+ *
+ * Creates a cairo surface that targets the given DC. The DC will be
+ * queried for its initial clip extents, and this will be used as the
+ * size of the cairo surface. Also, if the DC is a raster DC, it will
+ * be queried for its pixel format and the cairo surface format will
+ * be set appropriately.
+ *
+ * Return value: the newly created surface
+ **/
cairo_surface_t *
cairo_win32_surface_create (HDC hdc)
{
cairo_win32_surface_t *surface;
RECT rect;
+ int depth;
+ cairo_format_t format;
/* Try to figure out the drawing bounds for the Device context
*/
@@ -988,7 +989,28 @@ cairo_win32_surface_create (HDC hdc)
_cairo_error (CAIRO_STATUS_NO_MEMORY);
return &_cairo_surface_nil;
}
-
+
+ if (GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASDISPLAY) {
+ depth = GetDeviceCaps(hdc, BITSPIXEL);
+ if (depth == 32)
+ format = CAIRO_FORMAT_ARGB32;
+ else if (depth == 24)
+ format = CAIRO_FORMAT_RGB24;
+ else if (depth == 16)
+ format = CAIRO_FORMAT_RGB24;
+ else if (depth == 8)
+ format = CAIRO_FORMAT_A8;
+ else if (depth == 1)
+ format = CAIRO_FORMAT_A1;
+ else {
+ _cairo_win32_print_gdi_error("cairo_win32_surface_create(bad BITSPIXEL)");
+ _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ return &_cairo_surface_nil;
+ }
+ } else {
+ format = CAIRO_FORMAT_RGB24;
+ }
+
surface = malloc (sizeof (cairo_win32_surface_t));
if (surface == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY);
@@ -996,7 +1018,7 @@ cairo_win32_surface_create (HDC hdc)
}
surface->image = NULL;
- surface->format = CAIRO_FORMAT_RGB24;
+ surface->format = format;
surface->dc = hdc;
surface->bitmap = NULL;
@@ -1007,8 +1029,19 @@ cairo_win32_surface_create (HDC hdc)
surface->clip_rect.width = rect.right - rect.left;
surface->clip_rect.height = rect.bottom - rect.top;
- surface->set_clip = 0;
- surface->saved_clip = NULL;
+ if (surface->clip_rect.width == 0 ||
+ surface->clip_rect.height == 0)
+ {
+ surface->saved_clip = NULL;
+ } else {
+ surface->saved_clip = CreateRectRgn (0, 0, 0, 0);
+ if (GetClipRgn (hdc, surface->saved_clip) == 0) {
+ DeleteObject(surface->saved_clip);
+ surface->saved_clip = NULL;
+ }
+ }
+
+ surface->extents = surface->clip_rect;
_cairo_surface_init (&surface->base, &cairo_win32_surface_backend);
@@ -1016,6 +1049,28 @@ cairo_win32_surface_create (HDC hdc)
}
/**
+ * cairo_win32_surface_create_with_dib:
+ * @format: format of pixels in the surface to create
+ * @width: width of the surface, in pixels
+ * @height: height of the surface, in pixels
+ *
+ * Creates a device-independent-bitmap surface not associated with
+ * any particular existing surface or device context. The created
+ * bitmap will be unititialized.
+ *
+ * Return value: the newly created surface
+ *
+ **/
+cairo_surface_t *
+cairo_win32_surface_create_with_dib (cairo_format_t format,
+ int width,
+ int height)
+{
+ return _cairo_win32_surface_create_for_dc (NULL, format, width, height);
+}
+
+
+/**
* _cairo_surface_is_win32:
* @surface: a #cairo_surface_t
*
@@ -1029,7 +1084,33 @@ _cairo_surface_is_win32 (cairo_surface_t *surface)
return surface->backend == &cairo_win32_surface_backend;
}
+/**
+ * cairo_win32_surface_get_dc
+ * @surface: a #cairo_surface_t
+ *
+ * Returns the HDC associated with this surface, or NULL if none.
+ * Also returns NULL if the surface is not a win32 surface.
+ *
+ * Return value: HDC or NULL if no HDC available.
+ **/
+HDC
+cairo_win32_surface_get_dc (cairo_surface_t *surface)
+{
+ cairo_win32_surface_t *winsurf;
+
+ if (surface == NULL)
+ return NULL;
+
+ if (!_cairo_surface_is_win32(surface))
+ return NULL;
+
+ winsurf = (cairo_win32_surface_t *) surface;
+
+ return winsurf->dc;
+}
+
static const cairo_surface_backend_t cairo_win32_surface_backend = {
+ CAIRO_SURFACE_TYPE_WIN32,
_cairo_win32_surface_create_similar,
_cairo_win32_surface_finish,
_cairo_win32_surface_acquire_source_image,
diff --git a/src/cairo-win32.h b/src/cairo-win32.h
index 8d43bb74f..6ba37dec1 100644
--- a/src/cairo-win32.h
+++ b/src/cairo-win32.h
@@ -47,6 +47,14 @@ CAIRO_BEGIN_DECLS
cairo_public cairo_surface_t *
cairo_win32_surface_create (HDC hdc);
+cairo_public cairo_surface_t *
+cairo_win32_surface_create_with_dib (cairo_format_t format,
+ int width,
+ int height);
+
+cairo_public HDC
+cairo_win32_surface_get_dc (cairo_surface_t *surface);
+
cairo_public cairo_font_face_t *
cairo_win32_font_face_create_for_logfontw (LOGFONTW *logfont);
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index faa207c0d..78eafc0fa 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -1025,6 +1025,7 @@ _cairo_xcb_surface_get_extents (void *abstract_surface,
}
static const cairo_surface_backend_t cairo_xcb_surface_backend = {
+ CAIRO_SURFACE_TYPE_XCB,
_cairo_xcb_surface_create_similar,
_cairo_xcb_surface_finish,
_cairo_xcb_surface_acquire_source_image,
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 38c7c76b6..0f195bf9b 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -41,6 +41,7 @@
#include "cairo-xlib-test.h"
#include "cairo-xlib-private.h"
#include <X11/extensions/Xrender.h>
+#include <X11/extensions/renderproto.h>
/* Xlib doesn't define a typedef, so define one ourselves */
typedef int (*cairo_xlib_error_func_t) (Display *display,
@@ -1047,7 +1048,7 @@ _categorize_composite_operation (cairo_xlib_surface_t *dst,
if (!dst->buggy_repeat)
return DO_RENDER;
- if (src_pattern->type == CAIRO_PATTERN_SURFACE)
+ if (src_pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
{
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *)src_pattern;
@@ -1675,6 +1676,7 @@ _cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font);
static const cairo_surface_backend_t cairo_xlib_surface_backend = {
+ CAIRO_SURFACE_TYPE_XLIB,
_cairo_xlib_surface_create_similar,
_cairo_xlib_surface_finish,
_cairo_xlib_surface_acquire_source_image,
@@ -2403,6 +2405,8 @@ _cairo_xlib_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
cairo_int_status_t status;
cairo_xlib_surface_t *self = abstract_surface;
cairo_xlib_surface_t *src;
+ const cairo_glyph_t *glyphs_chunk;
+ int glyphs_remaining, chunk_size, max_chunk_size;
composite_operation_t operation;
cairo_scaled_glyph_t *scaled_glyph;
cairo_xlib_surface_font_private_t *font_private;
@@ -2457,23 +2461,41 @@ _cairo_xlib_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
}
_cairo_xlib_surface_ensure_dst_picture (self);
- /* Call the appropriate sub-function. */
+ max_chunk_size = XMaxRequestSize (self->dpy);
if (max_index < 256)
- status = _cairo_xlib_surface_old_show_glyphs8 (scaled_font, op, src, self,
- source_x + attributes.x_offset - dest_x,
- source_y + attributes.y_offset - dest_y,
- glyphs, num_glyphs);
+ max_chunk_size -= sz_xRenderCompositeGlyphs8Req;
else if (max_index < 65536)
- status = _cairo_xlib_surface_old_show_glyphs16 (scaled_font, op, src, self,
- source_x + attributes.x_offset - dest_x,
- source_y + attributes.y_offset - dest_y,
- glyphs, num_glyphs);
- else
- status = _cairo_xlib_surface_old_show_glyphs32 (scaled_font, op, src, self,
- source_x + attributes.x_offset - dest_x,
- source_y + attributes.y_offset - dest_y,
- glyphs, num_glyphs);
+ max_chunk_size -= sz_xRenderCompositeGlyphs16Req;
+ else
+ max_chunk_size -= sz_xRenderCompositeGlyphs32Req;
+ max_chunk_size /= sz_xGlyphElt;
+
+ for (glyphs_remaining = num_glyphs, glyphs_chunk = glyphs;
+ glyphs_remaining;
+ glyphs_remaining -= chunk_size, glyphs_chunk += chunk_size)
+ {
+ chunk_size = MIN (glyphs_remaining, max_chunk_size);
+
+ /* Call the appropriate sub-function. */
+ if (max_index < 256)
+ status = _cairo_xlib_surface_old_show_glyphs8 (scaled_font, op, src, self,
+ source_x + attributes.x_offset - dest_x,
+ source_y + attributes.y_offset - dest_y,
+ glyphs_chunk, chunk_size);
+ else if (max_index < 65536)
+ status = _cairo_xlib_surface_old_show_glyphs16 (scaled_font, op, src, self,
+ source_x + attributes.x_offset - dest_x,
+ source_y + attributes.y_offset - dest_y,
+ glyphs_chunk, chunk_size);
+ else
+ status = _cairo_xlib_surface_old_show_glyphs32 (scaled_font, op, src, self,
+ source_x + attributes.x_offset - dest_x,
+ source_y + attributes.y_offset - dest_y,
+ glyphs_chunk, chunk_size);
+ if (status != CAIRO_STATUS_SUCCESS)
+ break;
+ }
if (status == CAIRO_STATUS_SUCCESS && !_cairo_operator_bounded_by_mask (op)) {
cairo_rectangle_t extents;
diff --git a/src/cairo.c b/src/cairo.c
index 3319e2b45..0f35fa674 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -220,6 +220,9 @@ cairo_create (cairo_surface_t *target)
cairo_t *
cairo_reference (cairo_t *cr)
{
+ if (cr == NULL)
+ return NULL;
+
if (cr->ref_count == (unsigned int)-1)
return cr;
@@ -241,6 +244,9 @@ cairo_reference (cairo_t *cr)
void
cairo_destroy (cairo_t *cr)
{
+ if (cr == NULL)
+ return;
+
if (cr->ref_count == (unsigned int)-1)
return;
@@ -2027,6 +2033,46 @@ cairo_get_font_options (cairo_t *cr,
}
/**
+ * cairo_set_scaled_font:
+ * @cr: a #cairo_t
+ * @scaled_font: a #cairo_scaled_font_t
+ *
+ * Replaces the current font face, font matrix, and font options in
+ * the #cairo_t with those of the #cairo_scaled_font_t. Except for
+ * some translation, the current CTM of the #cairo_t should be the
+ * same as that of the #cairo_scaled_font_t, which can be accessed
+ * using cairo_scaled_font_get_ctm().
+ **/
+void
+cairo_set_scaled_font (cairo_t *cr,
+ const cairo_scaled_font_t *scaled_font)
+{
+ if (cr->status)
+ return;
+
+ cr->status = scaled_font->status;
+ if (cr->status)
+ goto BAIL;
+
+ cr->status = _cairo_gstate_set_font_face (cr->gstate, scaled_font->font_face);
+ if (cr->status)
+ goto BAIL;
+
+ cr->status = _cairo_gstate_set_font_matrix (cr->gstate, &scaled_font->font_matrix);
+ if (cr->status)
+ goto BAIL;
+
+ cr->status = _cairo_gstate_set_font_options (cr->gstate, &scaled_font->options);
+ if (cr->status)
+ goto BAIL;
+
+ return;
+
+BAIL:
+ _cairo_set_error (cr, cr->status);
+}
+
+/**
* cairo_text_extents:
* @cr: a #cairo_t
* @utf8: a string of text, encoded in UTF-8
@@ -2203,6 +2249,9 @@ cairo_show_glyphs (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs)
if (cr->status)
return;
+ if (num_glyphs == 0)
+ return;
+
cr->status = _cairo_gstate_show_glyphs (cr->gstate, glyphs, num_glyphs);
if (cr->status)
_cairo_set_error (cr, cr->status);
diff --git a/src/cairo.h b/src/cairo.h
index 6dd274267..db9354074 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -856,6 +856,10 @@ cairo_get_font_options (cairo_t *cr,
cairo_font_options_t *options);
cairo_public void
+cairo_set_scaled_font (cairo_t *cr,
+ const cairo_scaled_font_t *scaled_font);
+
+cairo_public void
cairo_show_text (cairo_t *cr, const char *utf8);
cairo_public void
@@ -899,6 +903,47 @@ cairo_font_face_destroy (cairo_font_face_t *font_face);
cairo_public cairo_status_t
cairo_font_face_status (cairo_font_face_t *font_face);
+/**
+ * cairo_font_type_t
+ * @CAIRO_SCALED_FONT_TYPE_FT: The font is of type ft
+ * @CAIRO_SCALED_FONT_TYPE_WIN32: The font is of type win32
+ * @CAIRO_SCALED_FONT_TYPE_ATSUI: The font is of type atsui
+ *
+ * @cairo_font_type_t is used to describe the type of a given font
+ * face or scaled font. The font types are also known as "font
+ * backends" within cairo.
+ *
+ * The type of a font face is determined by the function used to
+ * create it, which will generally be of the form
+ * cairo_<type>_font_face_create. The font face type can be queried
+ * with cairo_font_face_get_type()
+ *
+ * The various cairo_font_face functions can be used with a font face
+ * of any type.
+ *
+ * The type of a scaled font is determined by the type of the font
+ * face passed to cairo_scaled_font_create. The scaled font type can
+ * be queried with cairo_scaled_font_get_type()
+ *
+ * The various cairo_scaled_font functions can be used with scaled
+ * fonts of any type, but some font backends also provide
+ * type-specific functions that must only be called with a scaled font
+ * of the appropriate type. These functions have names that begin with
+ * cairo_<type>_scaled_font such as cairo_ft_scaled_font_lock_face.
+ *
+ * The behavior of calling a type-specific function with a scaled font
+ * of the wrong type is undefined.
+ */
+typedef enum _cairo_font_type {
+ CAIRO_FONT_TYPE_TOY,
+ CAIRO_FONT_TYPE_FT,
+ CAIRO_FONT_TYPE_WIN32,
+ CAIRO_FONT_TYPE_ATSUI
+} cairo_font_type_t;
+
+cairo_public cairo_font_type_t
+cairo_font_face_get_type (cairo_font_face_t *font_face);
+
cairo_public void *
cairo_font_face_get_user_data (cairo_font_face_t *font_face,
const cairo_user_data_key_t *key);
@@ -926,6 +971,9 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font);
cairo_public cairo_status_t
cairo_scaled_font_status (cairo_scaled_font_t *scaled_font);
+cairo_public cairo_font_type_t
+cairo_scaled_font_get_type (cairo_scaled_font_t *scaled_font);
+
cairo_public void
cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font,
cairo_font_extents_t *extents);
@@ -1151,13 +1199,63 @@ cairo_public cairo_surface_t *
cairo_surface_reference (cairo_surface_t *surface);
cairo_public void
+cairo_surface_finish (cairo_surface_t *surface);
+
+cairo_public void
cairo_surface_destroy (cairo_surface_t *surface);
cairo_public cairo_status_t
cairo_surface_status (cairo_surface_t *surface);
-cairo_public void
-cairo_surface_finish (cairo_surface_t *surface);
+/**
+ * cairo_surface_type_t
+ * @CAIRO_SURFACE_TYPE_IMAGE: The surface is of type image
+ * @CAIRO_SURFACE_TYPE_PDF: The surface is of type pdf
+ * @CAIRO_SURFACE_TYPE_PS: The surface is of type ps
+ * @CAIRO_SURFACE_TYPE_XLIB: The surface is of type xlib
+ * @CAIRO_SURFACE_TYPE_XCB: The surface is of type xcb
+ * @CAIRO_SURFACE_TYPE_GLITZ: The surface is of type glitz
+ * @CAIRO_SURFACE_TYPE_QUARTZ: The surface is of type quartz
+ * @CAIRO_SURFACE_TYPE_WIN32: The surface is of type win32
+ * @CAIRO_SURFACE_TYPE_BEOS: The surface is of type beos
+ * @CAIRO_SURFACE_TYPE_DIRECTFB: The surface is of type directfb
+ * @CAIRO_SURFACE_TYPE_SVG: The surface is of type svg
+ *
+ * @cairo_surface_type_t is used to describe the type of a given
+ * surface. The surface types are also known as "backends" or "surface
+ * backends" within cairo.
+ *
+ * The type of a surface is determined by the function used to create
+ * it, which will generally be of the form cairo_<type>_surface_create,
+ * (though see cairo_surface_create_similar as well).
+ *
+ * The surface type can be queried with cairo_surface_get_type()
+ *
+ * The various cairo_surface functions can be used with surfaces of
+ * any type, but some backends also provide type-specific functions
+ * that must only be called with a surface of the appropriate
+ * type. These functions have names that begin with
+ * cairo_<type>_surface such as cairo_image_surface_get_width().
+ *
+ * The behavior of calling a type-specific function with a surface of
+ * the wrong type is undefined.
+ */
+typedef enum _cairo_surface_type {
+ CAIRO_SURFACE_TYPE_IMAGE,
+ CAIRO_SURFACE_TYPE_PDF,
+ CAIRO_SURFACE_TYPE_PS,
+ CAIRO_SURFACE_TYPE_XLIB,
+ CAIRO_SURFACE_TYPE_XCB,
+ CAIRO_SURFACE_TYPE_GLITZ,
+ CAIRO_SURFACE_TYPE_QUARTZ,
+ CAIRO_SURFACE_TYPE_WIN32,
+ CAIRO_SURFACE_TYPE_BEOS,
+ CAIRO_SURFACE_TYPE_DIRECTFB,
+ CAIRO_SURFACE_TYPE_SVG
+} cairo_surface_type_t;
+
+cairo_public cairo_surface_type_t
+cairo_surface_get_type (cairo_surface_t *surface);
#if CAIRO_HAS_PNG_FUNCTIONS
@@ -1293,6 +1391,43 @@ cairo_pattern_destroy (cairo_pattern_t *pattern);
cairo_public cairo_status_t
cairo_pattern_status (cairo_pattern_t *pattern);
+/**
+ * cairo_pattern_type_t
+
+ * @CAIRO_PATTERN_TYPE_SOLID: The pattern is a solid (uniform)
+ * color. It may be opaque or translucent.
+ * @CAIRO_PATTERN_TYPE_SURFACE: The pattern is a based on a surface (an image).
+ * @CAIRO_PATTERN_TYPE_LINEAR: The pattern is a linear gradient.
+ * @CAIRO_PATTERN_TYPE_RADIAL: The pattern is a radial gradient.
+ *
+ * @cairo_pattern_type_t us used to describe the type of a given pattern.
+ *
+ * The type of a pattern is determined by the function used to create
+ * it. The cairo_pattern_create_rgb() and cairo_pattern_create_rgba()
+ * functions create SOLID patterns. The remaining
+ * cairo_pattern_create functions map to pattern types in obvious
+ * ways.
+ *
+ * The pattern type can be queried with cairo_pattern_get_type()
+ *
+ * Most cairo_pattern functions can be called with a pattern of any
+ * type, (though trying to change the extend or filter for a solid
+ * pattern will have no effect). A notable exception is
+ * cairo_pattern_add_color_stop_rgb() and
+ * cairo_pattern_add_color_stop_rgba() which must only be called with
+ * gradient patterns (either LINEAR or RADIAL). Otherwise the pattern
+ * will be shutdown and put into an error state.
+ */
+typedef enum _cairo_pattern_type {
+ CAIRO_PATTERN_TYPE_SOLID,
+ CAIRO_PATTERN_TYPE_SURFACE,
+ CAIRO_PATTERN_TYPE_LINEAR,
+ CAIRO_PATTERN_TYPE_RADIAL
+} cairo_pattern_type_t;
+
+cairo_public cairo_pattern_type_t
+cairo_pattern_get_type (cairo_pattern_t *pattern);
+
cairo_public void
cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern,
double offset,
diff --git a/src/cairoint.h b/src/cairoint.h
index d51b994cf..65b482ff9 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -184,6 +184,10 @@ cairo_private void _cairo_beos_unlock(void*);
#define TRUE 1
#endif
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
#define ASSERT_NOT_REACHED \
do { \
static const int NOT_REACHED = 0; \
@@ -256,6 +260,15 @@ typedef enum cairo_int_status {
CAIRO_INT_STATUS_CACHE_EMPTY
} cairo_int_status_t;
+typedef enum cairo_internal_surface_type {
+ CAIRO_INTERNAL_SURFACE_TYPE_META = 0x1000,
+ CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED,
+ CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
+ CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
+ CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+ CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED
+} cairo_internal_surface_type_t;
+
typedef enum cairo_direction {
CAIRO_DIRECTION_FORWARD,
CAIRO_DIRECTION_REVERSE
@@ -464,6 +477,7 @@ struct _cairo_scaled_font {
};
struct _cairo_font_face {
+ /* hash_entry must be first */
cairo_hash_entry_t hash_entry;
cairo_status_t status;
int ref_count;
@@ -508,6 +522,8 @@ typedef enum _cairo_scaled_glyph_info {
} cairo_scaled_glyph_info_t;
struct _cairo_scaled_font_backend {
+ cairo_font_type_t type;
+
cairo_status_t
(*create_toy) (cairo_toy_font_face_t *toy_face,
const cairo_matrix_t *font_matrix,
@@ -555,6 +571,8 @@ struct _cairo_scaled_font_backend {
};
struct _cairo_font_face_backend {
+ cairo_font_type_t type;
+
/* The destroy() function is allowed to resurrect the font face
* by re-referencing. This is needed for the FreeType backend.
*/
@@ -599,6 +617,8 @@ typedef struct _cairo_stroke_style {
} cairo_stroke_style_t;
struct _cairo_surface_backend {
+ cairo_surface_type_t type;
+
cairo_surface_t *
(*create_similar) (void *surface,
cairo_content_t content,
@@ -829,6 +849,11 @@ typedef struct _cairo_format_masks {
struct _cairo_surface {
const cairo_surface_backend_t *backend;
+ /* We allow surfaces to override the backend->type by shoving something
+ * else into surface->type. This is for "wrapper" surfaces that want to
+ * hide their internal type from the user-level API. */
+ cairo_surface_type_t type;
+
unsigned int ref_count;
cairo_status_t status;
cairo_bool_t finished;
@@ -909,13 +934,6 @@ typedef enum {
#define CAIRO_EXTEND_GRADIENT_DEFAULT CAIRO_EXTEND_PAD
#define CAIRO_FILTER_DEFAULT CAIRO_FILTER_BEST
-typedef enum {
- CAIRO_PATTERN_SOLID,
- CAIRO_PATTERN_SURFACE,
- CAIRO_PATTERN_LINEAR,
- CAIRO_PATTERN_RADIAL
-} cairo_pattern_type_t;
-
struct _cairo_pattern {
cairo_pattern_type_t type;
unsigned int ref_count;
@@ -1372,6 +1390,13 @@ _cairo_font_options_init_copy (cairo_font_options_t *options,
cairo_private cairo_status_t
_cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices);
+/* cairo_operator.c */
+cairo_private cairo_bool_t
+_cairo_operator_always_opaque (cairo_operator_t op);
+
+cairo_private cairo_bool_t
+_cairo_operator_always_translucent (cairo_operator_t op);
+
/* cairo_path.c */
cairo_private void
_cairo_path_fixed_init (cairo_path_fixed_t *path);
@@ -1536,7 +1561,7 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
cairo_private cairo_status_t
_cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
- cairo_glyph_t *glyphs,
+ const cairo_glyph_t *glyphs,
int num_glyphs,
cairo_path_fixed_t *path);
@@ -1804,6 +1829,9 @@ _cairo_surface_composite_shape_fixup_unbounded (cairo_surface_t *dst,
unsigned int width,
unsigned int height);
+cairo_private cairo_bool_t
+_cairo_surface_is_opaque (const cairo_surface_t *surface);
+
/* cairo_image_surface.c */
#define CAIRO_FORMAT_VALID(format) ((format) >= CAIRO_FORMAT_ARGB32 && \
@@ -1847,6 +1875,19 @@ _cairo_image_surface_create_for_data_with_content (unsigned char *data,
cairo_private void
_cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface);
+/* XXX: It's a nasty kludge that this appears here. Backend functions
+ * like this should really be static. But we're doing this to work
+ * around some general defects in the backend clipping interfaces,
+ * (see some notes in test-paginated-surface.c).
+ *
+ * I want to fix the real defects, but it's "hard" as they touch many
+ * backends, so doing that will require synchronizing several backend
+ * maintainers.
+ */
+cairo_private cairo_int_status_t
+_cairo_image_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region);
+
cairo_private cairo_bool_t
_cairo_surface_is_image (const cairo_surface_t *surface);
@@ -2040,7 +2081,10 @@ _cairo_pattern_transform (cairo_pattern_t *pattern,
const cairo_matrix_t *ctm_inverse);
cairo_private cairo_bool_t
-_cairo_pattern_is_opaque_solid (cairo_pattern_t *pattern);
+_cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern);
+
+cairo_bool_t
+_cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern);
cairo_private cairo_int_status_t
_cairo_pattern_acquire_surface (cairo_pattern_t *pattern,
@@ -2110,14 +2154,37 @@ _cairo_utf8_to_utf16 (const unsigned char *str,
typedef struct _cairo_output_stream cairo_output_stream_t;
+extern const cairo_private cairo_output_stream_t cairo_output_stream_nil;
+
+/* We already have the following declared in cairo.h:
+
+typedef cairo_status_t (*cairo_write_func_t) (void *closure,
+ const unsigned char *data,
+ unsigned int length);
+*/
+typedef cairo_status_t (*cairo_close_func_t) (void *closure);
+
+
+/* This function never returns NULL. If an error occurs (NO_MEMORY)
+ * while trying to create the output stream this function returns a
+ * valid pointer to a nil output stream.
+ *
+ * Note that even with a nil surface, the close_func callback will be
+ * called by a call to _cairo_output_stream_close or
+ * _cairo_output_stream_destroy.
+ */
cairo_private cairo_output_stream_t *
_cairo_output_stream_create (cairo_write_func_t write_func,
+ cairo_close_func_t close_func,
void *closure);
cairo_private void
+_cairo_output_stream_close (cairo_output_stream_t *stream);
+
+cairo_private void
_cairo_output_stream_destroy (cairo_output_stream_t *stream);
-cairo_private cairo_status_t
+cairo_private void
_cairo_output_stream_write (cairo_output_stream_t *stream,
const void *data, size_t length);
@@ -2126,11 +2193,14 @@ _cairo_output_stream_write_hex_string (cairo_output_stream_t *stream,
const char *data,
size_t length);
-cairo_private cairo_status_t
+cairo_private unsigned char *
+_cairo_lzw_compress (unsigned char *data, unsigned long *data_size_in_out);
+
+cairo_private void
_cairo_output_stream_vprintf (cairo_output_stream_t *stream,
const char *fmt, va_list ap);
-cairo_private cairo_status_t
+cairo_private void
_cairo_output_stream_printf (cairo_output_stream_t *stream,
const char *fmt, ...) CAIRO_PRINTF_FORMAT(2, 3);
@@ -2140,8 +2210,30 @@ _cairo_output_stream_get_position (cairo_output_stream_t *status);
cairo_private cairo_status_t
_cairo_output_stream_get_status (cairo_output_stream_t *stream);
+/* This function never returns NULL. If an error occurs (NO_MEMORY or
+ * WRITE_ERROR) while trying to create the output stream this function
+ * returns a valid pointer to a nil output stream.
+ *
+ * NOTE: Even if a nil surface is returned, the caller should still
+ * call _cairo_output_stream_destroy (or _cairo_output_stream_close at
+ * least) in order to ensure that everything is properly cleaned up.
+ */
cairo_private cairo_output_stream_t *
-_cairo_output_stream_create_for_file (const char *filename);
+_cairo_output_stream_create_for_filename (const char *filename);
+
+/* This function never returns NULL. If an error occurs (NO_MEMORY or
+ * WRITE_ERROR) while trying to create the output stream this function
+ * returns a valid pointer to a nil output stream.
+ *
+ * The caller still "owns" file and is responsible for calling fclose
+ * on it when finished. The stream will not do this itself.
+ */
+cairo_private cairo_output_stream_t *
+_cairo_output_stream_create_for_file (FILE *file);
+
+/* cairo_base85_stream.c */
+cairo_output_stream_t *
+_cairo_base85_stream_create (cairo_output_stream_t *output);
cairo_private void
_cairo_error (cairo_status_t status);
@@ -2150,7 +2242,6 @@ cairo_private int
_cairo_dtostr (char *buffer, size_t size, double d);
/* Avoid unnecessary PLT entries. */
-
slim_hidden_proto(cairo_get_current_point)
slim_hidden_proto(cairo_fill_preserve)
slim_hidden_proto(cairo_clip_preserve)
diff --git a/src/test-fallback-surface.c b/src/test-fallback-surface.c
index fe0cc6fb5..cb8fd92a0 100644
--- a/src/test-fallback-surface.c
+++ b/src/test-fallback-surface.c
@@ -175,6 +175,7 @@ _test_fallback_surface_get_extents (void *abstract_surface,
}
const cairo_surface_backend_t test_fallback_surface_backend = {
+ CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
_test_fallback_surface_create_similar,
_test_fallback_surface_finish,
_test_fallback_surface_acquire_source_image,
diff --git a/src/test-meta-surface.c b/src/test-meta-surface.c
index bdabf31d3..6d36fcab2 100644
--- a/src/test-meta-surface.c
+++ b/src/test-meta-surface.c
@@ -296,6 +296,7 @@ _test_meta_surface_snapshot (void *abstract_other)
}
const cairo_surface_backend_t test_meta_surface_backend = {
+ CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
NULL, /* create_similar */
_test_meta_surface_finish,
_test_meta_surface_acquire_source_image,
diff --git a/src/test-paginated-surface.c b/src/test-paginated-surface.c
index 155f2773f..e4eb58a2d 100644
--- a/src/test-paginated-surface.c
+++ b/src/test-paginated-surface.c
@@ -51,6 +51,15 @@
#include "cairo-paginated-surface-private.h"
+typedef struct _test_paginated_surface {
+ cairo_surface_t base;
+ cairo_surface_t *target;
+ cairo_paginated_mode_t paginated_mode;
+} test_paginated_surface_t;
+
+static const cairo_surface_backend_t test_paginated_surface_backend;
+static const cairo_paginated_surface_backend_t test_paginated_surface_paginated_backend;
+
cairo_surface_t *
_test_paginated_surface_create_for_data (unsigned char *data,
cairo_content_t content,
@@ -58,11 +67,218 @@ _test_paginated_surface_create_for_data (unsigned char *data,
int height,
int stride)
{
+ cairo_status_t status;
cairo_surface_t *target;
+ test_paginated_surface_t *surface;
- target = _cairo_image_surface_create_for_data_with_content (data, content,
+ target = _cairo_image_surface_create_for_data_with_content (data, content,
width, height,
stride);
+ status = cairo_surface_status (target);
+ if (status) {
+ _cairo_error (status);
+ return (cairo_surface_t *) &_cairo_surface_nil;
+ }
+
+ surface = malloc (sizeof (test_paginated_surface_t));
+ if (surface == NULL) {
+ _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ return (cairo_surface_t *) &_cairo_surface_nil;
+ }
+
+ _cairo_surface_init (&surface->base, &test_paginated_surface_backend);
+
+ surface->target = target;
+
+ return _cairo_paginated_surface_create (&surface->base, content, width, height,
+ &test_paginated_surface_paginated_backend);
+}
+
+static cairo_int_status_t
+_test_paginated_surface_set_clip_region (void *abstract_surface,
+ pixman_region16_t *region)
+{
+ test_paginated_surface_t *surface = abstract_surface;
+
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ return CAIRO_STATUS_SUCCESS;
+
+ /* XXX: The whole surface backend clipping interface is a giant
+ * disaster right now. In particular, its uncleanness shows up
+ * when trying to implement one surface that wraps another one (as
+ * we are doing here).
+ *
+ * Here are two of the problems that show up:
+ *
+ * 1. The most critical piece of information in all this stuff,
+ * the "clip" isn't getting passed to the backend
+ * functions. Instead the generic surface layer is caching that as
+ * surface->clip. This is a problem for surfaces like this one
+ * that do wrapping. Our base surface will have the clip set, but
+ * our target's surface will not.
+ *
+ * 2. We're here in our backend's set_clip_region function, and we
+ * want to call into our target surface's set_clip_region.
+ * Generally, we would do this by calling an equivalent
+ * _cairo_surface function, but _cairo_surface_set_clip_region
+ * does not have the same signature/semantics, (it has the
+ * clip_serial stuff as well).
+ *
+ * We kludge around each of these by manually copying the clip
+ * object from our base surface into the target's base surface
+ * (yuck!) and by reaching directly into the image surface's
+ * set_clip_region instead of calling into the generic
+ * _cairo_surface_set_clip_region (double yuck!).
+ */
+
+ surface->target->clip = surface->base.clip;
+
+ return _cairo_image_surface_set_clip_region (surface->target, region);
+}
+
+static cairo_int_status_t
+_test_paginated_surface_get_extents (void *abstract_surface,
+ cairo_rectangle_t *rectangle)
+{
+ test_paginated_surface_t *surface = abstract_surface;
+
+ return _cairo_surface_get_extents (surface->target, rectangle);
+}
+
+static cairo_int_status_t
+_test_paginated_surface_paint (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source)
+{
+ test_paginated_surface_t *surface = abstract_surface;
+
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ return CAIRO_STATUS_SUCCESS;
+
+ return _cairo_surface_paint (surface->target, op, source);
+}
+
+static cairo_int_status_t
+_test_paginated_surface_mask (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source,
+ cairo_pattern_t *mask)
+{
+ test_paginated_surface_t *surface = abstract_surface;
- return _cairo_paginated_surface_create (target, content, width, height);
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ return CAIRO_STATUS_SUCCESS;
+
+ return _cairo_surface_mask (surface->target, op, source, mask);
+}
+
+static cairo_int_status_t
+_test_paginated_surface_stroke (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_stroke_style_t *style,
+ cairo_matrix_t *ctm,
+ cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ test_paginated_surface_t *surface = abstract_surface;
+
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ return CAIRO_STATUS_SUCCESS;
+
+ return _cairo_surface_stroke (surface->target, op, source,
+ path, style,
+ ctm, ctm_inverse,
+ tolerance, antialias);
+}
+
+static cairo_int_status_t
+_test_paginated_surface_fill (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias)
+{
+ test_paginated_surface_t *surface = abstract_surface;
+
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ return CAIRO_STATUS_SUCCESS;
+
+ return _cairo_surface_fill (surface->target, op, source,
+ path, fill_rule,
+ tolerance, antialias);
+}
+
+static cairo_int_status_t
+_test_paginated_surface_show_glyphs (void *abstract_surface,
+ cairo_operator_t op,
+ cairo_pattern_t *source,
+ const cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font)
+{
+ test_paginated_surface_t *surface = abstract_surface;
+
+ if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
+ return CAIRO_STATUS_SUCCESS;
+
+ return _cairo_surface_show_glyphs (surface->target, op, source,
+ glyphs, num_glyphs, scaled_font);
+}
+
+static void
+_test_paginated_surface_set_paginated_mode (void *abstract_surface,
+ cairo_paginated_mode_t mode)
+{
+ test_paginated_surface_t *surface = abstract_surface;
+
+ surface->paginated_mode = mode;
}
+
+static const cairo_surface_backend_t test_paginated_surface_backend = {
+ CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
+
+ /* Since we are a paginated user, we get to regard most of the
+ * surface backend interface as historical cruft and ignore it. */
+
+ NULL, /* create_similar */
+ NULL, /* finish */
+ NULL, /* acquire_source_image */
+ NULL, /* release_source_image */
+ NULL, /* acquire_dest_image */
+ NULL, /* release_dest_image */
+ NULL, /* clone_similar */
+ NULL, /* composite */
+ NULL, /* fill_rectangles */
+ NULL, /* composite_trapezoids */
+ NULL, /* copy_page */
+ NULL, /* show_page */
+ _test_paginated_surface_set_clip_region,
+ NULL, /* intersect_clip_path */
+ _test_paginated_surface_get_extents,
+ NULL, /* old_show_glyphs */
+ NULL, /* get_font_options */
+ NULL, /* flush */
+ NULL, /* mark_dirty_rectangle */
+ NULL, /* scaled_font_fini */
+ NULL, /* scaled_glyph_fini */
+
+ /* Here is the more "modern" section of the surface backend
+ * interface which is mostly just drawing functions */
+
+ _test_paginated_surface_paint,
+ _test_paginated_surface_mask,
+ _test_paginated_surface_stroke,
+ _test_paginated_surface_fill,
+ _test_paginated_surface_show_glyphs,
+ NULL /* snapshot */
+};
+
+static const cairo_paginated_surface_backend_t test_paginated_surface_paginated_backend = {
+ NULL, /* start_page */
+ _test_paginated_surface_set_paginated_mode
+};
diff --git a/test/.gitignore b/test/.gitignore
index 1a1212224..c124fc60b 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -19,11 +19,13 @@ create-from-png
create-from-png-stream
dash-caps-joins
dash-offset-negative
+dash-zero-length
extend-reflect
fill-and-stroke
fill-rule
filter-nearest-offset
ft-font-create-for-ft-face
+font-face-get-type
get-and-set
gradient-alpha
imagediff
@@ -44,6 +46,7 @@ operator-source
paint
paint-with-alpha
path-data
+pattern-get-type
pdf2png
png-flatten
svg2png
@@ -60,6 +63,7 @@ select-font-no-show-text
self-copy
self-intersecting
set-source
+show-glyphs-many
show-text-current-point
source-clip
source-surface-scale-paint
diff --git a/test/Makefile.am b/test/Makefile.am
index 0ea0624aa..044dc08c1 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,4 +1,4 @@
-# All test cases go here
+# Here are all the tests that are run unconditionally
TESTS = \
a8-mask \
caps-joins \
@@ -16,10 +16,12 @@ create-from-png \
create-from-png-stream \
dash-caps-joins \
dash-offset-negative \
+dash-zero-length \
extend-reflect \
fill-and-stroke \
fill-rule \
filter-nearest-offset \
+font-face-get-type \
get-and-set \
gradient-alpha \
leaky-polygon \
@@ -36,6 +38,7 @@ operator-source \
paint \
paint-with-alpha \
path-data \
+pattern-get-type \
pixman-rotate \
rectangle-rounding-error \
scale-source-surface-paint \
@@ -62,6 +65,8 @@ unbounded-operator \
user-data \
rel-path
+# Then we have a collection of tests that are only run if certain
+# features are compiled into cairo
if HAVE_PTHREAD
TESTS += pthread-show-text
endif
@@ -82,6 +87,23 @@ if CAIRO_HAS_MULTI_PAGE_SURFACES
TESTS += multi-page
endif
+# XXX: Here are some existing tests that are currently disabled for
+# one reason or another.
+#
+# show-glyphs-many - this stress test was exercising a particular bug
+# in the xlib surface code (exceeding the X11 protocol request
+# limit) when rendering several thousand glyphs at once. The
+# original xlib-surface bug is fixed now, but the test continues
+# to stress some other aspects of the test suite. For example,
+# when doing text as paths, the resuilting PostScript file is one
+# giant path that ghostscript has a particularly hard time
+# with. I'm disabling this test for now, since I don't care about
+# that performance problem in ghostscript. (But, there is a
+# similar performance problem when using cairo to rasterize the
+# equivalen giant path---from an SBG files say---so this might be
+# a useful kind of test to bring back again for performance (not
+# correctness) testing.
+
# All tests which have a reference image go here.
# I really don't like having to repeat this list. Anyone know a good
# way to avoid it? Can I use a wildcard here?
@@ -120,6 +142,8 @@ dash-caps-joins-rgb24-ref.png \
dash-offset-negative-ref.png \
dash-offset-negative-rgb24-ref.png \
dash-offset-negative-ps-rgb24-ref.png \
+dash-zero-length-ref.png \
+dash-zero-length-rgb24-ref.png \
extend-reflect-ref.png \
extend-reflect-rgb24-ref.png \
fill-and-stroke-ref.png \
@@ -299,9 +323,11 @@ create_from_png_LDADD = $(LDADDS)
create_from_png_stream_LDADD = $(LDADDS)
dash_caps_joins_LDADD = $(LDADDS)
dash_offset_negative_LDADD = $(LDADDS)
+dash_zero_length_LDADD = $(LDADDS)
extend_reflect_LDADD = $(LDADDS)
fill_and_stroke_LDADD = $(LDADDS)
fill_rule_LDADD = $(LDADDS)
+font_face_get_type_LDADD = $(LDADDS)
filter_nearest_offset_LDADD = $(LDADDS)
ft_font_create_for_ft_face_LDADD = $(LDADDS)
get_and_set_LDADD = $(LDADDS)
@@ -321,6 +347,7 @@ operator_source_LDADD = $(LDADDS)
paint_LDADD = $(LDADDS)
paint_with_alpha_LDADD = $(LDADDS)
path_data_LDADD = $(LDADDS)
+pattern_get_type_LDADD = $(LDADDS)
svg_surface_LDADD = $(LDADDS)
svg_clip_LDADD = $(LDADDS)
pixman_rotate_LDADD = $(LDADDS)
diff --git a/test/cairo-test.c b/test/cairo-test.c
index 557ccb6fd..fce38fe48 100644
--- a/test/cairo-test.c
+++ b/test/cairo-test.c
@@ -47,6 +47,21 @@
#include "write-png.h"
#include "xmalloc.h"
+/* This is copied from cairoint.h. That makes it painful to keep in
+ * sync, but the slim stuff makes cairoint.h "hard" to include when
+ * not actually building the cairo library itself. Fortunately, since
+ * we're checking all these values, we do have a safeguard for keeping
+ * them in sync.
+ */
+typedef enum cairo_internal_surface_type {
+ CAIRO_INTERNAL_SURFACE_TYPE_META = 0x1000,
+ CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED,
+ CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
+ CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
+ CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+ CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED
+} cairo_internal_surface_type_t;
+
#ifdef _MSC_VER
#define vsnprintf _vsnprintf
#define access _access
@@ -163,11 +178,12 @@ typedef void
typedef struct _cairo_test_target
{
const char *name;
+ cairo_surface_type_t expected_type;
cairo_content_t content;
cairo_test_create_target_surface_t create_target_surface;
cairo_test_write_to_png_t write_to_png;
cairo_test_cleanup_target_t cleanup_target;
- void *closure;
+ void *closure;
} cairo_test_target_t;
static char *
@@ -1282,12 +1298,21 @@ cleanup_pdf (void *closure)
#if CAIRO_HAS_SVG_SURFACE && CAIRO_CAN_TEST_SVG_SURFACE
#include "cairo-svg.h"
+static const char *svg_ignored_tests[] = {
+ "operator-source",
+ "operator-clear",
+ "clip-operator",
+ "unbounded-operator",
+ NULL
+};
+
cairo_user_data_key_t svg_closure_key;
typedef struct _svg_target_closure
{
char *filename;
int width, height;
+ cairo_surface_t *target;
} svg_target_closure_t;
static cairo_surface_t *
@@ -1297,22 +1322,41 @@ create_svg_surface (cairo_test_t *test,
{
int width = test->width;
int height = test->height;
+ int i;
svg_target_closure_t *ptc;
cairo_surface_t *surface;
+ for (i = 0; svg_ignored_tests[i] != NULL; i++)
+ if (strcmp (test->name, svg_ignored_tests[i]) == 0)
+ return NULL;
+
*closure = ptc = xmalloc (sizeof (svg_target_closure_t));
ptc->width = width;
ptc->height = height;
- xasprintf (&ptc->filename, "%s-%s%s", test->name, "svg-argb32-out", ".svg");
+ xasprintf (&ptc->filename, "%s-svg-%s-out.svg",
+ test->name, _cairo_test_content_name (content));
+
surface = cairo_svg_surface_create (ptc->filename, width, height);
if (cairo_surface_status (surface)) {
free (ptc->filename);
free (ptc);
return NULL;
}
+ cairo_svg_surface_set_dpi (surface, 72., 72.);
+
+ if (content == CAIRO_CONTENT_COLOR) {
+ ptc->target = surface;
+ surface = cairo_surface_create_similar (ptc->target,
+ CAIRO_CONTENT_COLOR,
+ width, height);
+ } else {
+ ptc->target = NULL;
+ }
+
cairo_surface_set_user_data (surface, &svg_closure_key, ptc, NULL);
+
return surface;
}
@@ -1322,15 +1366,26 @@ svg_surface_write_to_png (cairo_surface_t *surface, const char *filename)
svg_target_closure_t *ptc = cairo_surface_get_user_data (surface, &svg_closure_key);
char command[4096];
- cairo_surface_finish (surface);
+ if (ptc->target) {
+ cairo_t *cr;
+ cr = cairo_create (ptc->target);
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_paint (cr);
+ cairo_show_page (cr);
+ cairo_destroy (cr);
+
+ cairo_surface_finish (surface);
+ surface = ptc->target;
+ }
+ cairo_surface_finish (surface);
sprintf (command, "./svg2png %s %s",
ptc->filename, filename);
if (system (command) != 0)
return CAIRO_STATUS_WRITE_ERROR;
- return CAIRO_STATUS_WRITE_ERROR;
+ return CAIRO_STATUS_SUCCESS;
}
static void
@@ -1387,13 +1442,19 @@ cairo_test_for_target (cairo_test_t *test,
goto UNWIND_STRINGS;
}
+ if (cairo_surface_get_type (surface) != target->expected_type) {
+ cairo_test_log ("Error: Created surface is of type %d (expected %d)\n",
+ cairo_surface_get_type (surface), target->expected_type);
+ ret = CAIRO_TEST_FAILURE;
+ goto UNWIND_SURFACE;
+ }
+
cr = cairo_create (surface);
/* Clear to transparent (or black) depending on whether the target
* surface supports alpha. */
cairo_save (cr);
- cairo_set_source_rgba (cr, 0, 0, 0, 0);
- cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
cairo_restore (cr);
@@ -1418,6 +1479,7 @@ cairo_test_for_target (cairo_test_t *test,
/* Skip image check for tests with no image (width,height == 0,0) */
if (test->width != 0 && test->height != 0) {
int pixels_changed;
+ xunlink (png_name);
(target->write_to_png) (surface, png_name);
if (target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED)
pixels_changed = image_diff_flattened (png_name, ref_name, diff_name);
@@ -1436,6 +1498,7 @@ cairo_test_for_target (cairo_test_t *test,
UNWIND_CAIRO:
cairo_destroy (cr);
+UNWIND_SURFACE:
cairo_surface_destroy (surface);
cairo_debug_reset_static_data ();
@@ -1461,102 +1524,134 @@ cairo_test_expecting (cairo_test_t *test, cairo_test_draw_function_t draw,
cairo_test_target_t **targets_to_test;
cairo_test_target_t targets[] =
{
- { "image", CAIRO_CONTENT_COLOR_ALPHA,
+ { "image", CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR_ALPHA,
create_image_surface, cairo_surface_write_to_png, NULL},
- { "image", CAIRO_CONTENT_COLOR,
+ { "image", CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR,
create_image_surface, cairo_surface_write_to_png, NULL},
#ifdef CAIRO_HAS_TEST_SURFACES
- { "test-fallback", CAIRO_CONTENT_COLOR_ALPHA,
+ { "test-fallback", CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+ CAIRO_CONTENT_COLOR_ALPHA,
create_test_fallback_surface, cairo_surface_write_to_png, NULL },
- { "test-fallback", CAIRO_CONTENT_COLOR,
+ { "test-fallback", CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
+ CAIRO_CONTENT_COLOR,
create_test_fallback_surface, cairo_surface_write_to_png, NULL },
- { "test-meta", CAIRO_CONTENT_COLOR_ALPHA,
+ { "test-meta", CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
+ CAIRO_CONTENT_COLOR_ALPHA,
create_test_meta_surface, cairo_surface_write_to_png, NULL },
- { "test-meta", CAIRO_CONTENT_COLOR,
+ { "test-meta", CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
+ CAIRO_CONTENT_COLOR,
create_test_meta_surface, cairo_surface_write_to_png, NULL },
- { "test-paginated", CAIRO_CONTENT_COLOR_ALPHA,
+ { "test-paginated", CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
+ CAIRO_CONTENT_COLOR_ALPHA,
create_test_paginated_surface,
test_paginated_write_to_png,
cleanup_test_paginated },
- { "test-paginated", CAIRO_CONTENT_COLOR,
+ { "test-paginated", CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED,
+ CAIRO_CONTENT_COLOR,
create_test_paginated_surface,
test_paginated_write_to_png,
cleanup_test_paginated },
#endif
#ifdef CAIRO_HAS_GLITZ_SURFACE
#if CAIRO_CAN_TEST_GLITZ_GLX_SURFACE
- { "glitz-glx", CAIRO_CONTENT_COLOR_ALPHA,
+ { "glitz-glx", CAIRO_SURFACE_TYPE_GLITZ,CAIRO_CONTENT_COLOR_ALPHA,
create_cairo_glitz_glx_surface, cairo_surface_write_to_png,
cleanup_cairo_glitz_glx },
- { "glitz-glx", CAIRO_CONTENT_COLOR,
+ { "glitz-glx", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR,
create_cairo_glitz_glx_surface, cairo_surface_write_to_png,
cleanup_cairo_glitz_glx },
#endif
#if CAIRO_CAN_TEST_GLITZ_AGL_SURFACE
- { "glitz-agl", CAIRO_CONTENT_COLOR_ALPHA,
+ { "glitz-agl", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR_ALPHA,
create_cairo_glitz_agl_surface, cairo_surface_write_to_png,
cleanup_cairo_glitz_agl },
- { "glitz-agl", CAIRO_CONTENT_COLOR,
+ { "glitz-agl", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR,
create_cairo_glitz_agl_surface, cairo_surface_write_to_png,
cleanup_cairo_glitz_agl },
#endif
#if CAIRO_CAN_TEST_GLITZ_WGL_SURFACE
- { "glitz-wgl", CAIRO_CONTENT_COLOR_ALPHA,
+ { "glitz-wgl", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR_ALPHA,
create_cairo_glitz_wgl_surface, cairo_surface_write_to_png,
cleanup_cairo_glitz_wgl },
- { "glitz-wgl", CAIRO_CONTENT_COLOR,
+ { "glitz-wgl", CAIRO_SURFACE_TYPE_GLITZ, CAIRO_CONTENT_COLOR,
create_cairo_glitz_wgl_surface, cairo_surface_write_to_png,
cleanup_cairo_glitz_wgl },
#endif
#endif /* CAIRO_HAS_GLITZ_SURFACE */
#if 0 && CAIRO_HAS_QUARTZ_SURFACE
- { "quartz", CAIRO_CONTENT_COLOR,
+ { "quartz", CAIRO_SURFACE_TYPE_QUARTZ, CAIRO_CONTENT_COLOR,
create_quartz_surface, cairo_surface_write_to_png,
cleanup_quartz },
#endif
#if CAIRO_HAS_WIN32_SURFACE
- { "win32", CAIRO_CONTENT_COLOR,
+ { "win32", CAIRO_SURFACE_TYPE_WIN32, CAIRO_CONTENT_COLOR,
create_win32_surface, cairo_surface_write_to_png, cleanup_win32 },
#endif
#if CAIRO_HAS_XCB_SURFACE
- { "xcb", CAIRO_CONTENT_COLOR_ALPHA,
+ { "xcb", CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR_ALPHA,
create_xcb_surface, cairo_surface_write_to_png, cleanup_xcb},
#endif
#if CAIRO_HAS_XLIB_SURFACE
- { "xlib", CAIRO_CONTENT_COLOR_ALPHA,
+ { "xlib", CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR_ALPHA,
create_xlib_surface, cairo_surface_write_to_png, cleanup_xlib},
- { "xlib", CAIRO_CONTENT_COLOR,
+ { "xlib", CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR,
create_xlib_surface, cairo_surface_write_to_png, cleanup_xlib},
#endif
#if CAIRO_HAS_PS_SURFACE
- { "ps", CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED,
+ { "ps", CAIRO_SURFACE_TYPE_PS,
+ CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED,
create_ps_surface, ps_surface_write_to_png, cleanup_ps },
- { "ps", CAIRO_CONTENT_COLOR,
+
+ /* XXX: We expect type image here only due to a limitation in
+ * the current PS/meta-surface code. A PS surface is
+ * "naturally" COLOR_ALPHA, so the COLOR-only variant goes
+ * through create_similar in create_ps_surface which results
+ * in the similar surface being used as a source. We do not yet
+ * have source support for PS/meta-surfaces, so the
+ * create_similar path for all paginated surfaces currently
+ * returns an image surface.*/
+ { "ps", CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR,
create_ps_surface, ps_surface_write_to_png, cleanup_ps },
#endif
#if CAIRO_HAS_PDF_SURFACE && CAIRO_CAN_TEST_PDF_SURFACE
- { "pdf", CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED,
+ { "pdf", CAIRO_SURFACE_TYPE_PDF,
+ CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED,
create_pdf_surface, pdf_surface_write_to_png, cleanup_pdf },
- { "pdf", CAIRO_CONTENT_COLOR,
+
+ /* XXX: We expect type image here only due to a limitation in
+ * the current PDF/meta-surface code. A PDF surface is
+ * "naturally" COLOR_ALPHA, so the COLOR-only variant goes
+ * through create_similar in create_pdf_surface which results
+ * in the similar surface being used as a source. We do not yet
+ * have source support for PDF/meta-surfaces, so the
+ * create_similar path for all paginated surfaces currently
+ * returns an image surface.*/
+ { "pdf", CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR,
create_pdf_surface, pdf_surface_write_to_png, cleanup_pdf },
#endif
#if CAIRO_HAS_SVG_SURFACE && CAIRO_CAN_TEST_SVG_SURFACE
- { "svg", CAIRO_CONTENT_COLOR_ALPHA,
+ { "svg", CAIRO_SURFACE_TYPE_SVG, CAIRO_CONTENT_COLOR_ALPHA,
+ create_svg_surface, svg_surface_write_to_png, cleanup_svg },
+
+ /* A SVG surface is COLOR_APLHA by default, and currently a create
+ * similar with content != COLOR_ALPHA will return a nil surface.
+ * So don't test COLOR for now. */
+ { "svg", CAIRO_SURFACE_TYPE_SVG, CAIRO_CONTENT_COLOR,
create_svg_surface, svg_surface_write_to_png, cleanup_svg },
#endif
#if CAIRO_HAS_BEOS_SURFACE
- { "beos", CAIRO_CONTENT_COLOR,
+ { "beos", CAIRO_SURFACE_TYPE_BEOS, CAIRO_CONTENT_COLOR,
create_beos_surface, cairo_surface_write_to_png, cleanup_beos},
- { "beos_bitmap", CAIRO_CONTENT_COLOR,
+ { "beos_bitmap", CAIRO_SURFACE_TYPE_BEOS, CAIRO_CONTENT_COLOR,
create_beos_bitmap_surface, cairo_surface_write_to_png, cleanup_beos_bitmap},
- { "beos_bitmap", CAIRO_CONTENT_COLOR_ALPHA,
+ { "beos_bitmap", CAIRO_SURFACE_TYPE_BEOS, CAIRO_CONTENT_COLOR_ALPHA,
create_beos_bitmap_surface, cairo_surface_write_to_png, cleanup_beos_bitmap},
#endif
#if CAIRO_HAS_DIRECTFB_SURFACE
- { "directfb", CAIRO_CONTENT_COLOR,
+ { "directfb", CAIRO_SURFACE_TYPE_DIRECTFB, CAIRO_CONTENT_COLOR,
create_directfb_surface, cairo_surface_write_to_png, cleanup_directfb},
- { "directfb_bitmap", CAIRO_CONTENT_COLOR_ALPHA,
+ { "directfb_bitmap", CAIRO_SURFACE_TYPE_DIRECTFB, CAIRO_CONTENT_COLOR_ALPHA,
create_directfb_bitmap_surface, cairo_surface_write_to_png,cleanup_directfb},
#endif
};
diff --git a/test/caps-joins-ps-argb32-ref.png b/test/caps-joins-ps-argb32-ref.png
new file mode 100644
index 000000000..d6742957a
--- /dev/null
+++ b/test/caps-joins-ps-argb32-ref.png
Binary files differ
diff --git a/test/caps-sub-paths-ps-argb32-ref.png b/test/caps-sub-paths-ps-argb32-ref.png
new file mode 100644
index 000000000..a7bc1acb4
--- /dev/null
+++ b/test/caps-sub-paths-ps-argb32-ref.png
Binary files differ
diff --git a/test/clip-fill-rule-ps-argb32-ref.png b/test/clip-fill-rule-ps-argb32-ref.png
new file mode 100644
index 000000000..6d97e04de
--- /dev/null
+++ b/test/clip-fill-rule-ps-argb32-ref.png
Binary files differ
diff --git a/test/clip-nesting-ps-argb32-ref.png b/test/clip-nesting-ps-argb32-ref.png
new file mode 100644
index 000000000..1bd43d7a1
--- /dev/null
+++ b/test/clip-nesting-ps-argb32-ref.png
Binary files differ
diff --git a/test/clip-twice-ps-argb32-ref.png b/test/clip-twice-ps-argb32-ref.png
new file mode 100644
index 000000000..9ec76b4ef
--- /dev/null
+++ b/test/clip-twice-ps-argb32-ref.png
Binary files differ
diff --git a/test/dash-caps-joins-ps-argb32-ref.png b/test/dash-caps-joins-ps-argb32-ref.png
new file mode 100644
index 000000000..629b97b34
--- /dev/null
+++ b/test/dash-caps-joins-ps-argb32-ref.png
Binary files differ
diff --git a/test/dash-caps-joins-ref.png b/test/dash-caps-joins-ref.png
index 5c887c5c9..9218ae499 100644
--- a/test/dash-caps-joins-ref.png
+++ b/test/dash-caps-joins-ref.png
Binary files differ
diff --git a/test/dash-caps-joins-rgb24-ref.png b/test/dash-caps-joins-rgb24-ref.png
index 28339f8ed..6ec274dfb 100644
--- a/test/dash-caps-joins-rgb24-ref.png
+++ b/test/dash-caps-joins-rgb24-ref.png
Binary files differ
diff --git a/test/dash-offset-negative-ps-argb32-ref.png b/test/dash-offset-negative-ps-argb32-ref.png
new file mode 100644
index 000000000..518e1c925
--- /dev/null
+++ b/test/dash-offset-negative-ps-argb32-ref.png
Binary files differ
diff --git a/test/dash-zero-length-ps-argb32-ref.png b/test/dash-zero-length-ps-argb32-ref.png
new file mode 100644
index 000000000..5c7fab579
--- /dev/null
+++ b/test/dash-zero-length-ps-argb32-ref.png
Binary files differ
diff --git a/test/dash-zero-length-ref.png b/test/dash-zero-length-ref.png
new file mode 100644
index 000000000..aca856f2b
--- /dev/null
+++ b/test/dash-zero-length-ref.png
Binary files differ
diff --git a/test/dash-zero-length-rgb24-ref.png b/test/dash-zero-length-rgb24-ref.png
new file mode 100644
index 000000000..f5e40e85c
--- /dev/null
+++ b/test/dash-zero-length-rgb24-ref.png
Binary files differ
diff --git a/test/dash-zero-length.c b/test/dash-zero-length.c
new file mode 100644
index 000000000..a5d0047de
--- /dev/null
+++ b/test/dash-zero-length.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright © 2006 Jeff Muizelaar
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Jeff Muizelaar. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Jeff Muizelaar. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * JEFF MUIZELAAR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL JEFF MUIZELAAR BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Jeff Muizelaar <jeff@infidigm.net>
+ */
+
+#include "cairo-test.h"
+
+#define IMAGE_WIDTH 19
+#define IMAGE_HEIGHT 25
+
+/* A test of the two extremes of dashing: a solid line
+ * and an invisible one. Also test that capping works
+ * on invisible lines.
+ */
+
+cairo_test_t test = {
+ "dash-zero-length",
+ "Tests cairo_set_dash with zero length",
+ IMAGE_WIDTH, IMAGE_HEIGHT
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ double solid_line[] = { 4, 0 };
+ double invisible_line[] = { 0, 4 };
+ double dotted_line[] = { 0, 6 };
+ double rounded_line[] = { 2, 6 };
+
+ cairo_set_source_rgb (cr, 1, 0, 0);
+ cairo_set_line_width (cr, 2);
+
+ /* draw a solid line */
+ cairo_set_dash (cr, solid_line, 2, 0);
+ cairo_move_to (cr, 1, 2);
+ cairo_line_to (cr, 18, 2);
+ cairo_stroke (cr);
+
+ /* draw an invisible line */
+ cairo_set_dash (cr, invisible_line, 2, 0);
+ cairo_move_to (cr, 1, 8);
+ cairo_line_to (cr, 18, 8);
+ cairo_stroke (cr);
+
+ /* draw a dotted line */
+ cairo_set_line_width (cr, 5);
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+ cairo_set_dash (cr, dotted_line, 2, 0);
+ cairo_move_to (cr, 5, 13);
+ cairo_line_to (cr, 18, 13);
+ cairo_stroke (cr);
+
+ /* draw a rounded line */
+ cairo_set_line_width (cr, 5);
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+ cairo_set_dash (cr, rounded_line, 2, 2);
+ cairo_move_to (cr, 5, 20);
+ cairo_line_to (cr, 18, 20);
+ cairo_stroke (cr);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+ return cairo_test (&test, draw);
+}
diff --git a/test/fill-and-stroke-ps-argb32-ref.png b/test/fill-and-stroke-ps-argb32-ref.png
new file mode 100644
index 000000000..0df3205df
--- /dev/null
+++ b/test/fill-and-stroke-ps-argb32-ref.png
Binary files differ
diff --git a/test/fill-rule-ps-argb32-ref.png b/test/fill-rule-ps-argb32-ref.png
new file mode 100644
index 000000000..b5487e683
--- /dev/null
+++ b/test/fill-rule-ps-argb32-ref.png
Binary files differ
diff --git a/test/font-face-get-type.c b/test/font-face-get-type.c
new file mode 100644
index 000000000..c21d5c238
--- /dev/null
+++ b/test/font-face-get-type.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright © 2006 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Red Hat, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Red Hat, Inc. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Carl D. Worth <cworth@cworth.org>
+ */
+
+#include "cairo-test.h"
+
+int
+main (void)
+{
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ cairo_font_face_t *font_face;
+
+ cairo_test_init ("font-face-get-type");
+
+ cairo_test_log ("Creating cairo context and obtaining a font face\n");
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+ cr = cairo_create (surface);
+
+ cairo_select_font_face (cr, "Bitstream Vera Sans",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_NORMAL);
+
+ font_face = cairo_get_font_face (cr);
+
+ cairo_test_log ("Testing return value of cairo_font_face_get_type\n");
+
+ if (cairo_font_face_get_type (font_face) != CAIRO_FONT_TYPE_TOY) {
+ cairo_test_log ("Unexpected value %d from cairo_font_face_get_type (expected %d)\n",
+ cairo_font_face_get_type (font_face), CAIRO_FONT_TYPE_TOY);
+ return CAIRO_TEST_FAILURE;
+ }
+
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+
+
+
diff --git a/test/ft-font-create-for-ft-face.c b/test/ft-font-create-for-ft-face.c
index bf668b9d8..0bb3b8c0d 100644
--- a/test/ft-font-create-for-ft-face.c
+++ b/test/ft-font-create-for-ft-face.c
@@ -64,6 +64,13 @@ draw (cairo_t *cr, int width, int height)
font_face = cairo_ft_font_face_create_for_pattern (resolved);
+ if (cairo_font_face_get_type (font_face) != CAIRO_FONT_TYPE_FT) {
+ cairo_test_log ("Unexpected value from cairo_font_face_get_type: %d (expected %d)\n",
+ cairo_font_face_get_type (font_face), CAIRO_FONT_TYPE_FT);
+ cairo_font_face_destroy (font_face);
+ return CAIRO_TEST_FAILURE;
+ }
+
cairo_matrix_init_identity (&font_matrix);
cairo_get_matrix (cr, &ctm);
@@ -82,6 +89,13 @@ draw (cairo_t *cr, int width, int height)
FcPatternDestroy (pattern);
FcPatternDestroy (resolved);
+ if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_FT) {
+ cairo_test_log ("Unexpected value from cairo_scaled_font_get_type: %d (expected %d)\n",
+ cairo_scaled_font_get_type (scaled_font), CAIRO_FONT_TYPE_FT);
+ cairo_scaled_font_destroy (scaled_font);
+ return CAIRO_TEST_FAILURE;
+ }
+
if (!ft_face) {
cairo_test_log ("Failed to get an ft_face with cairo_ft_scaled_font_lock_face\n");
cairo_scaled_font_destroy (scaled_font);
diff --git a/test/leaky-polygon-ps-argb32-ref.png b/test/leaky-polygon-ps-argb32-ref.png
new file mode 100644
index 000000000..23af504ec
--- /dev/null
+++ b/test/leaky-polygon-ps-argb32-ref.png
Binary files differ
diff --git a/test/line-width-ps-argb32-ref.png b/test/line-width-ps-argb32-ref.png
new file mode 100644
index 000000000..ef6abb74e
--- /dev/null
+++ b/test/line-width-ps-argb32-ref.png
Binary files differ
diff --git a/test/mask.c b/test/mask.c
index a9414e046..6d0e45878 100644
--- a/test/mask.c
+++ b/test/mask.c
@@ -213,12 +213,10 @@ draw (cairo_t *cr, int width, int height)
int x = i * (WIDTH + PAD) + PAD;
int y = (ARRAY_SIZE (mask_funcs) * k + j) * (HEIGHT + PAD) + PAD;
- /* Clear area we are going to be drawing onto */
+ /* Clear intermediate surface we are going to be drawing onto */
cairo_save (cr2);
- cairo_set_source_rgba (cr2, 0, 0, 0, 0); /* transparent */
- cairo_set_operator (cr2, CAIRO_OPERATOR_SOURCE);
- cairo_rectangle (cr2, x, y, WIDTH, HEIGHT);
- cairo_fill (cr2);
+ cairo_set_operator (cr2, CAIRO_OPERATOR_CLEAR);
+ cairo_paint (cr2);
cairo_restore (cr2);
/* draw */
diff --git a/test/path-data-ps-argb32-ref.png b/test/path-data-ps-argb32-ref.png
new file mode 100644
index 000000000..b724a0f89
--- /dev/null
+++ b/test/path-data-ps-argb32-ref.png
Binary files differ
diff --git a/test/pattern-get-type.c b/test/pattern-get-type.c
new file mode 100644
index 000000000..a6aba03aa
--- /dev/null
+++ b/test/pattern-get-type.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright © 2006 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Red Hat, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Red Hat, Inc. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Carl D. Worth <cworth@cworth.org>
+ */
+
+#include "cairo-test.h"
+
+int
+main (void)
+{
+ cairo_surface_t *surface;
+ cairo_pattern_t *solid_rgb, *solid_rgba, *surface_pattern, *linear, *radial;
+
+ cairo_test_init ("pattern-get-type");
+
+ cairo_test_log ("Creating patterns of all types\n");
+
+ solid_rgb = cairo_pattern_create_rgb (0.0, 0.1, 0.2);
+ solid_rgba = cairo_pattern_create_rgba (0.3, 0.4, 0.5, 0.6);
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ 1, 1);
+ surface_pattern = cairo_pattern_create_for_surface (surface);
+ linear = cairo_pattern_create_linear (0.0, 0.0, 10.0, 10.0);
+ radial = cairo_pattern_create_radial (10.0, 10.0, 0.1,
+ 10.0, 10.0, 1.0);
+
+ cairo_test_log ("Verifying return values of cairo_pattern_get_type\n");
+
+ if (cairo_pattern_get_type (solid_rgb) != CAIRO_PATTERN_TYPE_SOLID)
+ return CAIRO_TEST_FAILURE;
+
+ if (cairo_pattern_get_type (solid_rgba) != CAIRO_PATTERN_TYPE_SOLID)
+ return CAIRO_TEST_FAILURE;
+
+ if (cairo_pattern_get_type (surface_pattern) != CAIRO_PATTERN_TYPE_SURFACE)
+ return CAIRO_TEST_FAILURE;
+
+ if (cairo_pattern_get_type (linear) != CAIRO_PATTERN_TYPE_LINEAR)
+ return CAIRO_TEST_FAILURE;
+
+ if (cairo_pattern_get_type (radial) != CAIRO_PATTERN_TYPE_RADIAL)
+ return CAIRO_TEST_FAILURE;
+
+ cairo_test_log ("Cleaning up\n");
+
+ cairo_pattern_destroy (solid_rgb);
+ cairo_pattern_destroy (solid_rgba);
+ cairo_pattern_destroy (surface_pattern);
+ cairo_surface_destroy (surface);
+ cairo_pattern_destroy (linear);
+ cairo_pattern_destroy (radial);
+
+ return CAIRO_TEST_SUCCESS;
+}
diff --git a/test/rectangle-rounding-error-ps-argb32-ref.png b/test/rectangle-rounding-error-ps-argb32-ref.png
new file mode 100644
index 000000000..2753f6d24
--- /dev/null
+++ b/test/rectangle-rounding-error-ps-argb32-ref.png
Binary files differ
diff --git a/test/show-glyphs-many-ref.png b/test/show-glyphs-many-ref.png
new file mode 100644
index 000000000..b61c5f7b6
--- /dev/null
+++ b/test/show-glyphs-many-ref.png
Binary files differ
diff --git a/test/show-glyphs-many-rgb24-ref.png b/test/show-glyphs-many-rgb24-ref.png
new file mode 100644
index 000000000..450e8e0bb
--- /dev/null
+++ b/test/show-glyphs-many-rgb24-ref.png
Binary files differ
diff --git a/test/show-glyphs-many.c b/test/show-glyphs-many.c
new file mode 100644
index 000000000..3c444114d
--- /dev/null
+++ b/test/show-glyphs-many.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright © 2006 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Red Hat, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. Red Hat, Inc. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
+ * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Carl D. Worth <cworth@cworth.org>
+ */
+
+#include "cairo-test.h"
+
+#include <string.h>
+
+/* Bug history
+ *
+ * 2006-01-07 Jon Hellan <hellan@acm.org>
+ *
+ * Jon opened the following bug report:
+ *
+ * _XError from XRenderCompositeText8
+ * https://bugs.freedesktop.org/show_bug.cgi?id=5528
+ *
+ * 2006-03-02 Carl Worth <cworth@cworth.org>
+ *
+ * I wrote this test case to demonstrate the bug.
+ *
+ * Approach:
+ *
+ * Draw 65535 glyphs white-on-white all on top of each other.
+ *
+ * Rationale:
+ *
+ * The number 65535 comes from the original bug report.
+ *
+ * I would use cairo_show_text with a long string of 'x's say,
+ * but then the surface would need to be enormous to contain
+ * them. A smaller surface could be used, but I fear that at some
+ * point the off-surface glyph drawing would be optimized away
+ * and not exercise the bug.
+ *
+ * So, to keep the surface size under control, I use
+ * cairo_show_glyphs which allows me to place the glyphs all on
+ * top of each other. But, since cairo doesn't provide any
+ * character-to-glyphs mapping, I can't get a reliable glyph
+ * index (for character 'x' for example). So I just "guess" a
+ * glyph index and use white-on-white drawing to ignore the
+ * result. (I don't care what's drawn---I just want to ensure
+ * that things don't crash.)
+ *
+ * Status: I replicated bug. The largest value of NUM_GLYPHS for
+ * which I saw success is 21842.
+ */
+
+#define TEXT_SIZE 12
+#define NUM_GLYPHS 65535
+
+/* This is the index into the font for what glyph we'll draw. Since we
+ * don't guarantee we'll get any particular font, we can't relibably
+ * get any particular glyph. But we don't care what we draw anyway,
+ * (see discussion of white-on-white drawing above). For what it's
+ * worth, this appears to be giving me 'M' with Bitstream Vera
+ * Sans Mono. */
+#define GLYPH_INDEX 48
+
+cairo_test_t test = {
+ "show-glyphs-many",
+ "Test that cairo_show_glyps works when handed 'many' glyphs",
+ 9, 11
+};
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+ cairo_glyph_t glyphs[NUM_GLYPHS];
+ cairo_font_options_t *font_options;
+ int i;
+
+ /* Initialize our giant array of glyphs. */
+ for (i=0; i < NUM_GLYPHS; i++) {
+ glyphs[i].index = GLYPH_INDEX;
+ glyphs[i].x = 1.0;
+ glyphs[i].y = height - 1;
+ }
+
+ /* Paint white background. */
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
+ cairo_paint (cr);
+
+ cairo_select_font_face (cr, "Bitstream Vera Sans Mono",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_set_font_size (cr, TEXT_SIZE);
+
+ font_options = cairo_font_options_create ();
+
+ cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
+ cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_GRAY);
+
+ cairo_set_font_options (cr, font_options);
+ cairo_font_options_destroy (font_options);
+
+ cairo_show_glyphs (cr, glyphs, NUM_GLYPHS);
+
+ return CAIRO_TEST_SUCCESS;
+}
+
+int
+main (void)
+{
+ return cairo_test (&test, draw);
+}
diff --git a/test/show-text-current-point-ps-argb32-ref.png b/test/show-text-current-point-ps-argb32-ref.png
new file mode 100644
index 000000000..f00681b9d
--- /dev/null
+++ b/test/show-text-current-point-ps-argb32-ref.png
Binary files differ
diff --git a/test/show-text-current-point-svg-argb32-ref.png b/test/show-text-current-point-svg-argb32-ref.png
new file mode 100644
index 000000000..717ad7e42
--- /dev/null
+++ b/test/show-text-current-point-svg-argb32-ref.png
Binary files differ
diff --git a/test/show-text-current-point-svg-rgb24-ref.png b/test/show-text-current-point-svg-rgb24-ref.png
new file mode 100644
index 000000000..717ad7e42
--- /dev/null
+++ b/test/show-text-current-point-svg-rgb24-ref.png
Binary files differ
diff --git a/test/text-antialias-gray-ps-argb32-ref.png b/test/text-antialias-gray-ps-argb32-ref.png
new file mode 100644
index 000000000..acb273cb7
--- /dev/null
+++ b/test/text-antialias-gray-ps-argb32-ref.png
Binary files differ
diff --git a/test/text-antialias-gray-svg-argb32-ref.png b/test/text-antialias-gray-svg-argb32-ref.png
new file mode 100644
index 000000000..aa64fbbec
--- /dev/null
+++ b/test/text-antialias-gray-svg-argb32-ref.png
Binary files differ
diff --git a/test/text-antialias-gray-svg-rgb24-ref.png b/test/text-antialias-gray-svg-rgb24-ref.png
new file mode 100644
index 000000000..aa64fbbec
--- /dev/null
+++ b/test/text-antialias-gray-svg-rgb24-ref.png
Binary files differ
diff --git a/test/text-antialias-none-ps-argb32-ref.png b/test/text-antialias-none-ps-argb32-ref.png
new file mode 100644
index 000000000..acb273cb7
--- /dev/null
+++ b/test/text-antialias-none-ps-argb32-ref.png
Binary files differ
diff --git a/test/text-antialias-none-svg-argb32-ref.png b/test/text-antialias-none-svg-argb32-ref.png
new file mode 100644
index 000000000..aa64fbbec
--- /dev/null
+++ b/test/text-antialias-none-svg-argb32-ref.png
Binary files differ
diff --git a/test/text-antialias-none-svg-rgb24-ref.png b/test/text-antialias-none-svg-rgb24-ref.png
new file mode 100644
index 000000000..aa64fbbec
--- /dev/null
+++ b/test/text-antialias-none-svg-rgb24-ref.png
Binary files differ
diff --git a/test/text-antialias-subpixel-ps-argb32-ref.png b/test/text-antialias-subpixel-ps-argb32-ref.png
new file mode 100644
index 000000000..acb273cb7
--- /dev/null
+++ b/test/text-antialias-subpixel-ps-argb32-ref.png
Binary files differ
diff --git a/test/text-antialias-subpixel-svg-argb32-ref.png b/test/text-antialias-subpixel-svg-argb32-ref.png
new file mode 100644
index 000000000..aa64fbbec
--- /dev/null
+++ b/test/text-antialias-subpixel-svg-argb32-ref.png
Binary files differ
diff --git a/test/text-antialias-subpixel-svg-rgb24-ref.png b/test/text-antialias-subpixel-svg-rgb24-ref.png
new file mode 100644
index 000000000..aa64fbbec
--- /dev/null
+++ b/test/text-antialias-subpixel-svg-rgb24-ref.png
Binary files differ
diff --git a/test/text-pattern-svg-argb32-ref.png b/test/text-pattern-svg-argb32-ref.png
new file mode 100644
index 000000000..e4b5f753e
--- /dev/null
+++ b/test/text-pattern-svg-argb32-ref.png
Binary files differ
diff --git a/test/text-pattern-svg-rgb24-ref.png b/test/text-pattern-svg-rgb24-ref.png
new file mode 100644
index 000000000..6f3510cbf
--- /dev/null
+++ b/test/text-pattern-svg-rgb24-ref.png
Binary files differ
diff --git a/test/transforms-ps-argb32-ref.png b/test/transforms-ps-argb32-ref.png
new file mode 100644
index 000000000..4858364f6
--- /dev/null
+++ b/test/transforms-ps-argb32-ref.png
Binary files differ
diff --git a/test/unantialiased-shapes-ps-argb32-ref.png b/test/unantialiased-shapes-ps-argb32-ref.png
new file mode 100644
index 000000000..dc64e3616
--- /dev/null
+++ b/test/unantialiased-shapes-ps-argb32-ref.png
Binary files differ
diff --git a/test/unantialiased-shapes-svg-argb32-ref.png b/test/unantialiased-shapes-svg-argb32-ref.png
new file mode 100644
index 000000000..da297735b
--- /dev/null
+++ b/test/unantialiased-shapes-svg-argb32-ref.png
Binary files differ
diff --git a/test/unantialiased-shapes-svg-rgb24-ref.png b/test/unantialiased-shapes-svg-rgb24-ref.png
new file mode 100644
index 000000000..da297735b
--- /dev/null
+++ b/test/unantialiased-shapes-svg-rgb24-ref.png
Binary files differ