b=404092, upgrade cairo to 1.5.2-55

git-svn-id: svn://10.0.0.236/trunk@240123 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
vladimir%pobox.com 2007-11-29 20:07:00 +00:00
parent 603b1cf9e1
commit 5c869f2081
120 changed files with 11510 additions and 4449 deletions

View File

@ -7,8 +7,8 @@ http://www.cairographics.org/.
VERSIONS: VERSIONS:
cairo (1.5.x - d8b0de01d67cdf73d8266a73f54ba1ac42fee3c9) cairo (1.5.x - 1.5.2-55-g39b8ddf)
pixman (0.9.x - 3be35594c99b7abd2af43b66349ca53bfa1462d6) pixman (0.9.x - pixman-0.9.6-13-g4193b3c)
glitz 0.5.2 (cvs - 2006-01-10) glitz 0.5.2 (cvs - 2006-01-10)
***** NOTE FOR VISUAL C++ 6.0 ***** ***** NOTE FOR VISUAL C++ 6.0 *****
@ -25,8 +25,4 @@ win32-logical-font-scale.patch: set CAIRO_WIN32_LOGICAL_FONT_SCALE to 1
nonfatal-assertions.patch: Make assertions non-fatal nonfatal-assertions.patch: Make assertions non-fatal
win32-glyph-metrics.patch: GetGlyphOutline only works on Truetype fonts,
so for non-Truetype fonts, assume no left or right bearing and use the
font ascent and descent for the glyph extents.
endian.patch: include cairo-platform.h for endian macros endian.patch: include cairo-platform.h for endian macros

View File

@ -1,26 +1,99 @@
Josh Aas <joshmoz@gmail.com> Memory leak fix for quartz backend
Daniel Amelang <dan@amelang.net> Many (magic) floating-point optimizations
Shawn T. Amundson <amundson@gtk.org> Build fix Shawn T. Amundson <amundson@gtk.org> Build fix
Olivier Andrieu <oliv__a@users.sourceforge.net> PNG backend Olivier Andrieu <oliv__a@users.sourceforge.net> PNG backend
Peter Dennis Bartok <peter@novonyx.com> Bug fix for clipping Peter Dennis Bartok <peter@novonyx.com> Bug fix for clipping
Dave Beckett <dajobe@debian.org> Build fixes, Debian packaging Dave Beckett <dajobe@debian.org> Build fixes, Debian packaging
Christian Biesinger <cbiesinger@web.de> BeOS backend
Billy Biggs <vektor@dumbterm.net> Pixman code merge. Optimization. Fixes for subtle rendering bugs.
Hans Breuer <hans@breuer.org> win32 bug fixes, build fixes, and improvements
Brian Cameron <brian.cameron@sun.com> Flag bug in Sun's X server
Damien Carbery <damien.carbery@sun.com> Build fixes
Andrew Chant <andrew.chant@utoronto.ca> Adding const where needed Andrew Chant <andrew.chant@utoronto.ca> Adding const where needed
Steve Chaplin <stevech1097@yahoo.com.au> Bug fixes for PNG reading
Tomasz Cholewo <cholewo@ieee-cis.org> Bug fixes
Manu Cornet <manu@manucornet.net> SVG build fix
Frederic Crozat <fcrozat@mandriva.com> Fix test suite for OPD platforms (IA64 or PPC64)
Radek Doulík <rodo@novell.com> Bug report and test case
John Ehresman <jpe@wingide.com> Build fixes for win32
John Ellson <ellson@research.att.com> First font/glyph extents functions John Ellson <ellson@research.att.com> First font/glyph extents functions
Michael Emmel <mike.emmel@gmail.com> DirectFB backend
Miklós Erdélyi <erdelyim@gmail.com> Fix typo leading to a crash
Behdad Esfahbod <behdad@behdad.org> Huge piles of bug fixes, improvements, and general maintenance
Brian Ewins <Brian.Ewins@gmail.com> ATSUI maintenance (first success at making it really work)
Bertram Felgenhauer <int-e@gmx.de> Fixes for subtle arithmetic errors
Bdale Garbee <bdale@gag.com> Provided essential support for cairo achitecture sessions
Jens Granseuer <jensgr@gmx.net> Fixes to generate proper compiler flags
Laxmi Harikumar <laxmi.harikumar@digital.com> Build fix
J. Ali Harlow <ali@avrc.city.ac.uk> win32 backend updates
Mathias Hasselmann <mathias.hasselmann@gmx.de> Significant reduction of calls to malloc
Richard Henderson <rth@twiddle.net> "slim" macros for better shared libraries Richard Henderson <rth@twiddle.net> "slim" macros for better shared libraries
James Henstridge <james@daa.com.au> Build fixes related to freetype James Henstridge <james@daa.com.au> Build fixes related to freetype
Graydon Hoare <graydon@redhat.com> Support for non-render X server, first real text support Graydon Hoare <graydon@redhat.com> Support for non-render X server, first real text support
Thomas Hunger <info@teh-web.de> Initial version of cairo_in_stroke/fill Thomas Hunger <info@teh-web.de> Initial version of cairo_in_stroke/fill
Kristian Høgsberg <krh@redhat.com> PDF backend Kristian Høgsberg <krh@redhat.com> PDF backend, PS backend with meta-surfaces
Amaury Jacquot <sxpert@esitcom.org> Documentation review, appplication testing
Adrian Johnson <ajohnson@redneon.com> PDF backend improvement
Michael Johnson <ahze@ahze.net> Bug fix for pre-C99 compilers
Jonathon Jongsma <jonathon.jongsma@gmail.com> Fix documentation typos
Øyvind Kolås <pippin@freedesktop.org> Bug fixes. Better default values.
Martin Kretzschmar <martink@gnome.org> Arithmetic fix for 64-bit architectures
Mathieu Lacage <Mathieu.Lacage@sophia.inria.fr> several bug/typo fixes
Dominic Lachowicz <domlachowicz@gmail.com> PDF conformance fix, fix image surface to zero out contents
Alexander Larsson <alexl@redhat.com> Profiling and performance fixes. Alexander Larsson <alexl@redhat.com> Profiling and performance fixes.
Tor Lillqvist <tml@novell.com> win32 build fixes, build scripts
Jinghua Luo <sunmoon1997@gmail.com> Add bitmap glyph transformation, many freetype and glitz fixes
Luke-Jr <luke-jr@utopios.org> Build fix for cross-compiling
Kjartan Maraas <kmaraas@gnome.org> Several fixes for sparse, lots of debug help for multi-thread bugs
Jordi Mas <jordi@ximian.com> Bug fix for cairo_show_text Jordi Mas <jordi@ximian.com> Bug fix for cairo_show_text
Nicholas Miell <nmiell@gmail.com> Fixes for linking bugs on AMD64
Eugeniy Meshcheryakov <eugen@debian.org> PS/PDF font subsetting improvements
Zakharov Mikhail <zmey20000@yahoo.com> Build fix for HP-UX
Christopher (Monty) Montgomery <xiphmont@gmail.com> Performnace fix (subimage_copy), multi-thread testing
Tim Mooney <enchanter@users.sourceforge.net> Fix test suite to compile with Solaris compiler
Jeff Muizelaar <jeff@infidigm.net> Patient, painful, pixman code merge. Many fixes for intricacies of dashing.
Yevgen Muntyan <muntyan@tamu.edu> win32 build fix
Declan Naughton <piratepenguin@gmail.com> Fix documentation typos
Peter Nilsson <c99pnn@cs.umu.se> Glitz backend
Henning Noren <henning.noren.402@student.lu.se> Fix memory leak
Geoff Norton <gnorton@customerdna.com> Build fixes
Robert O'Callahan <rocallahan@novell.com> Const-correctness fixes, several new API functions for completeness (and to help mozilla)
Ian Osgood <iano@quirkster.com> XCB backend maintenance
Benjamin Otte <in7y118@public.uni-hamburg.de> Refinements to cairo/perf timing
Mike Owens <etc@filespanker.com> Bug fixes
Emmanuel Pacaud <emmanuel.pacaud@lapp.in2p3.fr> SVG backend
Keith Packard <keithp@keithp.com> Original concept, polygon tessellation, dashing, font metrics rewrite Keith Packard <keithp@keithp.com> Original concept, polygon tessellation, dashing, font metrics rewrite
Stuart Parmenter <pavlov@pavlov.net> Original GDI+ backend, win32 fixes
Alfred Peng <alfred.peng@sun.com> Fixes for Sun compilers and for a memory leak
Christof Petig <christof@petig-baender.de> Build fixes related to freetype Christof Petig <christof@petig-baender.de> Build fixes related to freetype
Joonas Pihlaja <jpihlaja@cc.helsinki.fi> Huge improvements to the tessellator performance
Mart Raudsepp <leio@dustbite.net> Build fixes
David Reveman <davidr@novell.com> New pattern API, glitz backend David Reveman <davidr@novell.com> New pattern API, glitz backend
Calum Robinson <calumr@mac.com> Quartz backend Calum Robinson <calumr@mac.com> Quartz backend
Pavel Roskin <proski@gnu.org> Several cleanups to eliminate warnings
Tim Rowley <tim.rowley@gmail.com> Quartz/ATSUI fixes, X server workarounds, win32 glyph path support, test case to expose gradient regression
Soeren Sandmann <sandmann@daimi.au.dk> Lots of MMX love for pixman compositing
Torsten Schönfeld <kaffeetisch@gmx.de> Build fixes
Jamey Sharp <jamey@minilop.net> Surface/font backend virtualization, XCB backend Jamey Sharp <jamey@minilop.net> Surface/font backend virtualization, XCB backend
Jason Dorje Short <jdorje@users.sf.net> Build fixes and bug fixes
Jeff Smith <whydoubt@yahoo.com> Fixes for intricacies of stroking code
Travis Spencer <tspencer@cs.pdx.edu> XCB backend fix
Bill Spitzak <spitzak@d2.com> Build fix to find Xrender.h without xrender.pc Bill Spitzak <spitzak@d2.com> Build fix to find Xrender.h without xrender.pc
Owen Taylor <otaylor@redhat.com> Font support rewrite Zhe Su <james.su@gmail.com> Add support for fontconfig's embeddedbitmap option
Owen Taylor <otaylor@redhat.com> Font rewrite, documentation, win32 backend
Alp Toker <alp@atoker.com> Fix several code/comment typos
Malcolm Tredinnick <malcolm@commsecure.com.au> Documentation fixes
David Turner <david@freetype.org> Optimize gradient calculations
Kalle Vahlman <kalle.vahlman@gmail.com> Allow perf reports to be compared across different platforms
Sasha Vasko <sasha@aftercode.net> Build fix to compile without xlib backend Sasha Vasko <sasha@aftercode.net> Build fix to compile without xlib backend
Vladimir Vukicevic <vladimir@pobox.com> Bug fix for clipping Vladimir Vukicevic <vladimir@pobox.com> Quartz backend rewrite, win32/quartz maintenance
Jonathan Watt <jwatt@jwatt.org> win32 fixes
Peter Weilbacher <pmw@avila.aip.de> OS/2 backend
Dan Williams <dcbw@redhat.com> Implemnt MMX function to help OLPC
Chris Wilson <chris@chris-wilson.co.uk> Large-scale robustness improvements, (warn_unsed_result and malloc failure injection)
Carl Worth <cworth@isi.edu> Original library, support for paths, images Carl Worth <cworth@isi.edu> Original library, support for paths, images
Richard D. Worth <richard@theworths.org> Build fixes for cygwin Richard D. Worth <richard@theworths.org> Build fixes for cygwin
Kent Worsnop <kworsnop@accesswave.ca> Fix PDF dashing bug
Dave Yeo <daveryeo@telus.net> Build fix for win32
(please let us know if we have missed anyone) (please let us know if we have missed anyone)

View File

@ -1,9 +1,128 @@
This package uses automake, in order to generate the Makefiles use: Quick-start build instructions
------------------------------
1) Configure the package:
$ autogen.sh ./configure
After that, standard build procedures apply: 2) Compile it:
$ make make
# make install
3) Install it:
make install
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 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.
More detailed build instructions
--------------------------------
1) Configure the package
The first step in building cairo is to configure the package by
running the configure script. The configure script attempts to
automatically detect as much as possible about your system. So,
you should primarily just accept its defaults by running:
./configure
The configure script does accept a large number of options for
fine-tuning its behavior. See "./configure --help" for a complete
list. The most commonly used options are discussed here.
--prefix=PREFIX
This option specifies the directory under which the software
should be installed. By default configure will choose a
directory such as /usr/local. If you would like to install
cairo to some other location, pass the director to configure
with the --prefix option. For example:
./configure --prefix=/opt/cairo
would install cairo into the /opt/cairo directory. You could
also choose a prefix directory within your home directory if
you don't have write access to any system-wide directory.
After installing into a custom prefix, you will need to set
some environment variables to allow the software to be
found. Assuming the /opt/cairo prefix and assuming you are
using the bash shell, the following environment variables
should be set:
PKG_CONFIG_PATH=/opt/cairo/lib/pkgconfig
LD_LIBRARY_PATH=/opt/cairo/lib
export PKG_CONFIG_PATH LD_LIBRARY_PATH
(NOTE: On mac OS X, at least, use DYLD_LIBRARY_PATH in place
of LD_LIBRARY_PATH above.)
--enable-quartz
--enable-atsui
--enable-xcb
--enable-glitz
--enable-beos
--enable-os2
--enable-directfb
Some of cairo's backends are marked as experimental and will
not be built by default. If you would like to build and
experiment with these backends, you will need to pass one of
the above options to the configure script. You may need to
have certain libraries installed first as discussed in the
dependencies section of the README file.
--disable-xlib
--disable-win32
--disable-png
--disable-freetype
--disable-ps
--disable-pdf
--disable-svg
Cairo's configure script detects the libraries needed to build
each stable backend, and when it finds them, enables each
backend. If you would like to override this detection and
disable a backend, (even when it would be possible to build
it), use one of the options above to disable the backend.
2) Compile the package:
This step is very simple. Just:
make
The Makefiles included with cairo are designed to work on as many
different systems as possible.
When cairo is compiled, you can also run some automated tests of
cairo with:
make check
NOTE: Some versions of X servers will cause the -xlib tests to
report failures in make check even when cairo is working just
fine. If you see failures in nothing but -xlib tests, please
examine the corresponding -xlib-out.png images and compare them to
the -ref.png reference images (the -xlib-diff.png images might also
be useful). If the results seem "close enough" please do not report
a bug against cairo as the "failures" you are seeing are just due
to subtle variations in X server implementations.
3) Install the package:
The final step is to install the package with:
make install
If you are installing to a system-wide location you may need to
temporarily acquite root access in order to perform this
operation. A good way to do this is to use the sudo program:
sudo make install

File diff suppressed because it is too large Load Diff

View File

@ -1,60 +1,161 @@
Cairo - Multi-platform 2D graphics library Cairo - Multi-platform 2D graphics library
http://cairographics.org http://cairographics.org
Compiling What is cairo
--------- =============
See the INSTALL document for build instructions. Cairo is a 2D graphics library with support for multiple output
devices. Currently supported output targets include the X Window
System, win32, and image buffers, as well as PDF, PostScript, and SVG
file output. Experimental backends include OpenGL (through glitz),
Quartz, XCB, BeOS, OS/2, and DirectFB.
Description Cairo is designed to produce consistent output on all output media
----------- while taking advantage of display hardware acceleration when available
Cairo is a vector graphics library with cross-device output (for example, through the X Render Extension).
support. Currently supported output targets include the X Window
System and in-memory image buffers. PostScript and PDF file output is
planned. Cairo is designed to produce identical output on all output
media while taking advantage of display hardware acceleration when
available (eg. through the X Render Extension).
Cairo provides a stateful user-level API with capabilities similar to The cairo API provides operations similar to the drawing operators of
the PDF 1.4 imaging model. Cairo provides operations including PostScript and PDF. Operations in cairo include stroking and filling
stroking and filling Bezier cubic splines, transforming and cubic Bézier splines, transforming and compositing translucent images,
compositing translucent images, and antialiased text rendering. and antialiased text rendering. All drawing operations can be
transformed by any affine transformation (scale, rotation, shear,
etc.).
Cairo was once named Xr, (or Xr/Xc), so if you came looking for that Cairo has been designed to let you draw anything you want in a modern
software, you've found it. 2D graphical user interface. At the same time, the cairo API has been
designed to be as fun and easy to learn as possible. If you're not
having fun while programming with cairo, then we have failed
somewhere---let us know and we'll try to fix it next time around.
Cairo is free software and is available to be redistributed and/or
modified under the terms of either the GNU Lesser General Public
License (LGPL) version 2.1 or the Mozilla Public License (MPL) version
1.1.
Where to get more information about cairo
=========================================
The primary source of information about cairo is:
http://cairographics.org/
The latest releases of cairo can be found at:
http://cairographics.org/releases
Snapshots of in-development versions of cairo:
http://cairographics.org/snapshots
The programming manual for using cairo:
http://cairographics.org/manual
Mailing lists for contacting cairo users and developers:
http://cairographics.org/lists
Answers to some frequently asked questions about cairo:
http://cairographics.org/FAQ
Dependencies Dependencies
------------ ============
Cairo currently requires the following supporting libraries: The set of libraries needed to compile cairo depends on which backends
are enabled when cairo is configured. Here are the dependencies for
each backend:
libpixman Surface backends:
Xft2
fontconfig
freetype2
Documentation image backend (required)
------------- ------------------------
There's not much documentation yet apart from the cairo.h header pixman http://cairographics.org/releases
file. We'll be correcting that shortly. or: git://git.cairographics.org/git/pixman
In the meantime, the cairo-demo module in CVS provides a few example glitz backend
programs using cairo. These may be helpful to a programmer just -------------
beginning with cairo. Also, familiarity with the PostScript imaging glitz >= 0.4.4 http://freedesktop.org/Software/glitz
model will help in understanding cairo.
pdf backend
-----------
freetype >= 2.1.4 http://freetype.org
zlib http://www.gzip.org/zlib
postscript backend
------------------
freetype >= 2.1.4 http://freetype.org
zlib http://www.gzip.org/zlib
quartz backend
--------------
[*]
win32 backend
-------------
[*]
xcb backend
-----------
XCB http://xcb.freedesktop.org
xlib backend
------------
Xrender >= 0.6 http://freedesktop.org/Software/xlibs
beos backend
------------
No dependencies in itself other than an installed BeOS system, but cairo
requires a font backend. See the freetype dependency list.
os2 backend
-----------
Cairo should run on any recent version of OS/2 or eComStation, but it
requires a font backend. See the freetype dependency list. Ready to use
packages and developer dependencies are available at Netlabs:
ftp://ftp.netlabs.org/pub/cairo
Font backends:
freetype font backend
---------------------
freetype >= 2.1.4 http://freetype.org
fontconfig http://fontconfig.org
win32 font backend
------------------
[*]
atsui font backend
------------------
[*]
[*] I don't know specifically what packages might need to be
installed on a Mac OS X system to use the Quartz and ATSUI
backends. As far as win32, the situation is rather complex:
The Win32 backend should work on Windows 2000 and newer
(excluding Windows Me.) Most testing has been done on
Windows XP. While some portions of the code have been
adapted to work on older versions of Windows, considerable
work still needs to be done to get cairo running in these
environments.
Cairo can be compiled on Windows either with the GCC
toolchain (see http://www.mingw.org) or with Microsoft
Visual C++. Makefiles or project files for compiling with
MSVC are however not provided as of this release. We have
received reports that MSVC 6.0 compiles parts of cairo
incorrectly, (leading to incorrect color). MSVC 7.0 is
known to work.
Compiling
=========
See the INSTALL document for build instructions.
History History
------- =======
Cairo was originally developed by Carl Worth <cworth@cworth.org> and Cairo was originally developed by Carl Worth <cworth@cworth.org> and
Keith Packard <keithp@keithp.com>. Many thanks are due to Lyle Ramshaw Keith Packard <keithp@keithp.com>. Many thanks are due to Lyle Ramshaw
without whose patient help our ignorance would be much more apparent. without whose patient help our ignorance would be much more apparent.
Mailing List Since the original development, many more people have contributed to
------------ cairo. See the AUTHORS files for as complete a list as we've been able
If you have trouble with cairo or you have some ideas for how it could be to compile so far.
improved, please feel free to send a message to cairo@cairographics.org
Cairo is still under active development and all discussion happens on
that list. So if you want to lurk or, (even better), take part in the
development, take a look. Subscription information and archives are
available:
http://cairographics.org/cgi-bin/mailman/listinfo/cairo

View File

@ -1,86 +0,0 @@
Changes that are expected to impact the public API
==================================================
Patch submitted to mailing list?
/ Documentation included in patch?
|/ Review of patch completed?
||/ Test case included?
|||/ Committed.
||||/
Backwards compatible (API additions only)
-----------------------------------------
cairo_begin_group, cairo_end_group, cairo_get_group
PDR C cairo_surface_mark_dirty (see below for details)
PDRTC Add support for non-antialiased rendering + API
Add CAIRO_FILL_RULE_INVERSE_WINDING and CAIRO_FILL_RULE_INVERSE_EVEN_ODD
Add cairo_text_glyphs (see below for details)
Add support for programmatic patterns, (ie. arbitrary gradients)
P Add cairo_arc_to.
Add support for custom caps (see below for details)
Add support for getting at image data from image surface
Add CAIRO_STATUS_DESTROYED
Add cairo_finish
Backwards incompatible (API deletions or changes)
-------------------------------------------------
PDR C cairo_surface_finish, cairo_surface_flush
PDR C A hidden offset for the xlib backend
PDR C Consistent error handling for all objects
PDRTC Split cairo_format_t (see below for details)
P---C Remove cairo_status_string in favor of cairo_status_to_string
Details on some of the above changes
------------------------------------
* cairo_text_glyphs:
It would function as a sort of bridge between the toy and the
real text APIs:
> void
> cairo_text_glyphs (cairo_t *cr, const unsigned char *utf8,
> cairo_glyph_t *glyphs, int *num_glyphs);
>
> with num_glyphs as an input-output parameter. The behavior of this
> function would be such that calling:
>
> cairo_text_glyphs (cr, string, glyphs, &num_glyphs);
> cairo_show_glyphs (cr, glyphs, num_glyphs);
>
> would be equivalent too:
>
> cairo_show_text (cr, string);
>
> as long as the original size of glyphs/num_glyphs was large
> enough.
* support for custom caps:
It would be nice if the user had a mechanism to reliably draw custom
caps. One approach here would be to provide the coordinates of the
butt cap faces so that the user can append seamless caps to the
current path. We may also need to provide the coordinates of the
faces of every dash as well.
Changes that do not affect the public API
=========================================
* Fix clipping to work for all operators. The equation we have come up
with is:
((src Op dest) In clip) Add (dest Out clip)
* Change stroke code to go through one giant polygon. This will fix
problems with stroking self-intersecting paths.
* Fix the intersection problem, (see reference to Hobby's paper
mentioned in cairo_traps.c).
* Implement dashing for cairo_curve_to.
* Stroking closed, degenerate paths should still draw caps. Round
caps are easy; square should probably draw an axis-aligned square.
* Should add geometry pruning as appropriate.
* Verification, profiling, optimization.
centi_unfinished.svg may provide a good test case.

View File

@ -74,6 +74,7 @@ CSRCS = \
cairo-analysis-surface.c \ cairo-analysis-surface.c \
cairo-arc.c \ cairo-arc.c \
cairo-array.c \ cairo-array.c \
cairo-atomic.c \
cairo-bentley-ottmann.c \ cairo-bentley-ottmann.c \
cairo-cache.c \ cairo-cache.c \
cairo-clip.c \ cairo-clip.c \

View File

@ -46,12 +46,16 @@ cairo_private cairo_region_t *
_cairo_analysis_surface_get_supported (cairo_surface_t *surface); _cairo_analysis_surface_get_supported (cairo_surface_t *surface);
cairo_private cairo_region_t * cairo_private cairo_region_t *
_cairo_analysis_surface_get_unsupported (cairo_surface_t *unsupported); _cairo_analysis_surface_get_unsupported (cairo_surface_t *surface);
cairo_private cairo_bool_t cairo_private cairo_bool_t
_cairo_analysis_surface_has_supported (cairo_surface_t *unsupported); _cairo_analysis_surface_has_supported (cairo_surface_t *surface);
cairo_private cairo_bool_t cairo_private cairo_bool_t
_cairo_analysis_surface_has_unsupported (cairo_surface_t *unsupported); _cairo_analysis_surface_has_unsupported (cairo_surface_t *surface);
cairo_private void
_cairo_analysis_surface_get_bounding_box (cairo_surface_t *surface,
cairo_box_t *bbox);
#endif /* CAIRO_ANALYSIS_SURFACE_H */ #endif /* CAIRO_ANALYSIS_SURFACE_H */

View File

@ -48,12 +48,14 @@ typedef struct {
cairo_surface_t *target; cairo_surface_t *target;
cairo_bool_t first_op;
cairo_bool_t has_supported; cairo_bool_t has_supported;
cairo_bool_t has_unsupported; cairo_bool_t has_unsupported;
cairo_region_t supported_region; cairo_region_t supported_region;
cairo_region_t fallback_region; cairo_region_t fallback_region;
cairo_rectangle_int_t current_clip; cairo_rectangle_int_t current_clip;
cairo_box_t page_bbox;
} cairo_analysis_surface_t; } cairo_analysis_surface_t;
@ -74,7 +76,7 @@ _cairo_analysis_surface_analyze_meta_surface_pattern (cairo_analysis_surface_t *
analysis = _cairo_analysis_surface_create (surface->target, analysis = _cairo_analysis_surface_create (surface->target,
surface->width, surface->height); surface->width, surface->height);
if (analysis == NULL) if (analysis == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_meta_surface_replay_analyze_meta_pattern (meta_surface, analysis); status = _cairo_meta_surface_replay_analyze_meta_pattern (meta_surface, analysis);
if (status == CAIRO_STATUS_SUCCESS) if (status == CAIRO_STATUS_SUCCESS)
@ -90,10 +92,30 @@ _cairo_analysis_surface_add_operation (cairo_analysis_surface_t *surface,
cairo_int_status_t backend_status) cairo_int_status_t backend_status)
{ {
cairo_int_status_t status; cairo_int_status_t status;
cairo_box_t bbox;
if (rect->width == 0 || rect->height == 0) if (rect->width == 0 || rect->height == 0)
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
bbox.p1.x = _cairo_fixed_from_int (rect->x);
bbox.p1.y = _cairo_fixed_from_int (rect->y);
bbox.p2.x = _cairo_fixed_from_int (rect->x + rect->width);
bbox.p2.y = _cairo_fixed_from_int (rect->y + rect->height);
if (surface->first_op) {
surface->first_op = FALSE;
surface->page_bbox = bbox;
} else {
if (bbox.p1.x < surface->page_bbox.p1.x)
surface->page_bbox.p1.x = bbox.p1.x;
if (bbox.p1.y < surface->page_bbox.p1.y)
surface->page_bbox.p1.y = bbox.p1.y;
if (bbox.p2.x > surface->page_bbox.p2.x)
surface->page_bbox.p2.x = bbox.p2.x;
if (bbox.p2.y > surface->page_bbox.p2.y)
surface->page_bbox.p2.y = bbox.p2.y;
}
/* If the operation is completely enclosed within the fallback /* If the operation is completely enclosed within the fallback
* region there is no benefit in emitting a native operation as * region there is no benefit in emitting a native operation as
* the fallback image will be painted on top. * the fallback image will be painted on top.
@ -557,6 +579,7 @@ _cairo_analysis_surface_create (cairo_surface_t *target,
surface->height = height; surface->height = height;
surface->target = target; surface->target = target;
surface->first_op = TRUE;
surface->has_supported = FALSE; surface->has_supported = FALSE;
surface->has_unsupported = FALSE; surface->has_unsupported = FALSE;
_cairo_region_init (&surface->supported_region); _cairo_region_init (&surface->supported_region);
@ -569,7 +592,7 @@ _cairo_analysis_surface_create (cairo_surface_t *target,
return &surface->base; return &surface->base;
FAIL: FAIL:
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
} }
@ -604,3 +627,12 @@ _cairo_analysis_surface_has_unsupported (cairo_surface_t *abstract_surface)
return surface->has_unsupported; return surface->has_unsupported;
} }
void
_cairo_analysis_surface_get_bounding_box (cairo_surface_t *abstract_surface,
cairo_box_t *bbox)
{
cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
*bbox = surface->page_bbox;
}

View File

@ -133,17 +133,18 @@ _cairo_array_grow_by (cairo_array_t *array, int additional)
if (array->elements == NULL) { if (array->elements == NULL) {
array->elements = malloc (sizeof (char *)); array->elements = malloc (sizeof (char *));
if (array->elements == NULL) if (array->elements == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
*array->elements = NULL; *array->elements = NULL;
} }
array->size = new_size; array->size = new_size;
new_elements = realloc (*array->elements, new_elements = _cairo_realloc_ab (*array->elements,
array->size * array->element_size); array->size, array->element_size);
if (new_elements == NULL) { if (new_elements == NULL) {
array->size = old_size; array->size = old_size;
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
*array->elements = new_elements; *array->elements = new_elements;

View File

@ -0,0 +1,103 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef CAIRO_ATOMIC_PRIVATE_H
#define CAIRO_ATOMIC_PRIVATE_H
#if HAVE_CONFIG_H
#include "config.h"
#endif
CAIRO_BEGIN_DECLS
#define CAIRO_HAS_ATOMIC_OPS 1
#if CAIRO_HAS_INTEL_ATOMIC_PRIMITIVES
typedef int cairo_atomic_int_t;
# define _cairo_atomic_int_inc(x) ((void) __sync_fetch_and_add(x, 1))
# define _cairo_atomic_int_dec_and_test(x) (__sync_fetch_and_add(x, -1) == 1)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) __sync_val_compare_and_swap (x, oldv, newv)
#else
# include "cairo-compiler-private.h"
# undef CAIRO_HAS_ATOMIC_OPS
typedef int cairo_atomic_int_t;
cairo_private void
_cairo_atomic_int_inc (int *x);
cairo_private cairo_bool_t
_cairo_atomic_int_dec_and_test (int *x);
cairo_private int
_cairo_atomic_int_cmpxchg (int *x, int oldv, int newv);
#endif
#ifdef CAIRO_ATOMIC_OP_NEEDS_MEMORY_BARRIER
# include "cairo-compiler-private.h"
cairo_private int
_cairo_atomic_int_get (int *x);
cairo_private void
_cairo_atomic_int_set (int *x, int value);
#else
# define _cairo_atomic_int_get(x) (*x)
# define _cairo_atomic_int_set(x, value) ((*x) = value)
#endif
#define _cairo_status_set_error(status, err) do { \
/* hide compiler warnings about cairo_status_t != int (gcc treats its as \
* an unsigned integer instead, and about ignoring the return value. */ \
int ret__ = _cairo_atomic_int_cmpxchg ((int *) status, CAIRO_STATUS_SUCCESS, err); \
(void) ret__; \
} while (0)
CAIRO_END_DECLS
#endif

View File

@ -0,0 +1,96 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairoint.h"
#include "cairo-atomic-private.h"
#include "cairo-mutex-private.h"
#ifndef CAIRO_HAS_ATOMIC_OPS
void
_cairo_atomic_int_inc (int *x)
{
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
*x += 1;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
}
cairo_bool_t
_cairo_atomic_int_dec_and_test (int *x)
{
cairo_bool_t ret;
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
ret = --*x == 0;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
return ret;
}
int
_cairo_atomic_int_cmpxchg (int *x, int oldv, int newv)
{
int ret;
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
ret = *x;
if (ret == oldv)
*x = newv;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
return ret;
}
#endif
#ifdef CAIRO_ATOMIC_OP_NEEDS_MEMORY_BARRIER
int
_cairo_atomic_int_get (int *x)
{
int ret;
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
ret = *x;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
return ret;
}
void
_cairo_atomic_int_set (int *x, int value)
{
CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
*x = value;
CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
}
#endif

View File

@ -40,12 +40,6 @@
#include "cairo-atsui.h" #include "cairo-atsui.h"
#include "cairo-quartz-private.h" #include "cairo-quartz-private.h"
/* 10.5 SDK includes a funky new definition of FloatToFixed, so reset to old-style definition */
#ifdef FloatToFixed
#undef FloatToFixed
#define FloatToFixed(a) ((Fixed)((float)(a) * fixed1))
#endif
/* /*
* FixedToFloat/FloatToFixed are 10.3+ SDK items - include definitions * FixedToFloat/FloatToFixed are 10.3+ SDK items - include definitions
* here so we can use older SDKs. * here so we can use older SDKs.
@ -69,6 +63,9 @@
/* Public in 10.4, present in 10.3.9 */ /* Public in 10.4, present in 10.3.9 */
CG_EXTERN CGRect CGRectApplyAffineTransform (CGRect, CGAffineTransform); CG_EXTERN CGRect CGRectApplyAffineTransform (CGRect, CGAffineTransform);
/* Error code for path callbacks */
static OSStatus CAIRO_CG_PATH_ERROR = 1001;
typedef struct _cairo_atsui_font_face cairo_atsui_font_face_t; typedef struct _cairo_atsui_font_face cairo_atsui_font_face_t;
typedef struct _cairo_atsui_font cairo_atsui_font_t; typedef struct _cairo_atsui_font cairo_atsui_font_t;
typedef struct _cairo_atsui_scaled_path cairo_atsui_scaled_path_t; typedef struct _cairo_atsui_scaled_path cairo_atsui_scaled_path_t;
@ -90,7 +87,6 @@ struct _cairo_atsui_font {
Fixed size; Fixed size;
CGAffineTransform font_matrix; CGAffineTransform font_matrix;
CGFontRef cgfref;
}; };
struct _cairo_atsui_font_face { struct _cairo_atsui_font_face {
@ -115,6 +111,7 @@ _cairo_atsui_font_face_scaled_font_create (void *abstract_face,
const cairo_font_options_t *options, const cairo_font_options_t *options,
cairo_scaled_font_t **font) cairo_scaled_font_t **font)
{ {
cairo_status_t status;
cairo_atsui_font_face_t *font_face = abstract_face; cairo_atsui_font_face_t *font_face = abstract_face;
OSStatus err; OSStatus err;
ATSUAttributeTag styleTags[] = { kATSUFontTag }; ATSUAttributeTag styleTags[] = { kATSUFontTag };
@ -123,11 +120,22 @@ _cairo_atsui_font_face_scaled_font_create (void *abstract_face,
ATSUStyle style; ATSUStyle style;
err = ATSUCreateStyle (&style); err = ATSUCreateStyle (&style);
if (err != noErr)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
err = ATSUSetAttributes(style, ARRAY_LENGTH (styleTags), err = ATSUSetAttributes(style, ARRAY_LENGTH (styleTags),
styleTags, styleSizes, styleValues); styleTags, styleSizes, styleValues);
if (err != noErr) {
ATSUDisposeStyle (style);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
return _cairo_atsui_font_create_scaled (&font_face->base, font_face->font_id, style, status = _cairo_atsui_font_create_scaled (&font_face->base, font_face->font_id, style,
font_matrix, ctm, options, font); font_matrix, ctm, options, font);
if (status)
ATSUDisposeStyle (style);
return status;
} }
static const cairo_font_face_backend_t _cairo_atsui_font_face_backend = { static const cairo_font_face_backend_t _cairo_atsui_font_face_backend = {
@ -167,30 +175,35 @@ cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id)
return &font_face->base; return &font_face->base;
} }
static ATSUStyle static OSStatus
CreateSizedCopyOfStyle(ATSUStyle inStyle, CreateSizedCopyOfStyle(ATSUStyle inStyle,
const Fixed *theSize, const Fixed *theSize,
const CGAffineTransform *theTransform) const CGAffineTransform *theTransform,
ATSUStyle *style)
{ {
ATSUStyle style;
OSStatus err; OSStatus err;
const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag, const ATSUAttributeTag theFontStyleTags[] = { kATSUSizeTag,
kATSUFontMatrixTag }; kATSUFontMatrixTag };
const ByteCount theFontStyleSizes[] = { sizeof(Fixed), const ByteCount theFontStyleSizes[] = { sizeof(Fixed),
sizeof(CGAffineTransform) }; sizeof(CGAffineTransform) };
ATSUAttributeValuePtr theFontStyleValues[] = { (Fixed *)theSize, ATSUAttributeValuePtr theFontStyleValues[] = { (Fixed *)theSize,
(CGAffineTransform *)theTransform }; (CGAffineTransform *)theTransform };
err = ATSUCreateAndCopyStyle(inStyle, &style); err = ATSUCreateAndCopyStyle (inStyle, style);
if (err != noErr)
return err;
err = ATSUSetAttributes(style, err = ATSUSetAttributes(*style,
sizeof(theFontStyleTags) / sizeof(theFontStyleTags) /
sizeof(ATSUAttributeTag), theFontStyleTags, sizeof(ATSUAttributeTag), theFontStyleTags,
theFontStyleSizes, theFontStyleValues); theFontStyleSizes, theFontStyleValues);
if (err != noErr)
ATSUDisposeStyle (*style);
return style; return err;
} }
static cairo_status_t static cairo_status_t
_cairo_atsui_font_set_metrics (cairo_atsui_font_t *font) _cairo_atsui_font_set_metrics (cairo_atsui_font_t *font)
{ {
@ -208,7 +221,7 @@ _cairo_atsui_font_set_metrics (cairo_atsui_font_t *font)
extents.ascent = metrics.ascent; extents.ascent = metrics.ascent;
extents.descent = -metrics.descent; extents.descent = -metrics.descent;
extents.height = metrics.capHeight; extents.height = extents.ascent + extents.descent + metrics.leading;
extents.max_x_advance = metrics.maxAdvanceWidth; 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. */
@ -220,7 +233,7 @@ _cairo_atsui_font_set_metrics (cairo_atsui_font_t *font)
} }
} }
return CAIRO_STATUS_NULL_POINTER; return _cairo_error (CAIRO_STATUS_NULL_POINTER);
} }
static cairo_status_t static cairo_status_t
@ -240,7 +253,7 @@ _cairo_atsui_font_create_scaled (cairo_font_face_t *font_face,
font = malloc(sizeof(cairo_atsui_font_t)); font = malloc(sizeof(cairo_atsui_font_t));
if (font == NULL) if (font == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_scaled_font_init (&font->base, status = _cairo_scaled_font_init (&font->base,
font_face, font_matrix, ctm, options, font_face, font_matrix, ctm, options,
@ -257,7 +270,12 @@ _cairo_atsui_font_create_scaled (cairo_font_face_t *font_face,
0., 0.); 0., 0.);
font->size = FloatToFixed (xscale); font->size = FloatToFixed (xscale);
font->style = CreateSizedCopyOfStyle (style, &font->size, &font->font_matrix); err = CreateSizedCopyOfStyle (style, &font->size, &font->font_matrix, &font->style);
if (err != noErr) {
_cairo_error (CAIRO_STATUS_NO_MEMORY);
status = CAIRO_STATUS_NO_MEMORY;
goto FAIL;
}
{ {
Fixed theSize = FloatToFixed(1.0); Fixed theSize = FloatToFixed(1.0);
@ -270,7 +288,7 @@ _cairo_atsui_font_create_scaled (cairo_font_face_t *font_face,
sizeof(ATSUAttributeTag), theFontStyleTags, sizeof(ATSUAttributeTag), theFontStyleTags,
theFontStyleSizes, theFontStyleValues); theFontStyleSizes, theFontStyleValues);
if (err != noErr) { if (err != noErr) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FAIL; goto FAIL;
} }
} }
@ -282,11 +300,14 @@ _cairo_atsui_font_create_scaled (cairo_font_face_t *font_face,
status = _cairo_atsui_font_set_metrics (font); status = _cairo_atsui_font_set_metrics (font);
font->cgfref = NULL;
FAIL: FAIL:
if (status) { if (status) {
cairo_scaled_font_destroy (&font->base); if (font) {
if (font->style)
ATSUDisposeStyle(font->style);
free (font);
}
return status; return status;
} }
@ -300,6 +321,7 @@ _cairo_atsui_font_create_toy(cairo_toy_font_face_t *toy_face,
const cairo_font_options_t *options, const cairo_font_options_t *options,
cairo_scaled_font_t **font_out) cairo_scaled_font_t **font_out)
{ {
cairo_status_t status;
ATSUStyle style; ATSUStyle style;
ATSUFontID fontID; ATSUFontID fontID;
OSStatus err; OSStatus err;
@ -308,6 +330,9 @@ _cairo_atsui_font_create_toy(cairo_toy_font_face_t *toy_face,
const char *full_name; const char *full_name;
err = ATSUCreateStyle(&style); err = ATSUCreateStyle(&style);
if (err != noErr) {
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
switch (toy_face->weight) { switch (toy_face->weight) {
case CAIRO_FONT_WEIGHT_BOLD: case CAIRO_FONT_WEIGHT_BOLD:
@ -381,6 +406,10 @@ _cairo_atsui_font_create_toy(cairo_toy_font_face_t *toy_face,
kFontNoPlatformCode, kFontNoPlatformCode,
kFontRomanScript, kFontRomanScript,
kFontNoLanguageCode, &fontID); kFontNoLanguageCode, &fontID);
if (err != noErr) {
ATSUDisposeStyle (style);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
} }
} }
@ -393,10 +422,18 @@ _cairo_atsui_font_create_toy(cairo_toy_font_face_t *toy_face,
err = ATSUSetAttributes(style, ARRAY_LENGTH (styleTags), err = ATSUSetAttributes(style, ARRAY_LENGTH (styleTags),
styleTags, styleSizes, styleValues); styleTags, styleSizes, styleValues);
if (err != noErr) {
ATSUDisposeStyle (style);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
} }
return _cairo_atsui_font_create_scaled (&toy_face->base, fontID, style, status = _cairo_atsui_font_create_scaled (&toy_face->base, fontID, style,
font_matrix, ctm, options, font_out); font_matrix, ctm, options, font_out);
if (status)
ATSUDisposeStyle (style);
return status;
} }
static void static void
@ -411,9 +448,6 @@ _cairo_atsui_font_fini(void *abstract_font)
ATSUDisposeStyle(font->style); ATSUDisposeStyle(font->style);
if (font->unscaled_style) if (font->unscaled_style)
ATSUDisposeStyle(font->unscaled_style); ATSUDisposeStyle(font->unscaled_style);
if (font->cgfref)
CGFontRelease(font->cgfref);
} }
static GlyphID static GlyphID
@ -448,7 +482,7 @@ _cairo_atsui_font_init_glyph_metrics (cairo_atsui_font_t *scaled_font,
1, &theGlyph, 0, false, 1, &theGlyph, 0, false,
false, &metricsH); false, &metricsH);
if (err != noErr) if (err != noErr)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
/* Scale down to font units.*/ /* Scale down to font units.*/
_cairo_matrix_compute_scale_factors (&scaled_font->base.scale, _cairo_matrix_compute_scale_factors (&scaled_font->base.scale,
@ -474,15 +508,21 @@ static OSStatus
_move_to (const Float32Point *point, _move_to (const Float32Point *point,
void *callback_data) void *callback_data)
{ {
cairo_status_t status;
cairo_atsui_scaled_path_t *scaled_path = callback_data; cairo_atsui_scaled_path_t *scaled_path = callback_data;
double x = point->x; double x = point->x;
double y = point->y; double y = point->y;
cairo_matrix_transform_point (scaled_path->scale, &x, &y); cairo_matrix_transform_point (scaled_path->scale, &x, &y);
_cairo_path_fixed_close_path (scaled_path->path); status = _cairo_path_fixed_close_path (scaled_path->path);
_cairo_path_fixed_move_to (scaled_path->path, if (status)
return CAIRO_CG_PATH_ERROR;
status = _cairo_path_fixed_move_to (scaled_path->path,
_cairo_fixed_from_double (x), _cairo_fixed_from_double (x),
_cairo_fixed_from_double (y)); _cairo_fixed_from_double (y));
if (status)
return CAIRO_CG_PATH_ERROR;
return noErr; return noErr;
} }
@ -491,15 +531,18 @@ static OSStatus
_line_to (const Float32Point *point, _line_to (const Float32Point *point,
void *callback_data) void *callback_data)
{ {
cairo_status_t status;
cairo_atsui_scaled_path_t *scaled_path = callback_data; cairo_atsui_scaled_path_t *scaled_path = callback_data;
double x = point->x; double x = point->x;
double y = point->y; double y = point->y;
cairo_matrix_transform_point (scaled_path->scale, &x, &y); cairo_matrix_transform_point (scaled_path->scale, &x, &y);
_cairo_path_fixed_line_to (scaled_path->path, status = _cairo_path_fixed_line_to (scaled_path->path,
_cairo_fixed_from_double (x), _cairo_fixed_from_double (x),
_cairo_fixed_from_double (y)); _cairo_fixed_from_double (y));
if (status)
return CAIRO_CG_PATH_ERROR;
return noErr; return noErr;
} }
@ -510,6 +553,7 @@ _curve_to (const Float32Point *point1,
const Float32Point *point3, const Float32Point *point3,
void *callback_data) void *callback_data)
{ {
cairo_status_t status;
cairo_atsui_scaled_path_t *scaled_path = callback_data; cairo_atsui_scaled_path_t *scaled_path = callback_data;
double x1 = point1->x; double x1 = point1->x;
double y1 = point1->y; double y1 = point1->y;
@ -522,13 +566,15 @@ _curve_to (const Float32Point *point1,
cairo_matrix_transform_point (scaled_path->scale, &x2, &y2); cairo_matrix_transform_point (scaled_path->scale, &x2, &y2);
cairo_matrix_transform_point (scaled_path->scale, &x3, &y3); cairo_matrix_transform_point (scaled_path->scale, &x3, &y3);
_cairo_path_fixed_curve_to (scaled_path->path, status = _cairo_path_fixed_curve_to (scaled_path->path,
_cairo_fixed_from_double (x1), _cairo_fixed_from_double (x1),
_cairo_fixed_from_double (y1), _cairo_fixed_from_double (y1),
_cairo_fixed_from_double (x2), _cairo_fixed_from_double (x2),
_cairo_fixed_from_double (y2), _cairo_fixed_from_double (y2),
_cairo_fixed_from_double (x3), _cairo_fixed_from_double (x3),
_cairo_fixed_from_double (y3)); _cairo_fixed_from_double (y3));
if (status)
return CAIRO_CG_PATH_ERROR;
return noErr; return noErr;
} }
@ -537,9 +583,12 @@ static OSStatus
_close_path (void *callback_data) _close_path (void *callback_data)
{ {
cairo_status_t status;
cairo_atsui_scaled_path_t *scaled_path = callback_data; cairo_atsui_scaled_path_t *scaled_path = callback_data;
_cairo_path_fixed_close_path (scaled_path->path); status = _cairo_path_fixed_close_path (scaled_path->path);
if (status)
return CAIRO_CG_PATH_ERROR;
return noErr; return noErr;
} }
@ -562,7 +611,7 @@ _cairo_atsui_scaled_font_init_glyph_path (cairo_atsui_font_t *scaled_font,
scaled_path.path = _cairo_path_fixed_create (); scaled_path.path = _cairo_path_fixed_create ();
if (!scaled_path.path) if (!scaled_path.path)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (theGlyph == kATSDeletedGlyphcode) { if (theGlyph == kATSDeletedGlyphcode) {
_cairo_scaled_glyph_set_path (scaled_glyph, &scaled_font->base, _cairo_scaled_glyph_set_path (scaled_glyph, &scaled_font->base,
@ -595,6 +644,10 @@ _cairo_atsui_scaled_font_init_glyph_path (cairo_atsui_font_t *scaled_font,
lineProc, lineProc,
curveProc, curveProc,
closePathProc, (void *)&scaled_path, &err); closePathProc, (void *)&scaled_path, &err);
if (err != noErr) {
_cairo_path_fixed_destroy (scaled_path.path);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
_cairo_scaled_glyph_set_path (scaled_glyph, &scaled_font->base, _cairo_scaled_glyph_set_path (scaled_glyph, &scaled_font->base,
scaled_path.path); scaled_path.path);
@ -658,6 +711,10 @@ _cairo_atsui_scaled_font_init_glyph_surface (cairo_atsui_font_t *scaled_font,
err = ATSUGlyphGetScreenMetrics (scaled_font->style, err = ATSUGlyphGetScreenMetrics (scaled_font->style,
1, &theGlyph, 0, false, 1, &theGlyph, 0, false,
false, &metricsH); false, &metricsH);
if (err != noErr) {
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
left = metricsH.sideBearing.x - 1.0; left = metricsH.sideBearing.x - 1.0;
width = metricsH.deviceAdvance.x width = metricsH.deviceAdvance.x
- metricsH.sideBearing.x - metricsH.sideBearing.x
@ -715,7 +772,7 @@ _cairo_atsui_scaled_font_init_glyph_surface (cairo_atsui_font_t *scaled_font,
if (!drawingContext) { if (!drawingContext) {
cairo_surface_destroy ((cairo_surface_t *)surface); cairo_surface_destroy ((cairo_surface_t *)surface);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
atsFont = FMGetATSFontRefFromFont (scaled_font->fontID); atsFont = FMGetATSFontRefFromFont (scaled_font->fontID);
@ -803,29 +860,45 @@ _cairo_atsui_font_text_to_glyphs (void *abstract_font,
status = _cairo_utf8_to_utf16 ((unsigned char *)utf8, -1, &utf16, &n16); status = _cairo_utf8_to_utf16 ((unsigned char *)utf8, -1, &utf16, &n16);
if (status) if (status)
return status; goto BAIL3;
err = ATSUCreateTextLayout(&textLayout); err = ATSUCreateTextLayout(&textLayout);
if (err != noErr) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL3;
}
err = ATSUSetTextPointerLocation(textLayout, utf16, 0, n16, n16); err = ATSUSetTextPointerLocation(textLayout, utf16, 0, n16, n16);
if (err != noErr) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL2;
}
/* Set the style for all of the text */ /* Set the style for all of the text */
err = ATSUSetRunStyle(textLayout, err = ATSUSetRunStyle(textLayout,
font->style, kATSUFromTextBeginning, kATSUToTextEnd); font->style, kATSUFromTextBeginning, kATSUToTextEnd);
if (err != noErr) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL2;
}
err = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout, err = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(textLayout,
0, 0,
kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
(void *)&layoutRecords, (void *)&layoutRecords,
&glyphCount); &glyphCount);
if (err != noErr) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL2;
}
*num_glyphs = glyphCount - 1; *num_glyphs = glyphCount - 1;
*glyphs = *glyphs =
(cairo_glyph_t *) _cairo_malloc_ab(*num_glyphs, sizeof (cairo_glyph_t)); (cairo_glyph_t *) _cairo_malloc_ab(*num_glyphs, sizeof (cairo_glyph_t));
if (*glyphs == NULL) { if (*glyphs == NULL) {
return CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL1;
} }
_cairo_matrix_compute_scale_factors (&font->base.ctm, &xscale, &yscale, 1); _cairo_matrix_compute_scale_factors (&font->base.ctm, &xscale, &yscale, 1);
device_to_user_scale = device_to_user_scale =
CGAffineTransformInvert (CGAffineTransformMake (xscale, 0, CGAffineTransformInvert (CGAffineTransformMake (xscale, 0,
@ -841,14 +914,17 @@ _cairo_atsui_font_text_to_glyphs (void *abstract_font,
(*glyphs)[i].y = y; (*glyphs)[i].y = y;
} }
free (utf16); BAIL1:
/* TODO ignored return value. Is there anything we should do? */
ATSUDirectReleaseLayoutDataArrayPtr(NULL, ATSUDirectReleaseLayoutDataArrayPtr(NULL,
kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
(void *) &layoutRecords); (void *) &layoutRecords);
BAIL2:
ATSUDisposeTextLayout(textLayout); ATSUDisposeTextLayout(textLayout);
BAIL3:
free (utf16);
return CAIRO_STATUS_SUCCESS; return status;
} }
ATSUStyle ATSUStyle
@ -867,19 +943,6 @@ _cairo_atsui_scaled_font_get_atsu_font_id (cairo_scaled_font_t *sfont)
return afont->fontID; return afont->fontID;
} }
CGFontRef
_cairo_atsui_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont)
{
cairo_atsui_font_t *afont = (cairo_atsui_font_t *) sfont;
if (!afont->cgfref) {
ATSFontRef atsfref = FMGetATSFontRefFromFont (afont->fontID);
afont->cgfref = CGFontCreateWithPlatformFont (&atsfref);
}
return afont->cgfref;
}
static cairo_int_status_t static cairo_int_status_t
_cairo_atsui_load_truetype_table (void *abstract_font, _cairo_atsui_load_truetype_table (void *abstract_font,
unsigned long tag, unsigned long tag,

View File

@ -114,8 +114,10 @@ _cairo_base85_stream_create (cairo_output_stream_t *output)
cairo_base85_stream_t *stream; cairo_base85_stream_t *stream;
stream = malloc (sizeof (cairo_base85_stream_t)); stream = malloc (sizeof (cairo_base85_stream_t));
if (stream == NULL) if (stream == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil; return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base, _cairo_output_stream_init (&stream->base,
_cairo_base85_stream_write, _cairo_base85_stream_write,

View File

@ -701,7 +701,7 @@ _cairo_bo_event_queue_insert (cairo_bo_event_queue_t *queue,
/* Don't insert if there's already an equivalent intersection event in the queue. */ /* Don't insert if there's already an equivalent intersection event in the queue. */
if (_cairo_skip_list_insert (&queue->intersection_queue, event, if (_cairo_skip_list_insert (&queue->intersection_queue, event,
event->type == CAIRO_BO_EVENT_TYPE_INTERSECTION) == NULL) event->type == CAIRO_BO_EVENT_TYPE_INTERSECTION) == NULL)
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return status; return status;
} }
@ -756,7 +756,7 @@ _cairo_bo_event_queue_init (cairo_bo_event_queue_t *event_queue,
* elt? */ * elt? */
events = _cairo_malloc_ab (num_events, sizeof (cairo_bo_event_t) + sizeof(cairo_bo_event_t*)); events = _cairo_malloc_ab (num_events, sizeof (cairo_bo_event_t) + sizeof(cairo_bo_event_t*));
if (events == NULL) if (events == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
sorted_event_ptrs = (cairo_bo_event_t **) (events + num_events); sorted_event_ptrs = (cairo_bo_event_t **) (events + num_events);
event_queue->startstop_events = events; event_queue->startstop_events = events;
@ -859,7 +859,7 @@ _cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line,
sweep_line_elt = _cairo_skip_list_insert (&sweep_line->active_edges, &edge, sweep_line_elt = _cairo_skip_list_insert (&sweep_line->active_edges, &edge,
1 /* unique inserts*/); 1 /* unique inserts*/);
if (sweep_line_elt == NULL) if (sweep_line_elt == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
next_elt = sweep_line_elt->elt.next[0]; next_elt = sweep_line_elt->elt.next[0];
if (next_elt) if (next_elt)
@ -1147,7 +1147,7 @@ _cairo_bo_edge_start_or_continue_trap (cairo_bo_edge_t *edge,
if (edge->next) { if (edge->next) {
trap = edge->deferred_trap = _cairo_freelist_alloc (&bo_traps->freelist); trap = edge->deferred_trap = _cairo_freelist_alloc (&bo_traps->freelist);
if (!edge->deferred_trap) if (!edge->deferred_trap)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
trap->right = edge->next; trap->right = edge->next;
trap->top = top; trap->top = top;
@ -1438,7 +1438,7 @@ _cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps,
} else { } else {
edges = _cairo_malloc_ab (polygon->num_edges, sizeof (cairo_bo_edge_t)); edges = _cairo_malloc_ab (polygon->num_edges, sizeof (cairo_bo_edge_t));
if (edges == NULL) if (edges == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
/* Figure out the bounding box of the input coordinates and /* Figure out the bounding box of the input coordinates and

View File

@ -39,6 +39,7 @@
#ifndef CAIRO_CACHE_PRIVATE_H #ifndef CAIRO_CACHE_PRIVATE_H
#define CAIRO_CACHE_PRIVATE_H #define CAIRO_CACHE_PRIVATE_H
#include "cairo-compiler-private.h"
#include "cairo-types-private.h" #include "cairo-types-private.h"
/** /**

View File

@ -54,7 +54,7 @@ _cairo_cache_init (cairo_cache_t *cache,
{ {
cache->hash_table = _cairo_hash_table_create (keys_equal); cache->hash_table = _cairo_hash_table_create (keys_equal);
if (cache->hash_table == NULL) if (cache->hash_table == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
cache->entry_destroy = entry_destroy; cache->entry_destroy = entry_destroy;
@ -131,8 +131,10 @@ _cairo_cache_create (cairo_cache_keys_equal_func_t keys_equal,
cairo_cache_t *cache; cairo_cache_t *cache;
cache = malloc (sizeof (cairo_cache_t)); cache = malloc (sizeof (cairo_cache_t));
if (cache == NULL) if (cache == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
}
status = _cairo_cache_init (cache, keys_equal, entry_destroy, max_size); status = _cairo_cache_init (cache, keys_equal, entry_destroy, max_size);
if (status) { if (status) {

View File

@ -385,15 +385,23 @@ cff_index_append_copy (cairo_array_t *index,
unsigned int length) unsigned int length)
{ {
cff_index_element_t element; cff_index_element_t element;
cairo_status_t status;
element.length = length; element.length = length;
element.is_copy = TRUE; element.is_copy = TRUE;
element.data = malloc (element.length); element.data = malloc (element.length);
if (element.data == NULL) if (element.data == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (element.data, object, element.length); memcpy (element.data, object, element.length);
return _cairo_array_append (index, &element); status = _cairo_array_append (index, &element);
if (status) {
free (element.data);
return status;
}
return CAIRO_STATUS_SUCCESS;
} }
static void static void
@ -419,10 +427,14 @@ _cairo_cff_dict_equal (const void *key_a, const void *key_b)
return op_a->operator == op_b->operator; return op_a->operator == op_b->operator;
} }
static void static cairo_status_t
cff_dict_init (cairo_hash_table_t **dict) cff_dict_init (cairo_hash_table_t **dict)
{ {
*dict = _cairo_hash_table_create (_cairo_cff_dict_equal); *dict = _cairo_hash_table_create (_cairo_cff_dict_equal);
if (*dict == NULL)
return CAIRO_STATUS_NO_MEMORY;
return CAIRO_STATUS_SUCCESS;
} }
static void static void
@ -440,12 +452,16 @@ cff_dict_create_operator (int operator,
cff_dict_operator_t *op; cff_dict_operator_t *op;
op = malloc (sizeof (cff_dict_operator_t)); op = malloc (sizeof (cff_dict_operator_t));
if (op == NULL) if (op == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
}
_cairo_dict_init_key (op, operator); _cairo_dict_init_key (op, operator);
op->operand = malloc (operand_length); op->operand = malloc (operand_length);
if (op->operand == NULL) { if (op->operand == NULL) {
free (op); free (op);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
} }
memcpy (op->operand, operand, operand_length); memcpy (op->operand, operand, operand_length);
@ -480,7 +496,7 @@ cff_dict_read (cairo_hash_table_t *dict, unsigned char *p, int dict_size)
_cairo_array_index (&operands, 0), _cairo_array_index (&operands, 0),
_cairo_array_num_elements (&operands)); _cairo_array_num_elements (&operands));
if (op == NULL) { if (op == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail; goto fail;
} }
status = _cairo_hash_table_insert (dict, &op->base); status = _cairo_hash_table_insert (dict, &op->base);
@ -544,8 +560,9 @@ cff_dict_set_operands (cairo_hash_table_t *dict,
{ {
free (op->operand); free (op->operand);
op->operand = malloc (size); op->operand = malloc (size);
if (op->operand == NULL) if (op->operand == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (op->operand, operand, size); memcpy (op->operand, operand, size);
op->operand_length = size; op->operand_length = size;
} }
@ -553,7 +570,8 @@ cff_dict_set_operands (cairo_hash_table_t *dict,
{ {
op = cff_dict_create_operator (operator, operand, size); op = cff_dict_create_operator (operator, operand, size);
if (op == NULL) if (op == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_hash_table_insert (dict, &op->base); status = _cairo_hash_table_insert (dict, &op->base);
if (status) if (status)
return status; return status;
@ -690,6 +708,7 @@ cairo_cff_font_read_private_dict (cairo_cff_font_t *font,
unsigned char *ptr, unsigned char *ptr,
int size) int size)
{ {
cairo_int_status_t status;
unsigned char buf[10]; unsigned char buf[10];
unsigned char *end_buf; unsigned char *end_buf;
int offset; int offset;
@ -697,16 +716,23 @@ cairo_cff_font_read_private_dict (cairo_cff_font_t *font,
unsigned char *operand; unsigned char *operand;
unsigned char *p; unsigned char *p;
cff_dict_read (private_dict, ptr, size); status = cff_dict_read (private_dict, ptr, size);
if (status)
return status;
operand = cff_dict_get_operands (private_dict, LOCAL_SUB_OP, &i); operand = cff_dict_get_operands (private_dict, LOCAL_SUB_OP, &i);
if (operand) { if (operand) {
decode_integer (operand, &offset); decode_integer (operand, &offset);
p = ptr + offset; p = ptr + offset;
cff_index_read (local_sub_index, &p, font->data_end); status = cff_index_read (local_sub_index, &p, font->data_end);
if (status)
return status;
/* Use maximum sized encoding to reserve space for later modification. */ /* Use maximum sized encoding to reserve space for later modification. */
end_buf = encode_integer_max (buf, 0); end_buf = encode_integer_max (buf, 0);
cff_dict_set_operands (private_dict, LOCAL_SUB_OP, buf, end_buf - buf); status = cff_dict_set_operands (private_dict, LOCAL_SUB_OP, buf, end_buf - buf);
if (status)
return status;
} }
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
@ -719,7 +745,7 @@ cairo_cff_font_read_fdselect (cairo_cff_font_t *font, unsigned char *p)
font->fdselect = calloc (font->num_glyphs, sizeof (int)); font->fdselect = calloc (font->num_glyphs, sizeof (int));
if (font->fdselect == NULL) if (font->fdselect == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
type = *p++; type = *p++;
if (type == 0) if (type == 0)
@ -767,28 +793,27 @@ cairo_cff_font_read_cid_fontdict (cairo_cff_font_t *font, unsigned char *ptr)
font->fd_dict = calloc (sizeof (cairo_hash_table_t *), font->num_fontdicts); font->fd_dict = calloc (sizeof (cairo_hash_table_t *), font->num_fontdicts);
if (font->fd_dict == NULL) { if (font->fd_dict == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail; goto fail;
} }
font->fd_private_dict = calloc (sizeof (cairo_hash_table_t *), font->num_fontdicts); font->fd_private_dict = calloc (sizeof (cairo_hash_table_t *), font->num_fontdicts);
if (font->fd_private_dict == NULL) { if (font->fd_private_dict == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail; goto fail;
} }
font->fd_local_sub_index = calloc (sizeof (cairo_array_t), font->num_fontdicts); font->fd_local_sub_index = calloc (sizeof (cairo_array_t), font->num_fontdicts);
if (font->fd_local_sub_index == NULL) { if (font->fd_local_sub_index == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail; goto fail;
} }
for (i = 0; i < font->num_fontdicts; i++) { for (i = 0; i < font->num_fontdicts; i++) {
cff_dict_init (&font->fd_dict[i]); status = cff_dict_init (&font->fd_dict[i]);
if (font->fd_dict[i] == NULL) { if (status)
status = CAIRO_STATUS_NO_MEMORY;
goto fail; goto fail;
}
element = _cairo_array_index (&index, i); element = _cairo_array_index (&index, i);
status = cff_dict_read (font->fd_dict[i], element->data, element->length); status = cff_dict_read (font->fd_dict[i], element->data, element->length);
if (status) if (status)
@ -801,11 +826,10 @@ cairo_cff_font_read_cid_fontdict (cairo_cff_font_t *font, unsigned char *ptr)
} }
operand = decode_integer (operand, &size); operand = decode_integer (operand, &size);
decode_integer (operand, &offset); decode_integer (operand, &offset);
cff_dict_init (&font->fd_private_dict[i]); status = cff_dict_init (&font->fd_private_dict[i]);
if (font->fd_private_dict[i] == NULL) { if (status)
status = CAIRO_STATUS_NO_MEMORY;
goto fail; goto fail;
}
cff_index_init (&font->fd_local_sub_index[i]); cff_index_init (&font->fd_local_sub_index[i]);
status = cairo_cff_font_read_private_dict (font, status = cairo_cff_font_read_private_dict (font,
font->fd_private_dict[i], font->fd_private_dict[i],
@ -828,7 +852,7 @@ cairo_cff_font_read_cid_fontdict (cairo_cff_font_t *font, unsigned char *ptr)
fail: fail:
cff_index_fini (&index); cff_index_fini (&index);
return status; return _cairo_error (status);
} }
static cairo_int_status_t static cairo_int_status_t
@ -870,28 +894,49 @@ cairo_cff_font_read_top_dict (cairo_cff_font_t *font)
if (font->is_cid) { if (font->is_cid) {
operand = cff_dict_get_operands (font->top_dict, FDSELECT_OP, &size); operand = cff_dict_get_operands (font->top_dict, FDSELECT_OP, &size);
decode_integer (operand, &offset); decode_integer (operand, &offset);
cairo_cff_font_read_fdselect (font, font->data + offset); status = cairo_cff_font_read_fdselect (font, font->data + offset);
if (status)
goto fail;
operand = cff_dict_get_operands (font->top_dict, FDARRAY_OP, &size); operand = cff_dict_get_operands (font->top_dict, FDARRAY_OP, &size);
decode_integer (operand, &offset); decode_integer (operand, &offset);
cairo_cff_font_read_cid_fontdict (font, font->data + offset); status = cairo_cff_font_read_cid_fontdict (font, font->data + offset);
if (status)
goto fail;
} else { } else {
operand = cff_dict_get_operands (font->top_dict, PRIVATE_OP, &size); operand = cff_dict_get_operands (font->top_dict, PRIVATE_OP, &size);
operand = decode_integer (operand, &size); operand = decode_integer (operand, &size);
decode_integer (operand, &offset); decode_integer (operand, &offset);
cairo_cff_font_read_private_dict (font, status = cairo_cff_font_read_private_dict (font,
font->private_dict, font->private_dict,
&font->local_sub_index, &font->local_sub_index,
font->data + offset, font->data + offset,
size); size);
if (status)
goto fail;
} }
/* Use maximum sized encoding to reserve space for later modification. */ /* Use maximum sized encoding to reserve space for later modification. */
end_buf = encode_integer_max (buf, 0); end_buf = encode_integer_max (buf, 0);
cff_dict_set_operands (font->top_dict, CHARSTRINGS_OP, buf, end_buf - buf); status = cff_dict_set_operands (font->top_dict,
cff_dict_set_operands (font->top_dict, FDSELECT_OP, buf, end_buf - buf); CHARSTRINGS_OP, buf, end_buf - buf);
cff_dict_set_operands (font->top_dict, FDARRAY_OP, buf, end_buf - buf); if (status)
cff_dict_set_operands (font->top_dict, CHARSET_OP, buf, end_buf - buf); goto fail;
status = cff_dict_set_operands (font->top_dict,
FDSELECT_OP, buf, end_buf - buf);
if (status)
goto fail;
status = cff_dict_set_operands (font->top_dict,
FDARRAY_OP, buf, end_buf - buf);
if (status)
goto fail;
status = cff_dict_set_operands (font->top_dict,
CHARSET_OP, buf, end_buf - buf);
if (status)
goto fail;
cff_dict_remove (font->top_dict, ENCODING_OP); cff_dict_remove (font->top_dict, ENCODING_OP);
cff_dict_remove (font->top_dict, PRIVATE_OP); cff_dict_remove (font->top_dict, PRIVATE_OP);
@ -945,9 +990,10 @@ cairo_cff_font_read_font (cairo_cff_font_t *font)
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
static void static cairo_status_t
cairo_cff_font_set_ros_strings (cairo_cff_font_t *font) cairo_cff_font_set_ros_strings (cairo_cff_font_t *font)
{ {
cairo_status_t status;
unsigned char buf[30]; unsigned char buf[30];
unsigned char *p; unsigned char *p;
int sid1, sid2; int sid1, sid2;
@ -955,22 +1001,32 @@ cairo_cff_font_set_ros_strings (cairo_cff_font_t *font)
const char *ordering = "Identity"; const char *ordering = "Identity";
sid1 = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index); sid1 = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index);
cff_index_append_copy (&font->strings_subset_index, status = cff_index_append_copy (&font->strings_subset_index,
(unsigned char *)registry, (unsigned char *)registry,
strlen(registry)); strlen(registry));
if (status)
return status;
sid2 = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index); sid2 = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index);
cff_index_append_copy (&font->strings_subset_index, status = cff_index_append_copy (&font->strings_subset_index,
(unsigned char *)ordering, (unsigned char *)ordering,
strlen(ordering)); strlen(ordering));
if (status)
return status;
p = encode_integer (buf, sid1); p = encode_integer (buf, sid1);
p = encode_integer (p, sid2); p = encode_integer (p, sid2);
p = encode_integer (p, 0); p = encode_integer (p, 0);
cff_dict_set_operands (font->top_dict, ROS_OP, buf, p - buf); status = cff_dict_set_operands (font->top_dict, ROS_OP, buf, p - buf);
if (status)
return status;
p = encode_integer (buf, font->scaled_font_subset->num_glyphs); p = encode_integer (buf, font->scaled_font_subset->num_glyphs);
cff_dict_set_operands (font->top_dict, CIDCOUNT_OP, buf, p - buf); status = cff_dict_set_operands (font->top_dict, CIDCOUNT_OP, buf, p - buf);
if (status)
return status;
return CAIRO_STATUS_SUCCESS;
} }
static cairo_status_t static cairo_status_t
@ -1000,7 +1056,9 @@ cairo_cff_font_subset_dict_string(cairo_cff_font_t *font,
return status; return status;
p = encode_integer (buf, sid); p = encode_integer (buf, sid);
cff_dict_set_operands (dict, operator, buf, p - buf); status = cff_dict_set_operands (dict, operator, buf, p - buf);
if (status)
return status;
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -1063,19 +1121,19 @@ cairo_cff_font_subset_fontdict (cairo_cff_font_t *font)
font->fdselect_subset = calloc (font->scaled_font_subset->num_glyphs, font->fdselect_subset = calloc (font->scaled_font_subset->num_glyphs,
sizeof (int)); sizeof (int));
if (font->fdselect_subset == NULL) if (font->fdselect_subset == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font->fd_subset_map = calloc (font->num_fontdicts, sizeof (int)); font->fd_subset_map = calloc (font->num_fontdicts, sizeof (int));
if (font->fd_subset_map == NULL) if (font->fd_subset_map == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font->private_dict_offset = calloc (font->num_fontdicts, sizeof (int)); font->private_dict_offset = calloc (font->num_fontdicts, sizeof (int));
if (font->private_dict_offset == NULL) if (font->private_dict_offset == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
reverse_map = calloc (font->num_fontdicts, sizeof (int)); reverse_map = calloc (font->num_fontdicts, sizeof (int));
if (reverse_map == NULL) if (reverse_map == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
for (i = 0; i < font->num_fontdicts; i++) for (i = 0; i < font->num_fontdicts; i++)
reverse_map[i] = -1; reverse_map[i] = -1;
@ -1100,21 +1158,27 @@ cairo_cff_font_create_cid_fontdict (cairo_cff_font_t *font)
{ {
unsigned char buf[100]; unsigned char buf[100];
unsigned char *end_buf; unsigned char *end_buf;
cairo_status_t status;
font->num_fontdicts = 1; font->num_fontdicts = 1;
font->fd_dict = malloc (sizeof (cairo_hash_table_t *)); font->fd_dict = malloc (sizeof (cairo_hash_table_t *));
if (font->fd_dict == NULL) if (font->fd_dict == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
cff_dict_init (&font->fd_dict[0]); if (cff_dict_init (&font->fd_dict[0])) {
free (font->fd_dict);
font->fd_dict = NULL;
font->num_fontdicts = 0;
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
font->fd_subset_map = malloc (sizeof (int)); font->fd_subset_map = malloc (sizeof (int));
if (font->fd_subset_map == NULL) if (font->fd_subset_map == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font->private_dict_offset = malloc (sizeof (int)); font->private_dict_offset = malloc (sizeof (int));
if (font->private_dict_offset == NULL) if (font->private_dict_offset == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font->fd_subset_map[0] = 0; font->fd_subset_map[0] = 0;
font->num_subset_fontdicts = 1; font->num_subset_fontdicts = 1;
@ -1123,7 +1187,9 @@ cairo_cff_font_create_cid_fontdict (cairo_cff_font_t *font)
* space for any value later */ * space for any value later */
end_buf = encode_integer_max (buf, 0); end_buf = encode_integer_max (buf, 0);
end_buf = encode_integer_max (end_buf, 0); end_buf = encode_integer_max (end_buf, 0);
cff_dict_set_operands (font->fd_dict[0], PRIVATE_OP, buf, end_buf - buf); status = cff_dict_set_operands (font->fd_dict[0], PRIVATE_OP, buf, end_buf - buf);
if (status)
return status;
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -1137,6 +1203,7 @@ cairo_cff_font_subset_strings (cairo_cff_font_t *font)
status = cairo_cff_font_subset_dict_strings (font, font->top_dict); status = cairo_cff_font_subset_dict_strings (font, font->top_dict);
if (status) if (status)
return status; return status;
if (font->is_cid) { if (font->is_cid) {
for (i = 0; i < font->num_subset_fontdicts; i++) { for (i = 0; i < font->num_subset_fontdicts; i++) {
status = cairo_cff_font_subset_dict_strings (font, font->fd_dict[font->fd_subset_map[i]]); status = cairo_cff_font_subset_dict_strings (font, font->fd_dict[font->fd_subset_map[i]]);
@ -1159,16 +1226,20 @@ cairo_cff_font_subset_font (cairo_cff_font_t *font)
{ {
cairo_status_t status; cairo_status_t status;
cairo_cff_font_set_ros_strings (font); status = cairo_cff_font_set_ros_strings (font);
if (status)
return status;
status = cairo_cff_font_subset_charstrings (font); status = cairo_cff_font_subset_charstrings (font);
if (status) if (status)
return status; return status;
if (font->is_cid) if (font->is_cid)
cairo_cff_font_subset_fontdict (font); status = cairo_cff_font_subset_fontdict (font);
else else
cairo_cff_font_create_cid_fontdict (font); status = cairo_cff_font_create_cid_fontdict (font);
if (status)
return status;
status = cairo_cff_font_subset_strings (font); status = cairo_cff_font_subset_strings (font);
if (status) if (status)
@ -1211,21 +1282,25 @@ cairo_cff_font_write_header (cairo_cff_font_t *font)
static cairo_status_t static cairo_status_t
cairo_cff_font_write_name (cairo_cff_font_t *font) cairo_cff_font_write_name (cairo_cff_font_t *font)
{ {
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_array_t index; cairo_array_t index;
cairo_status_t status;
cff_index_init (&index); cff_index_init (&index);
status = cff_index_append_copy (&index, status = cff_index_append_copy (&index,
(unsigned char *) font->subset_font_name, (unsigned char *) font->subset_font_name,
strlen(font->subset_font_name)); strlen(font->subset_font_name));
if (status) if (status)
return status; goto FAIL;
status = cff_index_write (&index, &font->output); status = cff_index_write (&index, &font->output);
if (status) if (status)
return status; goto FAIL;
FAIL:
cff_index_fini (&index); cff_index_fini (&index);
return CAIRO_STATUS_SUCCESS; return status;
} }
static cairo_status_t static cairo_status_t
@ -1428,6 +1503,7 @@ cairo_cff_font_write_private_dict (cairo_cff_font_t *font,
status = cff_dict_write (private_dict, &font->output); status = cff_dict_write (private_dict, &font->output);
if (status) if (status)
return status; return status;
size = _cairo_array_num_elements (&font->output) - font->private_dict_offset[dict_num]; size = _cairo_array_num_elements (&font->output) - font->private_dict_offset[dict_num];
/* private entry has two operands - size and offset */ /* private entry has two operands - size and offset */
buf_end = encode_integer_max (buf, size); buf_end = encode_integer_max (buf, size);
@ -1476,7 +1552,7 @@ static cairo_status_t
cairo_cff_font_write_cid_private_dict_and_local_sub (cairo_cff_font_t *font) cairo_cff_font_write_cid_private_dict_and_local_sub (cairo_cff_font_t *font)
{ {
unsigned int i; unsigned int i;
cairo_int_status_t status = CAIRO_STATUS_SUCCESS; cairo_int_status_t status;
if (font->is_cid) { if (font->is_cid) {
for (i = 0; i < font->num_subset_fontdicts; i++) { for (i = 0; i < font->num_subset_fontdicts; i++) {
@ -1503,13 +1579,18 @@ cairo_cff_font_write_cid_private_dict_and_local_sub (cairo_cff_font_t *font)
0, 0,
font->fd_dict[0], font->fd_dict[0],
font->private_dict); font->private_dict);
if (status)
return status;
status = cairo_cff_font_write_local_sub (font, status = cairo_cff_font_write_local_sub (font,
0, 0,
font->private_dict, font->private_dict,
&font->local_sub_index); &font->local_sub_index);
if (status)
return status;
} }
return status; return CAIRO_STATUS_SUCCESS;
} }
typedef cairo_status_t typedef cairo_status_t
@ -1521,8 +1602,8 @@ static const font_write_t font_write_funcs[] = {
cairo_cff_font_write_top_dict, cairo_cff_font_write_top_dict,
cairo_cff_font_write_strings, cairo_cff_font_write_strings,
cairo_cff_font_write_global_subrs, cairo_cff_font_write_global_subrs,
cairo_cff_font_write_fdselect,
cairo_cff_font_write_charset, cairo_cff_font_write_charset,
cairo_cff_font_write_fdselect,
cairo_cff_font_write_charstrings, cairo_cff_font_write_charstrings,
cairo_cff_font_write_cid_fontdict, cairo_cff_font_write_cid_fontdict,
cairo_cff_font_write_cid_private_dict_and_local_sub, cairo_cff_font_write_cid_private_dict_and_local_sub,
@ -1669,7 +1750,8 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
name = malloc (size); name = malloc (size);
if (name == NULL) if (name == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = backend->load_truetype_table (scaled_font_subset->scaled_font, status = backend->load_truetype_table (scaled_font_subset->scaled_font,
TT_TAG_name, 0, TT_TAG_name, 0,
(unsigned char *) name, &size); (unsigned char *) name, &size);
@ -1678,7 +1760,7 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
font = malloc (sizeof (cairo_cff_font_t)); font = malloc (sizeof (cairo_cff_font_t));
if (font == NULL) { if (font == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail1; goto fail1;
} }
@ -1692,8 +1774,8 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
font->subset_font_name = strdup (subset_name); font->subset_font_name = strdup (subset_name);
if (font->subset_font_name == NULL) { if (font->subset_font_name == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3; goto fail2;
} }
font->x_min = (int16_t) be16_to_cpu (head.x_min); font->x_min = (int16_t) be16_to_cpu (head.x_min);
font->y_min = (int16_t) be16_to_cpu (head.y_min); font->y_min = (int16_t) be16_to_cpu (head.y_min);
@ -1728,8 +1810,8 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
if (font->font_name == NULL) { if (font->font_name == NULL) {
font->font_name = malloc (30); font->font_name = malloc (30);
if (font->font_name == NULL) { if (font->font_name == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail4; goto fail3;
} }
snprintf(font->font_name, 30, "CairoFont-%u-%u", snprintf(font->font_name, 30, "CairoFont-%u-%u",
scaled_font_subset->font_id, scaled_font_subset->font_id,
@ -1745,26 +1827,36 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
font->widths = calloc (font->scaled_font_subset->num_glyphs, sizeof (int)); font->widths = calloc (font->scaled_font_subset->num_glyphs, sizeof (int));
if (font->widths == NULL) { if (font->widths == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail5; goto fail4;
} }
cairo_cff_font_create_set_widths (font);
status = cairo_cff_font_create_set_widths (font);
if (status)
goto fail5;
font->data_length = data_length; font->data_length = data_length;
font->data = malloc (data_length); font->data = malloc (data_length);
if (font->data == NULL) { if (font->data == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail6; goto fail5;
} }
status = font->backend->load_truetype_table ( font->scaled_font_subset->scaled_font, status = font->backend->load_truetype_table ( font->scaled_font_subset->scaled_font,
TT_TAG_CFF, 0, font->data, TT_TAG_CFF, 0, font->data,
&font->data_length); &font->data_length);
if (status) if (status)
goto fail7; goto fail6;
font->data_end = font->data + font->data_length; font->data_end = font->data + font->data_length;
cff_dict_init (&font->top_dict); status = cff_dict_init (&font->top_dict);
cff_dict_init (&font->private_dict); if (status)
goto fail6;
status = cff_dict_init (&font->private_dict);
if (status)
goto fail7;
cff_index_init (&font->strings_index); cff_index_init (&font->strings_index);
cff_index_init (&font->charstrings_index); cff_index_init (&font->charstrings_index);
cff_index_init (&font->global_sub_index); cff_index_init (&font->global_sub_index);
@ -1785,20 +1877,21 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
fail7: fail7:
free (font->data); _cairo_hash_table_destroy (font->top_dict);
fail6: fail6:
free (font->widths); free (font->data);
fail5: fail5:
free (font->font_name); free (font->widths);
fail4: fail4:
free (font->subset_font_name); free (font->font_name);
fail3: fail3:
_cairo_array_fini (&font->output); free (font->subset_font_name);
fail2: fail2:
_cairo_array_fini (&font->output);
free (font); free (font);
fail1: fail1:
free (name); free (name);
return status; return _cairo_error (status);
} }
static void static void
@ -1878,12 +1971,16 @@ _cairo_cff_subset_init (cairo_cff_subset_t *cff_subset,
goto fail1; goto fail1;
cff_subset->base_font = strdup (font->font_name); cff_subset->base_font = strdup (font->font_name);
if (cff_subset->base_font == NULL) if (cff_subset->base_font == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail1; goto fail1;
}
cff_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs); cff_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs);
if (cff_subset->widths == NULL) if (cff_subset->widths == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2; goto fail2;
}
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) for (i = 0; i < font->scaled_font_subset->num_glyphs; i++)
cff_subset->widths[i] = font->widths[i]; cff_subset->widths[i] = font->widths[i];
@ -1895,8 +1992,10 @@ _cairo_cff_subset_init (cairo_cff_subset_t *cff_subset,
cff_subset->descent = font->descent; cff_subset->descent = font->descent;
cff_subset->data = malloc (length); cff_subset->data = malloc (length);
if (cff_subset->data == NULL) if (cff_subset->data == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3; goto fail3;
}
memcpy (cff_subset->data, data, length); memcpy (cff_subset->data, data, length);
cff_subset->data_length = length; cff_subset->data_length = length;
@ -1912,7 +2011,7 @@ _cairo_cff_subset_init (cairo_cff_subset_t *cff_subset,
fail1: fail1:
cairo_cff_font_destroy (font); cairo_cff_font_destroy (font);
return status; return _cairo_error (status);
} }
void void
@ -1933,7 +2032,7 @@ _cairo_cff_font_fallback_create (cairo_scaled_font_subset_t *scaled_font_subset
font = malloc (sizeof (cairo_cff_font_t)); font = malloc (sizeof (cairo_cff_font_t));
if (font == NULL) if (font == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font->backend = NULL; font->backend = NULL;
font->scaled_font_subset = scaled_font_subset; font->scaled_font_subset = scaled_font_subset;
@ -1945,14 +2044,14 @@ _cairo_cff_font_fallback_create (cairo_scaled_font_subset_t *scaled_font_subset
font->subset_font_name = strdup (subset_name); font->subset_font_name = strdup (subset_name);
if (font->subset_font_name == NULL) { if (font->subset_font_name == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2; goto fail1;
} }
font->font_name = strdup (subset_name); font->font_name = strdup (subset_name);
if (font->subset_font_name == NULL) { if (font->subset_font_name == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3; goto fail2;
} }
font->x_min = 0; font->x_min = 0;
@ -1964,16 +2063,22 @@ _cairo_cff_font_fallback_create (cairo_scaled_font_subset_t *scaled_font_subset
font->widths = calloc (font->scaled_font_subset->num_glyphs, sizeof (int)); font->widths = calloc (font->scaled_font_subset->num_glyphs, sizeof (int));
if (font->widths == NULL) { if (font->widths == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail4; goto fail3;
} }
font->data_length = 0; font->data_length = 0;
font->data = NULL; font->data = NULL;
font->data_end = 0; font->data_end = NULL;
status = cff_dict_init (&font->top_dict);
if (status)
goto fail4;
status = cff_dict_init (&font->private_dict);
if (status)
goto fail5;
cff_dict_init (&font->top_dict);
cff_dict_init (&font->private_dict);
cff_index_init (&font->strings_index); cff_index_init (&font->strings_index);
cff_index_init (&font->charstrings_index); cff_index_init (&font->charstrings_index);
cff_index_init (&font->global_sub_index); cff_index_init (&font->global_sub_index);
@ -1992,15 +2097,18 @@ _cairo_cff_font_fallback_create (cairo_scaled_font_subset_t *scaled_font_subset
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
fail5:
_cairo_hash_table_destroy (font->top_dict);
fail4: fail4:
free (font->font_name); free (font->widths);
fail3: fail3:
free (font->subset_font_name); free (font->font_name);
fail2: fail2:
_cairo_array_fini (&font->output); free (font->subset_font_name);
fail1: fail1:
_cairo_array_fini (&font->output);
free (font); free (font);
return status; return _cairo_error (status);
} }
static cairo_int_status_t static cairo_int_status_t
@ -2029,16 +2137,40 @@ cairo_cff_font_fallback_generate (cairo_cff_font_t *font,
end_buf = encode_integer (end_buf, type2_subset->y_min); end_buf = encode_integer (end_buf, type2_subset->y_min);
end_buf = encode_integer (end_buf, type2_subset->x_max); end_buf = encode_integer (end_buf, type2_subset->x_max);
end_buf = encode_integer (end_buf, type2_subset->y_max); end_buf = encode_integer (end_buf, type2_subset->y_max);
cff_dict_set_operands (font->top_dict, FONTBBOX_OP, buf, end_buf - buf); status = cff_dict_set_operands (font->top_dict,
FONTBBOX_OP, buf, end_buf - buf);
if (status)
return status;
end_buf = encode_integer_max (buf, 0); end_buf = encode_integer_max (buf, 0);
cff_dict_set_operands (font->top_dict, CHARSTRINGS_OP, buf, end_buf - buf); status = cff_dict_set_operands (font->top_dict,
cff_dict_set_operands (font->top_dict, FDSELECT_OP, buf, end_buf - buf); CHARSTRINGS_OP, buf, end_buf - buf);
cff_dict_set_operands (font->top_dict, FDARRAY_OP, buf, end_buf - buf); if (status)
cff_dict_set_operands (font->top_dict, CHARSET_OP, buf, end_buf - buf); return status;
cairo_cff_font_set_ros_strings (font);
status = cff_dict_set_operands (font->top_dict,
FDSELECT_OP, buf, end_buf - buf);
if (status)
return status;
status = cff_dict_set_operands (font->top_dict,
FDARRAY_OP, buf, end_buf - buf);
if (status)
return status;
status = cff_dict_set_operands (font->top_dict,
CHARSET_OP, buf, end_buf - buf);
if (status)
return status;
status = cairo_cff_font_set_ros_strings (font);
if (status)
return status;
/* Create CID FD dictionary */ /* Create CID FD dictionary */
cairo_cff_font_create_cid_fontdict (font); status = cairo_cff_font_create_cid_fontdict (font);
if (status)
return status;
/* Create charstrings */ /* Create charstrings */
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) { for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
@ -2084,15 +2216,19 @@ _cairo_cff_fallback_init (cairo_cff_subset_t *cff_subset,
status = cairo_cff_font_fallback_generate (font, &type2_subset, &data, &length); status = cairo_cff_font_fallback_generate (font, &type2_subset, &data, &length);
if (status) if (status)
goto fail1; goto fail2;
cff_subset->base_font = strdup (font->font_name); cff_subset->base_font = strdup (font->font_name);
if (cff_subset->base_font == NULL) if (cff_subset->base_font == NULL) {
goto fail1; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2;
}
cff_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs); cff_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs);
if (cff_subset->widths == NULL) if (cff_subset->widths == NULL) {
goto fail2; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3;
}
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) for (i = 0; i < font->scaled_font_subset->num_glyphs; i++)
cff_subset->widths[i] = type2_subset.widths[i]; cff_subset->widths[i] = type2_subset.widths[i];
@ -2103,24 +2239,27 @@ _cairo_cff_fallback_init (cairo_cff_subset_t *cff_subset,
cff_subset->ascent = type2_subset.y_max; cff_subset->ascent = type2_subset.y_max;
cff_subset->descent = type2_subset.y_min; cff_subset->descent = type2_subset.y_min;
_cairo_type2_charstrings_fini (&type2_subset);
cff_subset->data = malloc (length); cff_subset->data = malloc (length);
if (cff_subset->data == NULL) if (cff_subset->data == NULL) {
goto fail3; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail4;
}
memcpy (cff_subset->data, data, length); memcpy (cff_subset->data, data, length);
cff_subset->data_length = length; cff_subset->data_length = length;
cff_subset->data_length = length; cff_subset->data_length = length;
_cairo_type2_charstrings_fini (&type2_subset);
cairo_cff_font_destroy (font); cairo_cff_font_destroy (font);
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
fail3: fail4:
free (cff_subset->widths); free (cff_subset->widths);
fail2: fail3:
free (cff_subset->base_font); free (cff_subset->base_font);
fail2:
_cairo_type2_charstrings_fini (&type2_subset);
fail1: fail1:
cairo_cff_font_destroy (font); cairo_cff_font_destroy (font);

View File

@ -36,22 +36,25 @@
#ifndef CAIRO_CLIP_PRIVATE_H #ifndef CAIRO_CLIP_PRIVATE_H
#define CAIRO_CLIP_PRIVATE_H #define CAIRO_CLIP_PRIVATE_H
#include "cairo-compiler-private.h"
#include "cairo-path-fixed-private.h" #include "cairo-path-fixed-private.h"
extern const cairo_private cairo_rectangle_list_t _cairo_rectangles_nil; extern const cairo_private cairo_rectangle_list_t _cairo_rectangles_nil;
struct _cairo_clip_path { struct _cairo_clip_path {
unsigned int ref_count; cairo_reference_count_t ref_count;
cairo_path_fixed_t path; cairo_path_fixed_t path;
cairo_fill_rule_t fill_rule; cairo_fill_rule_t fill_rule;
double tolerance; double tolerance;
cairo_antialias_t antialias; cairo_antialias_t antialias;
cairo_clip_path_t *prev; cairo_clip_path_t *prev;
}; };
struct _cairo_clip { struct _cairo_clip {
cairo_clip_mode_t mode; cairo_clip_mode_t mode;
cairo_bool_t all_clipped;
/* /*
* Mask-based clipping for cases where the backend * Mask-based clipping for cases where the backend
* clipping isn't sufficiently able. * clipping isn't sufficiently able.

View File

@ -54,6 +54,8 @@ _cairo_clip_init (cairo_clip_t *clip, cairo_surface_t *target)
else else
clip->mode = CAIRO_CLIP_MODE_MASK; clip->mode = CAIRO_CLIP_MODE_MASK;
clip->all_clipped = FALSE;
clip->surface = NULL; clip->surface = NULL;
clip->surface_rect.x = 0; clip->surface_rect.x = 0;
clip->surface_rect.y = 0; clip->surface_rect.y = 0;
@ -73,6 +75,8 @@ _cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other)
{ {
clip->mode = other->mode; clip->mode = other->mode;
clip->all_clipped = other->all_clipped;
clip->surface = cairo_surface_reference (other->surface); clip->surface = cairo_surface_reference (other->surface);
clip->surface_rect = other->surface_rect; clip->surface_rect = other->surface_rect;
@ -81,12 +85,12 @@ _cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other)
_cairo_region_init (&clip->region); _cairo_region_init (&clip->region);
if (other->has_region) { if (other->has_region) {
if (_cairo_region_copy (&clip->region, &other->region) != cairo_status_t status;
CAIRO_STATUS_SUCCESS) status = _cairo_region_copy (&clip->region, &other->region);
{ if (status) {
_cairo_region_fini (&clip->region); _cairo_region_fini (&clip->region);
cairo_surface_destroy (clip->surface); cairo_surface_destroy (clip->surface);
return CAIRO_STATUS_NO_MEMORY; return status;
} }
clip->has_region = TRUE; clip->has_region = TRUE;
} else { } else {
@ -101,6 +105,8 @@ _cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other)
void void
_cairo_clip_reset (cairo_clip_t *clip) _cairo_clip_reset (cairo_clip_t *clip)
{ {
clip->all_clipped = FALSE;
/* destroy any existing clip-region artifacts */ /* destroy any existing clip-region artifacts */
cairo_surface_destroy (clip->surface); cairo_surface_destroy (clip->surface);
clip->surface = NULL; clip->surface = NULL;
@ -121,9 +127,19 @@ _cairo_clip_reset (cairo_clip_t *clip)
clip->path = NULL; clip->path = NULL;
} }
static void
_cairo_clip_set_all_clipped (cairo_clip_t *clip, cairo_surface_t *target)
{
_cairo_clip_reset (clip);
clip->all_clipped = TRUE;
clip->serial = _cairo_surface_allocate_clip_serial (target);
}
static cairo_status_t static cairo_status_t
_cairo_clip_path_intersect_to_rectangle (cairo_clip_path_t *clip_path, _cairo_clip_path_intersect_to_rectangle (cairo_clip_path_t *clip_path,
cairo_rectangle_int_t *rectangle) cairo_rectangle_int_t *rectangle)
{ {
while (clip_path) { while (clip_path) {
cairo_status_t status; cairo_status_t status;
@ -161,6 +177,11 @@ _cairo_clip_intersect_to_rectangle (cairo_clip_t *clip,
if (!clip) if (!clip)
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
if (clip->all_clipped) {
*rectangle = clip->surface_rect;
return CAIRO_STATUS_SUCCESS;
}
if (clip->path) { if (clip->path) {
cairo_status_t status; cairo_status_t status;
@ -203,6 +224,18 @@ _cairo_clip_intersect_to_region (cairo_clip_t *clip,
if (!clip) if (!clip)
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
if (clip->all_clipped) {
cairo_region_t clip_rect;
_cairo_region_init_rect (&clip_rect, &clip->surface_rect);
status = _cairo_region_intersect (region, &clip_rect, region);
_cairo_region_fini (&clip_rect);
return status;
}
if (clip->path) { if (clip->path) {
/* Intersect clip path into region. */ /* Intersect clip path into region. */
} }
@ -244,6 +277,9 @@ _cairo_clip_combine_to_surface (cairo_clip_t *clip,
cairo_pattern_union_t pattern; cairo_pattern_union_t pattern;
cairo_status_t status; cairo_status_t status;
if (clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
_cairo_pattern_init_for_surface (&pattern.surface, clip->surface); _cairo_pattern_init_for_surface (&pattern.surface, clip->surface);
status = _cairo_surface_composite (op, status = _cairo_surface_composite (op,
@ -277,7 +313,7 @@ _cairo_clip_intersect_path (cairo_clip_t *clip,
clip_path = malloc (sizeof (cairo_clip_path_t)); clip_path = malloc (sizeof (cairo_clip_path_t));
if (clip_path == NULL) if (clip_path == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_path_fixed_init_copy (&clip_path->path, path); status = _cairo_path_fixed_init_copy (&clip_path->path, path);
if (status) { if (status) {
@ -285,7 +321,7 @@ _cairo_clip_intersect_path (cairo_clip_t *clip,
return status; return status;
} }
clip_path->ref_count = 1; CAIRO_REFERENCE_COUNT_INIT (&clip_path->ref_count, 1);
clip_path->fill_rule = fill_rule; clip_path->fill_rule = fill_rule;
clip_path->tolerance = tolerance; clip_path->tolerance = tolerance;
clip_path->antialias = antialias; clip_path->antialias = antialias;
@ -301,7 +337,9 @@ _cairo_clip_path_reference (cairo_clip_path_t *clip_path)
if (clip_path == NULL) if (clip_path == NULL)
return NULL; return NULL;
clip_path->ref_count++; assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
_cairo_reference_count_inc (&clip_path->ref_count);
return clip_path; return clip_path;
} }
@ -312,8 +350,9 @@ _cairo_clip_path_destroy (cairo_clip_path_t *clip_path)
if (clip_path == NULL) if (clip_path == NULL)
return; return;
clip_path->ref_count--; assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
if (clip_path->ref_count)
if (! _cairo_reference_count_dec_and_test (&clip_path->ref_count))
return; return;
_cairo_path_fixed_fini (&clip_path->path); _cairo_path_fixed_fini (&clip_path->path);
@ -321,6 +360,7 @@ _cairo_clip_path_destroy (cairo_clip_path_t *clip_path)
free (clip_path); free (clip_path);
} }
static cairo_int_status_t static cairo_int_status_t
_cairo_clip_intersect_region (cairo_clip_t *clip, _cairo_clip_intersect_region (cairo_clip_t *clip,
cairo_traps_t *traps, cairo_traps_t *traps,
@ -329,6 +369,9 @@ _cairo_clip_intersect_region (cairo_clip_t *clip,
cairo_region_t region; cairo_region_t region;
cairo_int_status_t status; cairo_int_status_t status;
if (clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
if (clip->mode != CAIRO_CLIP_MODE_REGION) if (clip->mode != CAIRO_CLIP_MODE_REGION)
return CAIRO_INT_STATUS_UNSUPPORTED; return CAIRO_INT_STATUS_UNSUPPORTED;
@ -360,6 +403,9 @@ _cairo_clip_intersect_region (cairo_clip_t *clip,
clip->serial = _cairo_surface_allocate_clip_serial (target); clip->serial = _cairo_surface_allocate_clip_serial (target);
_cairo_region_fini (&region); _cairo_region_fini (&region);
if (! _cairo_region_not_empty (&clip->region))
_cairo_clip_set_all_clipped (clip, target);
return status; return status;
} }
@ -375,6 +421,9 @@ _cairo_clip_intersect_mask (cairo_clip_t *clip,
cairo_surface_t *surface; cairo_surface_t *surface;
cairo_status_t status; cairo_status_t status;
if (clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
/* Represent the clip as a mask surface. We create a new surface /* Represent the clip as a mask surface. We create a new surface
* the size of the intersection of the old mask surface and the * the size of the intersection of the old mask surface and the
* extents of the new clip path. */ * extents of the new clip path. */
@ -392,20 +441,30 @@ _cairo_clip_intersect_mask (cairo_clip_t *clip,
if (!status) if (!status)
_cairo_rectangle_intersect (&surface_rect, &target_rect); _cairo_rectangle_intersect (&surface_rect, &target_rect);
if (surface_rect.width == 0 || surface_rect.height == 0) {
surface = NULL;
status = CAIRO_STATUS_SUCCESS;
if (clip->surface != NULL)
cairo_surface_destroy (clip->surface);
goto DONE;
}
_cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
CAIRO_CONTENT_COLOR);
surface = _cairo_surface_create_similar_solid (target, surface = _cairo_surface_create_similar_solid (target,
CAIRO_CONTENT_ALPHA, CAIRO_CONTENT_ALPHA,
surface_rect.width, surface_rect.width,
surface_rect.height, surface_rect.height,
CAIRO_COLOR_WHITE, CAIRO_COLOR_WHITE,
NULL); &pattern.base);
if (surface->status) if (surface->status) {
return CAIRO_STATUS_NO_MEMORY; _cairo_pattern_fini (&pattern.base);
return surface->status;
}
/* Render the new clipping path into the new mask surface. */ /* Render the new clipping path into the new mask surface. */
_cairo_traps_translate (traps, -surface_rect.x, -surface_rect.y); _cairo_traps_translate (traps, -surface_rect.x, -surface_rect.y);
_cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE,
CAIRO_CONTENT_COLOR);
status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN, status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN,
&pattern.base, &pattern.base,
@ -453,10 +512,14 @@ _cairo_clip_intersect_mask (cairo_clip_t *clip,
cairo_surface_destroy (clip->surface); cairo_surface_destroy (clip->surface);
} }
DONE:
clip->surface = surface; clip->surface = surface;
clip->surface_rect = surface_rect; clip->surface_rect = surface_rect;
clip->serial = _cairo_surface_allocate_clip_serial (target); clip->serial = _cairo_surface_allocate_clip_serial (target);
if (surface_rect.width == 0 || surface_rect.height == 0)
_cairo_clip_set_all_clipped (clip, target);
return status; return status;
} }
@ -471,6 +534,15 @@ _cairo_clip_clip (cairo_clip_t *clip,
cairo_status_t status; cairo_status_t status;
cairo_traps_t traps; cairo_traps_t traps;
if (clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
/* catch the empty clip path */
if (! path->has_current_point) {
_cairo_clip_set_all_clipped (clip, target);
return CAIRO_STATUS_SUCCESS;
}
status = _cairo_clip_intersect_path (clip, status = _cairo_clip_intersect_path (clip,
path, fill_rule, tolerance, path, fill_rule, tolerance,
antialias); antialias);
@ -505,6 +577,9 @@ _cairo_clip_translate (cairo_clip_t *clip,
cairo_fixed_t tx, cairo_fixed_t tx,
cairo_fixed_t ty) cairo_fixed_t ty)
{ {
if (clip->all_clipped)
return;
if (clip->has_region) { if (clip->has_region) {
_cairo_region_translate (&clip->region, _cairo_region_translate (&clip->region,
_cairo_fixed_integer_part (tx), _cairo_fixed_integer_part (tx),
@ -531,18 +606,23 @@ _cairo_clip_translate (cairo_clip_t *clip,
} }
} }
static void static cairo_status_t
_cairo_clip_path_reapply_clip_path (cairo_clip_t *clip, _cairo_clip_path_reapply_clip_path (cairo_clip_t *clip,
cairo_clip_path_t *clip_path) cairo_clip_path_t *clip_path)
{ {
if (clip_path->prev) cairo_status_t status;
_cairo_clip_path_reapply_clip_path (clip, clip_path->prev);
_cairo_clip_intersect_path (clip, if (clip_path->prev) {
&clip_path->path, status = _cairo_clip_path_reapply_clip_path (clip, clip_path->prev);
clip_path->fill_rule, if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
clip_path->tolerance, return status;
clip_path->antialias); }
return _cairo_clip_intersect_path (clip,
&clip_path->path,
clip_path->fill_rule,
clip_path->tolerance,
clip_path->antialias);
} }
cairo_status_t cairo_status_t
@ -550,6 +630,8 @@ _cairo_clip_init_deep_copy (cairo_clip_t *clip,
cairo_clip_t *other, cairo_clip_t *other,
cairo_surface_t *target) cairo_surface_t *target)
{ {
cairo_status_t status;
_cairo_clip_init (clip, target); _cairo_clip_init (clip, target);
if (other->mode != clip->mode) { if (other->mode != clip->mode) {
@ -557,26 +639,30 @@ _cairo_clip_init_deep_copy (cairo_clip_t *clip,
* whatever the right handling is happen */ * whatever the right handling is happen */
} else { } else {
if (other->has_region) { if (other->has_region) {
if (_cairo_region_copy (&clip->region, &other->region) != status = _cairo_region_copy (&clip->region, &other->region);
CAIRO_STATUS_SUCCESS) if (status)
goto BAIL; goto BAIL;
clip->has_region = TRUE; clip->has_region = TRUE;
} }
if (other->surface) { if (other->surface) {
if (_cairo_surface_clone_similar (target, other->surface, status = _cairo_surface_clone_similar (target, other->surface,
other->surface_rect.x, other->surface_rect.x,
other->surface_rect.y, other->surface_rect.y,
other->surface_rect.width, other->surface_rect.width,
other->surface_rect.height, other->surface_rect.height,
&clip->surface) != &clip->surface);
CAIRO_STATUS_SUCCESS) if (status)
goto BAIL; goto BAIL;
clip->surface_rect = other->surface_rect; clip->surface_rect = other->surface_rect;
} }
if (other->path) { if (other->path) {
_cairo_clip_path_reapply_clip_path (clip, other->path); status = _cairo_clip_path_reapply_clip_path (clip, other->path);
if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
goto BAIL;
} }
} }
@ -588,7 +674,7 @@ BAIL:
if (clip->surface) if (clip->surface)
cairo_surface_destroy (clip->surface); cairo_surface_destroy (clip->surface);
return CAIRO_STATUS_NO_MEMORY; return status;
} }
const cairo_rectangle_list_t _cairo_rectangles_nil = const cairo_rectangle_list_t _cairo_rectangles_nil =
@ -623,7 +709,10 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
{ {
cairo_rectangle_list_t *list; cairo_rectangle_list_t *list;
cairo_rectangle_t *rectangles = NULL; cairo_rectangle_t *rectangles = NULL;
int n_boxes; int n_boxes = 0;
if (clip->all_clipped)
goto DONE;
if (clip->path || clip->surface) if (clip->path || clip->surface)
return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable; return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
@ -635,23 +724,26 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
if (_cairo_region_get_boxes (&clip->region, &n_boxes, &boxes) != CAIRO_STATUS_SUCCESS) if (_cairo_region_get_boxes (&clip->region, &n_boxes, &boxes) != CAIRO_STATUS_SUCCESS)
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
rectangles = _cairo_malloc_ab (n_boxes, sizeof (cairo_rectangle_t)); if (n_boxes) {
if (rectangles == NULL) { rectangles = _cairo_malloc_ab (n_boxes, sizeof (cairo_rectangle_t));
_cairo_region_boxes_fini (&clip->region, boxes); if (rectangles == NULL) {
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
}
for (i = 0; i < n_boxes; ++i) {
cairo_rectangle_int_t clip_rect = { boxes[i].p1.x, boxes[i].p1.y,
boxes[i].p2.x - boxes[i].p1.x,
boxes[i].p2.y - boxes[i].p1.y };
if (!_cairo_clip_int_rect_to_user(gstate, &clip_rect, &rectangles[i])) {
_cairo_region_boxes_fini (&clip->region, boxes); _cairo_region_boxes_fini (&clip->region, boxes);
free (rectangles); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable; return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
} }
}
for (i = 0; i < n_boxes; ++i) {
cairo_rectangle_int_t clip_rect = { boxes[i].p1.x, boxes[i].p1.y,
boxes[i].p2.x - boxes[i].p1.x,
boxes[i].p2.y - boxes[i].p1.y };
if (!_cairo_clip_int_rect_to_user(gstate, &clip_rect, &rectangles[i])) {
_cairo_region_boxes_fini (&clip->region, boxes);
free (rectangles);
return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
}
}
}
_cairo_region_boxes_fini (&clip->region, boxes); _cairo_region_boxes_fini (&clip->region, boxes);
} else { } else {
@ -660,8 +752,10 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
n_boxes = 1; n_boxes = 1;
rectangles = malloc(sizeof (cairo_rectangle_t)); rectangles = malloc(sizeof (cairo_rectangle_t));
if (rectangles == NULL) if (rectangles == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
}
if (_cairo_surface_get_extents (_cairo_gstate_get_target (gstate), &extents) || if (_cairo_surface_get_extents (_cairo_gstate_get_target (gstate), &extents) ||
!_cairo_clip_int_rect_to_user(gstate, &extents, rectangles)) !_cairo_clip_int_rect_to_user(gstate, &extents, rectangles))
@ -671,9 +765,11 @@ _cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
} }
} }
DONE:
list = malloc (sizeof (cairo_rectangle_list_t)); list = malloc (sizeof (cairo_rectangle_list_t));
if (list == NULL) { if (list == NULL) {
free (rectangles); free (rectangles);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
} }

View File

@ -0,0 +1,115 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2002 University of Southern California
* Copyright © 2005 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Carl D. Worth <cworth@cworth.org>
*/
#ifndef CAIRO_COMPILER_PRIVATE_H
#define CAIRO_COMPILER_PRIVATE_H
CAIRO_BEGIN_DECLS
#if __GNUC__ >= 3 && defined(__ELF__) && !defined(__sun)
# define slim_hidden_proto(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private
# define slim_hidden_proto_no_warn(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private_no_warn
# define slim_hidden_def(name) slim_hidden_def1(name, slim_hidden_int_name(name))
# define slim_hidden_int_name(name) INT_##name
# define slim_hidden_proto1(name, internal) \
extern __typeof (name) name \
__asm__ (slim_hidden_asmname (internal))
# define slim_hidden_def1(name, internal) \
extern __typeof (name) EXT_##name __asm__(slim_hidden_asmname(name)) \
__attribute__((__alias__(slim_hidden_asmname(internal))))
# define slim_hidden_ulp slim_hidden_ulp1(__USER_LABEL_PREFIX__)
# define slim_hidden_ulp1(x) slim_hidden_ulp2(x)
# define slim_hidden_ulp2(x) #x
# define slim_hidden_asmname(name) slim_hidden_asmname1(name)
# define slim_hidden_asmname1(name) slim_hidden_ulp #name
#else
# define slim_hidden_proto(name) int _cairo_dummy_prototype(void)
# define slim_hidden_proto_no_warn(name) int _cairo_dummy_prototype(void)
# define slim_hidden_def(name) int _cairo_dummy_prototype(void)
#endif
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
#define CAIRO_PRINTF_FORMAT(fmt_index, va_index) \
__attribute__((__format__(__printf__, fmt_index, va_index)))
#else
#define CAIRO_PRINTF_FORMAT(fmt_index, va_index)
#endif
/* slim_internal.h */
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun)
#define cairo_private_no_warn __attribute__((__visibility__("hidden")))
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
#define cairo_private_no_warn __hidden
#else /* not gcc >= 3.3 and not Sun Studio >= 8 */
#define cairo_private_no_warn
#endif
#ifndef WARN_UNUSED_RESULT
#define WARN_UNUSED_RESULT
#endif
/* Add attribute(warn_unused_result) if supported */
#define cairo_warn WARN_UNUSED_RESULT
#define cairo_private cairo_private_no_warn cairo_warn
/* This macro allow us to deprecate a function by providing an alias
for the old function name to the new function name. With this
macro, binary compatibility is preserved. The macro only works on
some platforms --- tough.
Meanwhile, new definitions in the public header file break the
source code so that it will no longer link against the old
symbols. Instead it will give a descriptive error message
indicating that the old function has been deprecated by the new
function.
*/
#if __GNUC__ >= 2 && defined(__ELF__)
# define CAIRO_FUNCTION_ALIAS(old, new) \
extern __typeof (new) old \
__asm__ ("" #old) \
__attribute__((__alias__("" #new)))
#else
# define CAIRO_FUNCTION_ALIAS(old, new)
#endif
#ifndef __GNUC__
#define __attribute__(x)
#endif
CAIRO_END_DECLS
#endif

View File

@ -59,6 +59,8 @@
void void
cairo_debug_reset_static_data (void) cairo_debug_reset_static_data (void)
{ {
CAIRO_MUTEX_INITIALIZE ();
_cairo_font_reset_static_data (); _cairo_font_reset_static_data ();
#if CAIRO_HAS_FT_FONT #if CAIRO_HAS_FT_FONT
@ -66,4 +68,6 @@ cairo_debug_reset_static_data (void)
#endif #endif
_cairo_pattern_reset_static_data (); _cairo_pattern_reset_static_data ();
CAIRO_MUTEX_FINALIZE ();
} }

View File

@ -117,9 +117,17 @@ _cairo_deflate_stream_create (cairo_output_stream_t *output)
{ {
cairo_deflate_stream_t *stream; cairo_deflate_stream_t *stream;
stream = malloc (sizeof (cairo_deflate_stream_t)); if (output->status) {
if (stream == NULL) _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil; return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
stream = malloc (sizeof (cairo_deflate_stream_t));
if (stream == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base, _cairo_output_stream_init (&stream->base,
_cairo_deflate_stream_write, _cairo_deflate_stream_write,

View File

@ -68,7 +68,7 @@
#define DFB_SHOW_GLYPHS 1 #define DFB_SHOW_GLYPHS 1
D_DEBUG_DOMAIN (Cairo_DirectFB, "Cairo/DirectFB", "Cairo DirectFB backend"); D_DEBUG_DOMAIN (Cairo_DirectFB, "Cairo/DirectFB", "Cairo DirectFB backend")
/*****************************************************************************/ /*****************************************************************************/
@ -390,7 +390,7 @@ _directfb_acquire_surface (cairo_directfb_surface_t *surface,
if( buffer != surface->dfbsurface) if( buffer != surface->dfbsurface)
buffer->Release(buffer); buffer->Release(buffer);
} }
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
@ -414,8 +414,10 @@ _cairo_directfb_surface_create_similar (void *abstract_src,
format = _cairo_format_from_content (content); format = _cairo_format_from_content (content);
surface = calloc (1, sizeof(cairo_directfb_surface_t)); surface = calloc (1, sizeof(cairo_directfb_surface_t));
if (!surface) if (!surface) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
}
surface->dfbsurface = _directfb_buffer_surface_create (source->dfb, surface->dfbsurface = _directfb_buffer_surface_create (source->dfb,
cairo_to_directfb_format (format), cairo_to_directfb_format (format),
@ -528,12 +530,12 @@ _cairo_directfb_surface_release_dest_image (void *abstract_surf
buffer->Unlock (buffer); buffer->Unlock (buffer);
if (surface->dfbsurface != buffer) { if (surface->dfbsurface != buffer) {
DFBRegion region = { x1:interest_rect->x, y1:interest_rect->y, DFBRegion region = { .x1 = interest_rect->x, .y1 = interest_rect->y,
x2:interest_rect->x+interest_rect->width-1, .x2 = interest_rect->x+interest_rect->width-1,
y2:interest_rect->y+interest_rect->height-1 }; .y2 = interest_rect->y+interest_rect->height-1 };
surface->dfbsurface->SetClip (surface->dfbsurface, &region); surface->dfbsurface->SetClip (surface->dfbsurface, &region);
//surface->dfbsurface->SetBlittingFlags (surface->dfbsurface, /* surface->dfbsurface->SetBlittingFlags (surface->dfbsurface,
// DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_COLORIZE); DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_COLORIZE); */
surface->dfbsurface->Blit (surface->dfbsurface,buffer,NULL, surface->dfbsurface->Blit (surface->dfbsurface,buffer,NULL,
image_rect->x,image_rect->y); image_rect->x,image_rect->y);
buffer->Release (buffer); buffer->Release (buffer);
@ -574,14 +576,14 @@ _cairo_directfb_surface_clone_similar (void *abstract_surface,
_cairo_content_from_format (image_src->format), _cairo_content_from_format (image_src->format),
image_src->width, image_src->height); image_src->width, image_src->height);
if (!clone) if (!clone)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
ret = clone->dfbsurface->Lock (clone->dfbsurface, ret = clone->dfbsurface->Lock (clone->dfbsurface,
DSLF_WRITE, (void *)&dst, &pitch); DSLF_WRITE, (void *)&dst, &pitch);
if (ret) { if (ret) {
DirectFBError ("IDirectFBSurface::Lock()", ret); DirectFBError ("IDirectFBSurface::Lock()", ret);
cairo_surface_destroy ((cairo_surface_t *)clone); cairo_surface_destroy ((cairo_surface_t *)clone);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
dst += pitch * src_y; dst += pitch * src_y;
@ -664,7 +666,7 @@ _directfb_prepare_composite (cairo_directfb_surface_t *dst,
if (sblend == DSBF_ONE) { if (sblend == DSBF_ONE) {
flags |= DSBLIT_BLEND_ALPHACHANNEL; flags |= DSBLIT_BLEND_ALPHACHANNEL;
sblend = DSBF_SRCALPHA; sblend = DSBF_SRCALPHA;
//dblend = DSBF_INVSRCALPHA; /* dblend = DSBF_INVSRCALPHA; */
} }
} }
@ -685,7 +687,7 @@ _directfb_prepare_composite (cairo_directfb_surface_t *dst,
dst->color = _cairo_directfb_surface_create_similar (dst, dst->color = _cairo_directfb_surface_create_similar (dst,
CAIRO_CONTENT_COLOR_ALPHA, 1, 1); CAIRO_CONTENT_COLOR_ALPHA, 1, 1);
if (!dst->color) if (!dst->color)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
src = (cairo_directfb_surface_t *)dst->color; src = (cairo_directfb_surface_t *)dst->color;
@ -756,7 +758,7 @@ _cairo_directfb_surface_composite (cairo_operator_t op,
unsigned int height) unsigned int height)
{ {
cairo_directfb_surface_t *dst = abstract_dst; cairo_directfb_surface_t *dst = abstract_dst;
cairo_directfb_surface_t *src; cairo_directfb_surface_t *src = NULL; /* hide compiler warning */
cairo_surface_attributes_t src_attr; cairo_surface_attributes_t src_attr;
cairo_matrix_t *m; cairo_matrix_t *m;
cairo_status_t ret; cairo_status_t ret;
@ -1107,9 +1109,11 @@ _cairo_directfb_surface_set_clip_region (void *abstract_surface,
if (region) { if (region) {
cairo_box_int_t *boxes; cairo_box_int_t *boxes;
int n_boxes, i; int n_boxes, i;
cairo_status_t status;
if (_cairo_region_get_boxes (region, &n_boxes, &boxes) != CAIRO_STATUS_SUCCESS) status = _cairo_region_get_boxes (region, &n_boxes, &boxes);
return CAIRO_STATUS_NO_MEMORY; if (status)
return status;
if (surface->n_clips != n_boxes) { if (surface->n_clips != n_boxes) {
if( surface->clips ) if( surface->clips )
@ -1119,7 +1123,7 @@ _cairo_directfb_surface_set_clip_region (void *abstract_surface,
if (!surface->clips) { if (!surface->clips) {
_cairo_region_boxes_fini (region, boxes); _cairo_region_boxes_fini (region, boxes);
surface->n_clips = 0; surface->n_clips = 0;
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
surface->n_clips = n_boxes; surface->n_clips = n_boxes;
@ -1181,7 +1185,7 @@ _cairo_directfb_surface_mark_dirty_rectangle (void *abstract_surface,
if( !surface->dirty_region ) if( !surface->dirty_region )
surface->dirty_region = malloc(sizeof(DFBRegion)); surface->dirty_region = malloc(sizeof(DFBRegion));
if (!dirty_region) if (!dirty_region)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
#endif #endif
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -1211,16 +1215,19 @@ _directfb_allocate_font_cache (IDirectFB *dfb, int width, int height)
cairo_directfb_font_cache_t *cache; cairo_directfb_font_cache_t *cache;
cache = calloc (1, sizeof(cairo_directfb_font_cache_t)); cache = calloc (1, sizeof(cairo_directfb_font_cache_t));
if (!cache) if (!cache) {
return NULL; _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
cache->dfbsurface = _directfb_buffer_surface_create( dfb, DSPF_A8, width, height); cache->dfbsurface = _directfb_buffer_surface_create( dfb, DSPF_A8, width, height);
if (!cache->dfbsurface) { if (!cache->dfbsurface) {
free (cache); free (cache);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
} }
//dfb->AddRef (dfb); /* dfb->AddRef (dfb); */
cache->dfb = dfb; cache->dfb = dfb;
cache->width = width; cache->width = width;
@ -1314,7 +1321,7 @@ _directfb_acquire_font_cache (cairo_directfb_surface_t *surface,
/* Remember glyph location */ /* Remember glyph location */
rect = malloc (sizeof(DFBRectangle)); rect = malloc (sizeof(DFBRectangle));
if (!rect) if (!rect)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
*rect = rects[n]; *rect = rects[n];
scaled_glyph->surface_private = rect; scaled_glyph->surface_private = rect;
@ -1352,7 +1359,7 @@ _directfb_acquire_font_cache (cairo_directfb_surface_t *surface,
new_cache = _directfb_allocate_font_cache (surface->dfb, w, h); new_cache = _directfb_allocate_font_cache (surface->dfb, w, h);
if (!new_cache) if (!new_cache)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
new_cache->dfbsurface->Blit (new_cache->dfbsurface, new_cache->dfbsurface->Blit (new_cache->dfbsurface,
cache->dfbsurface, NULL, 0, 0); cache->dfbsurface, NULL, 0, 0);
@ -1366,8 +1373,8 @@ _directfb_acquire_font_cache (cairo_directfb_surface_t *surface,
"Allocating font cache (%dx%d).\n", w, h); "Allocating font cache (%dx%d).\n", w, h);
cache = _directfb_allocate_font_cache (surface->dfb, w, h); cache = _directfb_allocate_font_cache (surface->dfb, w, h);
if (!cache) if (!cache)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
scaled_font->surface_backend = &cairo_directfb_surface_backend; scaled_font->surface_backend = &cairo_directfb_surface_backend;
scaled_font->surface_private = cache; scaled_font->surface_private = cache;
@ -1379,7 +1386,7 @@ _directfb_acquire_font_cache (cairo_directfb_surface_t *surface,
if (cache->dfbsurface->Lock (cache->dfbsurface, if (cache->dfbsurface->Lock (cache->dfbsurface,
DSLF_WRITE, (void *)&data, &pitch)) DSLF_WRITE, (void *)&data, &pitch))
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
for (i = 0; i < num_chars; i++) { for (i = 0; i < num_chars; i++) {
cairo_image_surface_t *img = chars[i]->surface; cairo_image_surface_t *img = chars[i]->surface;
@ -1629,8 +1636,10 @@ cairo_directfb_surface_create (IDirectFB *dfb, IDirectFBSurface *dfbsurface)
cairo_directfb_surface_backend_init (dfb); cairo_directfb_surface_backend_init (dfb);
surface = calloc (1, sizeof(cairo_directfb_surface_t)); surface = calloc (1, sizeof(cairo_directfb_surface_t));
if (!surface) if (!surface) {
return NULL; _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
dfbsurface->GetPixelFormat (dfbsurface, &format); dfbsurface->GetPixelFormat (dfbsurface, &format);
_cairo_surface_init (&surface->base, &cairo_directfb_surface_backend, _cairo_surface_init (&surface->base, &cairo_directfb_surface_backend,

View File

@ -53,9 +53,9 @@
#define CAIRO_VERSION_MAJOR 1 #define CAIRO_VERSION_MAJOR 1
#define CAIRO_VERSION_MINOR 5 #define CAIRO_VERSION_MINOR 5
#define CAIRO_VERSION_MICRO 1 #define CAIRO_VERSION_MICRO 3
#define CAIRO_VERSION_STRING "1.5.1" #define CAIRO_VERSION_STRING "1.5.3"
@PS_SURFACE_FEATURE@ @PS_SURFACE_FEATURE@

View File

@ -55,7 +55,10 @@ typedef cairo_int128_t cairo_fixed_96_32_t;
*/ */
#define CAIRO_FIXED_BITS 32 #define CAIRO_FIXED_BITS 32
/* The number of fractional bits. */ /* The number of fractional bits. Changing this involves
* making sure that you compute a double-to-fixed magic number.
* (see below).
*/
#define CAIRO_FIXED_FRAC_BITS 8 #define CAIRO_FIXED_FRAC_BITS 8
/* A signed type CAIRO_FIXED_BITS in size; the main fixed point type */ /* A signed type CAIRO_FIXED_BITS in size; the main fixed point type */
@ -206,12 +209,13 @@ _cairo_fixed_to_16_16 (cairo_fixed_t f)
#if (CAIRO_FIXED_FRAC_BITS == 16) && (CAIRO_FIXED_BITS == 32) #if (CAIRO_FIXED_FRAC_BITS == 16) && (CAIRO_FIXED_BITS == 32)
return f; return f;
#elif CAIRO_FIXED_FRAC_BITS > 16 #elif CAIRO_FIXED_FRAC_BITS > 16
/* We're just dropping the low bits, so we won't ever got over/underflow here */
return f >> (CAIRO_FIXED_FRAC_BITS - 16); return f >> (CAIRO_FIXED_FRAC_BITS - 16);
#else #else
cairo_fixed_16_16_t x; cairo_fixed_16_16_t x;
/* Clamp to INT16 so that we don't get odd overflow or underflow by /* Handle overflow/underflow by claping to the lowest/highest
* just shifting. * value representable as 16.16
*/ */
if ((f >> CAIRO_FIXED_FRAC_BITS) < INT16_MIN) { if ((f >> CAIRO_FIXED_FRAC_BITS) < INT16_MIN) {
x = INT32_MIN; x = INT32_MIN;

View File

@ -50,11 +50,23 @@ static const cairo_font_face_backend_t _cairo_toy_font_face_backend;
const cairo_font_face_t _cairo_font_face_nil = { const cairo_font_face_t _cairo_font_face_nil = {
{ 0 }, /* hash_entry */ { 0 }, /* hash_entry */
CAIRO_STATUS_NO_MEMORY, /* status */ CAIRO_STATUS_NO_MEMORY, /* status */
CAIRO_REF_COUNT_INVALID, /* ref_count */ CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
{ 0, 0, 0, NULL }, /* user_data */ { 0, 0, 0, NULL }, /* user_data */
&_cairo_toy_font_face_backend &_cairo_toy_font_face_backend
}; };
cairo_status_t
_cairo_font_face_set_error (cairo_font_face_t *font_face,
cairo_status_t status)
{
if (status == CAIRO_STATUS_SUCCESS)
return status;
_cairo_status_set_error (&font_face->status, status);
return _cairo_error (status);
}
void void
_cairo_font_face_init (cairo_font_face_t *font_face, _cairo_font_face_init (cairo_font_face_t *font_face,
const cairo_font_face_backend_t *backend) const cairo_font_face_backend_t *backend)
@ -62,7 +74,7 @@ _cairo_font_face_init (cairo_font_face_t *font_face,
CAIRO_MUTEX_INITIALIZE (); CAIRO_MUTEX_INITIALIZE ();
font_face->status = CAIRO_STATUS_SUCCESS; font_face->status = CAIRO_STATUS_SUCCESS;
font_face->ref_count = 1; CAIRO_REFERENCE_COUNT_INIT (&font_face->ref_count, 1);
font_face->backend = backend; font_face->backend = backend;
_cairo_user_data_array_init (&font_face->user_data); _cairo_user_data_array_init (&font_face->user_data);
@ -85,18 +97,15 @@ _cairo_font_face_init (cairo_font_face_t *font_face,
cairo_font_face_t * cairo_font_face_t *
cairo_font_face_reference (cairo_font_face_t *font_face) cairo_font_face_reference (cairo_font_face_t *font_face)
{ {
if (font_face == NULL || font_face->ref_count == CAIRO_REF_COUNT_INVALID) if (font_face == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
return font_face; return font_face;
CAIRO_MUTEX_LOCK (_cairo_font_face_mutex); /* We would normally assert that we have a reference here but we
/* We would normally assert (font_face->ref_count >0) here but we
* can't get away with that due to the zombie case as documented * can't get away with that due to the zombie case as documented
* in _cairo_ft_font_face_destroy. */ * in _cairo_ft_font_face_destroy. */
font_face->ref_count++; _cairo_reference_count_inc (&font_face->ref_count);
CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex);
return font_face; return font_face;
} }
@ -113,19 +122,14 @@ slim_hidden_def (cairo_font_face_reference);
void void
cairo_font_face_destroy (cairo_font_face_t *font_face) cairo_font_face_destroy (cairo_font_face_t *font_face)
{ {
if (font_face == NULL || font_face->ref_count == CAIRO_REF_COUNT_INVALID) if (font_face == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
return; return;
CAIRO_MUTEX_LOCK (_cairo_font_face_mutex); assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&font_face->ref_count));
assert (font_face->ref_count > 0); if (! _cairo_reference_count_dec_and_test (&font_face->ref_count))
if (--(font_face->ref_count) > 0) {
CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex);
return; return;
}
CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex);
font_face->backend->destroy (font_face); font_face->backend->destroy (font_face);
@ -133,7 +137,7 @@ cairo_font_face_destroy (cairo_font_face_t *font_face)
* FreeType backend where cairo_ft_font_face_t and cairo_ft_unscaled_font_t * FreeType backend where cairo_ft_font_face_t and cairo_ft_unscaled_font_t
* need to effectively mutually reference each other * need to effectively mutually reference each other
*/ */
if (font_face->ref_count > 0) if (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&font_face->ref_count))
return; return;
_cairo_user_data_array_fini (&font_face->user_data); _cairo_user_data_array_fini (&font_face->user_data);
@ -173,10 +177,11 @@ cairo_font_face_get_type (cairo_font_face_t *font_face)
unsigned int unsigned int
cairo_font_face_get_reference_count (cairo_font_face_t *font_face) cairo_font_face_get_reference_count (cairo_font_face_t *font_face)
{ {
if (font_face == NULL || font_face->ref_count == CAIRO_REF_COUNT_INVALID) if (font_face == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
return 0; return 0;
return font_face->ref_count; return CAIRO_REFERENCE_COUNT_GET_VALUE (&font_face->ref_count);
} }
/** /**
@ -237,8 +242,8 @@ cairo_font_face_set_user_data (cairo_font_face_t *font_face,
void *user_data, void *user_data,
cairo_destroy_func_t destroy) cairo_destroy_func_t destroy)
{ {
if (font_face->ref_count == CAIRO_REF_COUNT_INVALID) if (CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return _cairo_user_data_array_set_data (&font_face->user_data, return _cairo_user_data_array_set_data (&font_face->user_data,
key, user_data, destroy); key, user_data, destroy);
@ -315,6 +320,7 @@ _cairo_toy_font_face_init_key (cairo_toy_font_face_t *key,
hash += ((unsigned long) slant) * 1607; hash += ((unsigned long) slant) * 1607;
hash += ((unsigned long) weight) * 1451; hash += ((unsigned long) weight) * 1451;
assert (hash != 0);
key->base.hash_entry.hash = hash; key->base.hash_entry.hash = hash;
} }
@ -328,7 +334,7 @@ _cairo_toy_font_face_init (cairo_toy_font_face_t *font_face,
family_copy = strdup (family); family_copy = strdup (family);
if (family_copy == NULL) if (family_copy == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_cairo_toy_font_face_init_key (font_face, family_copy, _cairo_toy_font_face_init_key (font_face, family_copy,
slant, weight); slant, weight);
@ -393,17 +399,25 @@ _cairo_toy_font_face_create (const char *family,
&key.base.hash_entry, &key.base.hash_entry,
(cairo_hash_entry_t **) &font_face)) (cairo_hash_entry_t **) &font_face))
{ {
/* We increment the reference count here manually to avoid if (! font_face->base.status) {
double-locking. */ /* We increment the reference count here manually to avoid
font_face->base.ref_count++; double-locking. */
_cairo_toy_font_face_hash_table_unlock (); _cairo_reference_count_inc (&font_face->base.ref_count);
return &font_face->base; _cairo_toy_font_face_hash_table_unlock ();
return &font_face->base;
}
/* remove the bad font from the hash table */
_cairo_hash_table_remove (hash_table, &key.base.hash_entry);
font_face->base.hash_entry.hash = 0;
} }
/* Otherwise create it and insert into hash table. */ /* Otherwise create it and insert into hash table. */
font_face = malloc (sizeof (cairo_toy_font_face_t)); font_face = malloc (sizeof (cairo_toy_font_face_t));
if (font_face == NULL) if (font_face == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto UNWIND_HASH_TABLE_LOCK; goto UNWIND_HASH_TABLE_LOCK;
}
status = _cairo_toy_font_face_init (font_face, family, slant, weight); status = _cairo_toy_font_face_init (font_face, family, slant, weight);
if (status) if (status)
@ -432,14 +446,16 @@ _cairo_toy_font_face_destroy (void *abstract_face)
cairo_toy_font_face_t *font_face = abstract_face; cairo_toy_font_face_t *font_face = abstract_face;
cairo_hash_table_t *hash_table; cairo_hash_table_t *hash_table;
if (font_face == NULL) if (font_face == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->base.ref_count))
return; return;
hash_table = _cairo_toy_font_face_hash_table_lock (); hash_table = _cairo_toy_font_face_hash_table_lock ();
/* All created objects must have been mapped in the hash table. */ /* All created objects must have been mapped in the hash table. */
assert (hash_table != NULL); assert (hash_table != NULL);
_cairo_hash_table_remove (hash_table, &font_face->base.hash_entry); if (font_face->base.hash_entry.hash != 0)
_cairo_hash_table_remove (hash_table, &font_face->base.hash_entry);
_cairo_toy_font_face_hash_table_unlock (); _cairo_toy_font_face_hash_table_unlock ();
@ -457,12 +473,19 @@ _cairo_toy_font_face_scaled_font_create (void *abstract_font_face
const cairo_scaled_font_backend_t * backend = CAIRO_SCALED_FONT_BACKEND_DEFAULT; const cairo_scaled_font_backend_t * backend = CAIRO_SCALED_FONT_BACKEND_DEFAULT;
cairo_status_t status; cairo_status_t status;
if (font_face->base.status)
return font_face->base.status;
status = cairo_font_options_status ((cairo_font_options_t *) options); status = cairo_font_options_status ((cairo_font_options_t *) options);
if (status) if (status)
return status; return status;
return backend->create_toy (font_face, return _cairo_font_face_set_error (&font_face->base,
font_matrix, ctm, options, scaled_font); backend->create_toy (font_face,
font_matrix,
ctm,
options,
scaled_font));
} }
static const cairo_font_face_backend_t _cairo_toy_font_face_backend = { static const cairo_font_face_backend_t _cairo_toy_font_face_backend = {
@ -475,7 +498,7 @@ void
_cairo_unscaled_font_init (cairo_unscaled_font_t *unscaled_font, _cairo_unscaled_font_init (cairo_unscaled_font_t *unscaled_font,
const cairo_unscaled_font_backend_t *backend) const cairo_unscaled_font_backend_t *backend)
{ {
unscaled_font->ref_count = 1; CAIRO_REFERENCE_COUNT_INIT (&unscaled_font->ref_count, 1);
unscaled_font->backend = backend; unscaled_font->backend = backend;
} }
@ -485,7 +508,9 @@ _cairo_unscaled_font_reference (cairo_unscaled_font_t *unscaled_font)
if (unscaled_font == NULL) if (unscaled_font == NULL)
return NULL; return NULL;
unscaled_font->ref_count++; assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&unscaled_font->ref_count));
_cairo_reference_count_inc (&unscaled_font->ref_count);
return unscaled_font; return unscaled_font;
} }
@ -496,7 +521,9 @@ _cairo_unscaled_font_destroy (cairo_unscaled_font_t *unscaled_font)
if (unscaled_font == NULL) if (unscaled_font == NULL)
return; return;
if (--(unscaled_font->ref_count) > 0) assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&unscaled_font->ref_count));
if (! _cairo_reference_count_dec_and_test (&unscaled_font->ref_count))
return; return;
unscaled_font->backend->destroy (unscaled_font); unscaled_font->backend->destroy (unscaled_font);

View File

@ -86,10 +86,13 @@ _cairo_font_options_init_copy (cairo_font_options_t *options,
cairo_font_options_t * cairo_font_options_t *
cairo_font_options_create (void) cairo_font_options_create (void)
{ {
cairo_font_options_t *options = malloc (sizeof (cairo_font_options_t)); cairo_font_options_t *options;
if (!options) options = malloc (sizeof (cairo_font_options_t));
if (!options) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_font_options_t *)&_cairo_font_options_nil; return (cairo_font_options_t *)&_cairo_font_options_nil;
}
_cairo_font_options_init_default (options); _cairo_font_options_init_default (options);
@ -119,8 +122,10 @@ cairo_font_options_copy (const cairo_font_options_t *original)
return (cairo_font_options_t *)&_cairo_font_options_nil; return (cairo_font_options_t *)&_cairo_font_options_nil;
options = malloc (sizeof (cairo_font_options_t)); options = malloc (sizeof (cairo_font_options_t));
if (!options) if (!options) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_font_options_t *)&_cairo_font_options_nil; return (cairo_font_options_t *)&_cairo_font_options_nil;
}
_cairo_font_options_init_copy (options, original); _cairo_font_options_init_copy (options, original);

View File

@ -119,6 +119,10 @@ _cairo_ft_unscaled_font_keys_equal (const void *key_a,
static void static void
_cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled); _cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled);
static cairo_status_t
_cairo_ft_font_options_substitute (const cairo_font_options_t *options,
FcPattern *pattern);
typedef enum _cairo_ft_extra_flags { typedef enum _cairo_ft_extra_flags {
CAIRO_FT_OPTIONS_HINT_METRICS = (1 << 0), CAIRO_FT_OPTIONS_HINT_METRICS = (1 << 0),
CAIRO_FT_OPTIONS_EMBOLDEN = (1 << 1) CAIRO_FT_OPTIONS_EMBOLDEN = (1 << 1)
@ -180,8 +184,10 @@ _cairo_ft_unscaled_font_map_create (void)
assert (cairo_ft_unscaled_font_map == NULL); assert (cairo_ft_unscaled_font_map == NULL);
font_map = malloc (sizeof (cairo_ft_unscaled_font_map_t)); font_map = malloc (sizeof (cairo_ft_unscaled_font_map_t));
if (font_map == NULL) if (font_map == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
goto FAIL; goto FAIL;
}
font_map->hash_table = font_map->hash_table =
_cairo_hash_table_create (_cairo_ft_unscaled_font_keys_equal); _cairo_hash_table_create (_cairo_ft_unscaled_font_keys_equal);
@ -259,7 +265,7 @@ _cairo_ft_unscaled_font_map_lock (void)
if (cairo_ft_unscaled_font_map == NULL) { if (cairo_ft_unscaled_font_map == NULL) {
CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex); CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex);
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
} }
} }
@ -332,10 +338,8 @@ _cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled,
unscaled->face = NULL; unscaled->face = NULL;
filename_copy = strdup (filename); filename_copy = strdup (filename);
if (filename_copy == NULL) { if (filename_copy == NULL)
_cairo_error (CAIRO_STATUS_NO_MEMORY); return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_NO_MEMORY;
}
_cairo_ft_unscaled_font_init_key (unscaled, filename_copy, id); _cairo_ft_unscaled_font_init_key (unscaled, filename_copy, id);
} }
@ -427,8 +431,10 @@ _cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern)
/* Otherwise create it and insert into hash table. */ /* Otherwise create it and insert into hash table. */
unscaled = malloc (sizeof (cairo_ft_unscaled_font_t)); unscaled = malloc (sizeof (cairo_ft_unscaled_font_t));
if (unscaled == NULL) if (unscaled == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
goto UNWIND_FONT_MAP_LOCK; goto UNWIND_FONT_MAP_LOCK;
}
status = _cairo_ft_unscaled_font_init (unscaled, filename, id, NULL); status = _cairo_ft_unscaled_font_init (unscaled, filename, id, NULL);
if (status) if (status)
@ -460,8 +466,10 @@ _cairo_ft_unscaled_font_create_from_face (FT_Face face)
cairo_ft_unscaled_font_t *unscaled; cairo_ft_unscaled_font_t *unscaled;
unscaled = malloc (sizeof (cairo_ft_unscaled_font_t)); unscaled = malloc (sizeof (cairo_ft_unscaled_font_t));
if (unscaled == NULL) if (unscaled == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
}
status = _cairo_ft_unscaled_font_init (unscaled, NULL, 0, face); status = _cairo_ft_unscaled_font_init (unscaled, NULL, 0, face);
if (status) { if (status) {
@ -486,6 +494,8 @@ _cairo_ft_unscaled_font_destroy (void *abstract_font)
*/ */
if (unscaled->faces && !unscaled->faces->unscaled) if (unscaled->faces && !unscaled->faces->unscaled)
cairo_font_face_destroy (&unscaled->faces->base); cairo_font_face_destroy (&unscaled->faces->base);
unscaled->face = NULL;
} else { } else {
cairo_ft_unscaled_font_map_t *font_map; cairo_ft_unscaled_font_map_t *font_map;
@ -497,10 +507,10 @@ _cairo_ft_unscaled_font_destroy (void *abstract_font)
&unscaled->base.hash_entry); &unscaled->base.hash_entry);
_font_map_release_face_lock_held (font_map, unscaled); _font_map_release_face_lock_held (font_map, unscaled);
_cairo_ft_unscaled_font_fini (unscaled);
_cairo_ft_unscaled_font_map_unlock (); _cairo_ft_unscaled_font_map_unlock ();
} }
_cairo_ft_unscaled_font_fini (unscaled);
} }
static cairo_bool_t static cairo_bool_t
@ -558,7 +568,7 @@ _cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled)
{ {
unscaled->lock_count--; unscaled->lock_count--;
CAIRO_MUTEX_UNLOCK (unscaled->mutex); CAIRO_MUTEX_UNLOCK (unscaled->mutex);
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
} }
@ -673,10 +683,8 @@ _cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled,
x_scale * 64.0, x_scale * 64.0,
y_scale * 64.0, y_scale * 64.0,
0, 0); 0, 0);
if (error) { if (error)
_cairo_error (CAIRO_STATUS_NO_MEMORY); return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_NO_MEMORY;
}
} else { } else {
double min_distance = DBL_MAX; double min_distance = DBL_MAX;
int i; int i;
@ -705,10 +713,8 @@ _cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled,
error = FT_Set_Pixel_Sizes (unscaled->face, error = FT_Set_Pixel_Sizes (unscaled->face,
unscaled->face->available_sizes[best_i].width, unscaled->face->available_sizes[best_i].width,
unscaled->face->available_sizes[best_i].height); unscaled->face->available_sizes[best_i].height);
if (error) { if (error)
_cairo_error (CAIRO_STATUS_NO_MEMORY); return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_NO_MEMORY;
}
} }
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
@ -762,10 +768,8 @@ _get_bitmap_surface (FT_Bitmap *bitmap,
assert (stride == bitmap->pitch); assert (stride == bitmap->pitch);
} else { } else {
data = _cairo_malloc_ab (height, stride); data = _cairo_malloc_ab (height, stride);
if (!data) { if (!data)
_cairo_error (CAIRO_STATUS_NO_MEMORY); return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_NO_MEMORY;
}
if (stride == bitmap->pitch) { if (stride == bitmap->pitch) {
memcpy (data, bitmap->buffer, stride * height); memcpy (data, bitmap->buffer, stride * height);
@ -812,10 +816,9 @@ _get_bitmap_surface (FT_Bitmap *bitmap,
data = bitmap->buffer; data = bitmap->buffer;
} else { } else {
data = _cairo_malloc_ab (height, stride); data = _cairo_malloc_ab (height, stride);
if (!data) { if (!data)
_cairo_error (CAIRO_STATUS_NO_MEMORY); return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_NO_MEMORY;
}
memcpy (data, bitmap->buffer, stride * height); memcpy (data, bitmap->buffer, stride * height);
} }
format = CAIRO_FORMAT_A8; format = CAIRO_FORMAT_A8;
@ -853,12 +856,11 @@ _get_bitmap_surface (FT_Bitmap *bitmap,
width_rgba = width; width_rgba = width;
stride = bitmap->pitch; stride = bitmap->pitch;
stride_rgba = (width_rgba * 4 + 3) & ~3; stride_rgba = (width_rgba * 4 + 3) & ~3;
data_rgba = calloc (1, stride_rgba * height); data_rgba = calloc (stride_rgba, height);
if (data_rgba == NULL) { if (data_rgba == NULL) {
if (own_buffer) if (own_buffer)
free (bitmap->buffer); free (bitmap->buffer);
_cairo_error (CAIRO_STATUS_NO_MEMORY); return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_NO_MEMORY;
} }
os = 1; os = 1;
@ -926,8 +928,7 @@ _get_bitmap_surface (FT_Bitmap *bitmap,
default: default:
if (own_buffer) if (own_buffer)
free (bitmap->buffer); free (bitmap->buffer);
_cairo_error (CAIRO_STATUS_NO_MEMORY); return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_NO_MEMORY;
} }
*surface = (cairo_image_surface_t *) *surface = (cairo_image_surface_t *)
@ -936,7 +937,7 @@ _get_bitmap_surface (FT_Bitmap *bitmap,
width, height, stride); width, height, stride);
if ((*surface)->base.status) { if ((*surface)->base.status) {
free (data); free (data);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
if (subpixel) if (subpixel)
@ -1009,7 +1010,7 @@ _render_glyph_outline (FT_Face face,
(*surface) = (cairo_image_surface_t *) (*surface) = (cairo_image_surface_t *)
cairo_image_surface_create_for_data (NULL, format, 0, 0, 0); cairo_image_surface_create_for_data (NULL, format, 0, 0, 0);
if ((*surface)->base.status) if ((*surface)->base.status)
return CAIRO_STATUS_NO_MEMORY; return (*surface)->base.status;
} else { } else {
matrix.xx = matrix.yy = 0x10000L; matrix.xx = matrix.yy = 0x10000L;
@ -1054,19 +1055,16 @@ _render_glyph_outline (FT_Face face,
bitmap.pitch = stride; bitmap.pitch = stride;
bitmap.width = width * hmul; bitmap.width = width * hmul;
bitmap.rows = height * vmul; bitmap.rows = height * vmul;
bitmap.buffer = calloc (1, stride * bitmap.rows); bitmap.buffer = calloc (stride, bitmap.rows);
if (bitmap.buffer == NULL) { if (bitmap.buffer == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY); return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_NO_MEMORY;
} }
FT_Outline_Translate (outline, -cbox.xMin*hmul, -cbox.yMin*vmul); FT_Outline_Translate (outline, -cbox.xMin*hmul, -cbox.yMin*vmul);
if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) { if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) {
free (bitmap.buffer); free (bitmap.buffer);
_cairo_error (CAIRO_STATUS_NO_MEMORY); return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_NO_MEMORY;
} }
status = _get_bitmap_surface (&bitmap, TRUE, font_options, surface); status = _get_bitmap_surface (&bitmap, TRUE, font_options, surface);
@ -1107,10 +1105,8 @@ _render_glyph_bitmap (FT_Face face,
error = FT_Render_Glyph (glyphslot, FT_RENDER_MODE_NORMAL); error = FT_Render_Glyph (glyphslot, FT_RENDER_MODE_NORMAL);
/* XXX ignoring all other errors for now. They are not fatal, typically /* XXX ignoring all other errors for now. They are not fatal, typically
* just a glyph-not-found. */ * just a glyph-not-found. */
if (error == FT_Err_Out_Of_Memory) { if (error == FT_Err_Out_Of_Memory)
_cairo_error (CAIRO_STATUS_NO_MEMORY); return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_NO_MEMORY;
}
status = _get_bitmap_surface (&glyphslot->bitmap, FALSE, font_options, surface); status = _get_bitmap_surface (&glyphslot->bitmap, FALSE, font_options, surface);
if (status) if (status)
@ -1207,7 +1203,7 @@ _transform_glyph_bitmap (cairo_matrix_t * shape,
width = (width + 3) & ~3; width = (width + 3) & ~3;
image = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); image = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
if (image->status) if (image->status)
return CAIRO_STATUS_NO_MEMORY; return image->status;
/* Initialize it to empty /* Initialize it to empty
*/ */
@ -1473,15 +1469,16 @@ _cairo_ft_options_merge (cairo_ft_options_t *options,
options->extra_flags = other->extra_flags; options->extra_flags = other->extra_flags;
} }
static cairo_scaled_font_t * static cairo_status_t
_cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled, _cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled,
cairo_font_face_t *font_face, cairo_font_face_t *font_face,
const cairo_matrix_t *font_matrix, const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm, const cairo_matrix_t *ctm,
const cairo_font_options_t *options, const cairo_font_options_t *options,
cairo_ft_options_t ft_options) cairo_ft_options_t ft_options,
cairo_scaled_font_t **font_out)
{ {
cairo_ft_scaled_font_t *scaled_font = NULL; cairo_ft_scaled_font_t *scaled_font;
FT_Face face; FT_Face face;
FT_Size_Metrics *metrics; FT_Size_Metrics *metrics;
cairo_font_extents_t fs_metrics; cairo_font_extents_t fs_metrics;
@ -1489,13 +1486,12 @@ _cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled,
face = _cairo_ft_unscaled_font_lock_face (unscaled); face = _cairo_ft_unscaled_font_lock_face (unscaled);
if (!face) if (!face)
return NULL; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
scaled_font = malloc (sizeof(cairo_ft_scaled_font_t)); scaled_font = malloc (sizeof(cairo_ft_scaled_font_t));
if (scaled_font == NULL) { if (scaled_font == NULL) {
_cairo_ft_unscaled_font_unlock_face (unscaled); status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
_cairo_error (CAIRO_STATUS_NO_MEMORY); goto FAIL;
return NULL;
} }
_cairo_unscaled_font_reference (&unscaled->base); _cairo_unscaled_font_reference (&unscaled->base);
@ -1513,20 +1509,40 @@ _cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled,
&cairo_ft_scaled_font_backend); &cairo_ft_scaled_font_backend);
if (status) { if (status) {
free (scaled_font); free (scaled_font);
_cairo_unscaled_font_destroy (&unscaled->base); goto FAIL;
_cairo_ft_unscaled_font_unlock_face (unscaled);
return NULL;
} }
status = _cairo_ft_unscaled_font_set_scale (unscaled, status = _cairo_ft_unscaled_font_set_scale (unscaled,
&scaled_font->base.scale); &scaled_font->base.scale);
if (status) { if (status) {
free (scaled_font); free (scaled_font);
_cairo_unscaled_font_destroy (&unscaled->base); goto FAIL;
_cairo_ft_unscaled_font_unlock_face (unscaled);
return NULL;
} }
/*
* Force non-AA drawing when using a bitmap strike that
* won't be resampled due to non-scaling transform
*/
if (!unscaled->have_shape &&
(scaled_font->ft_options.load_flags & FT_LOAD_NO_BITMAP) == 0 &&
scaled_font->ft_options.base.antialias != CAIRO_ANTIALIAS_NONE &&
(face->face_flags & FT_FACE_FLAG_FIXED_SIZES))
{
int i;
FT_Size_Metrics *size_metrics = &face->size->metrics;
for (i = 0; i < face->num_fixed_sizes; i++)
{
FT_Bitmap_Size *bitmap_size = &face->available_sizes[i];
if (bitmap_size->x_ppem == size_metrics->x_ppem * 64 &&
bitmap_size->y_ppem == size_metrics->y_ppem * 64)
{
scaled_font->ft_options.base.antialias = CAIRO_ANTIALIAS_NONE;
break;
}
}
}
metrics = &face->size->metrics; metrics = &face->size->metrics;
@ -1574,9 +1590,12 @@ _cairo_ft_scaled_font_create (cairo_ft_unscaled_font_t *unscaled,
_cairo_scaled_font_set_metrics (&scaled_font->base, &fs_metrics); _cairo_scaled_font_set_metrics (&scaled_font->base, &fs_metrics);
*font_out = &scaled_font->base;
FAIL:
_cairo_ft_unscaled_font_unlock_face (unscaled); _cairo_ft_unscaled_font_unlock_face (unscaled);
return &scaled_font->base; return status;
} }
cairo_bool_t cairo_bool_t
@ -1594,30 +1613,23 @@ _cairo_ft_scaled_font_create_toy (cairo_toy_font_face_t *toy_face,
{ {
FcPattern *pattern, *resolved; FcPattern *pattern, *resolved;
cairo_ft_unscaled_font_t *unscaled; cairo_ft_unscaled_font_t *unscaled;
cairo_scaled_font_t *new_font = NULL;
FcResult result; FcResult result;
int fcslant; int fcslant;
int fcweight; int fcweight;
cairo_matrix_t scale; cairo_matrix_t scale;
cairo_status_t status;
cairo_ft_font_transform_t sf; cairo_ft_font_transform_t sf;
cairo_ft_options_t ft_options; cairo_ft_options_t ft_options;
unsigned char *family = (unsigned char*) toy_face->family;
pattern = FcPatternCreate (); pattern = FcPatternCreate ();
if (!pattern) { if (!pattern)
_cairo_error (CAIRO_STATUS_NO_MEMORY); return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_NO_MEMORY;
}
switch (toy_face->weight) if (!FcPatternAddString (pattern,
FC_FAMILY, (unsigned char *) toy_face->family))
{ {
case CAIRO_FONT_WEIGHT_BOLD: status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
fcweight = FC_WEIGHT_BOLD; goto FREE_PATTERN;
break;
case CAIRO_FONT_WEIGHT_NORMAL:
default:
fcweight = FC_WEIGHT_MEDIUM;
break;
} }
switch (toy_face->slant) switch (toy_face->slant)
@ -1634,36 +1646,65 @@ _cairo_ft_scaled_font_create_toy (cairo_toy_font_face_t *toy_face,
break; break;
} }
if (!FcPatternAddString (pattern, FC_FAMILY, family)) if (!FcPatternAddInteger (pattern, FC_SLANT, fcslant)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FREE_PATTERN; goto FREE_PATTERN;
if (!FcPatternAddInteger (pattern, FC_SLANT, fcslant)) }
goto FREE_PATTERN;
if (!FcPatternAddInteger (pattern, FC_WEIGHT, fcweight)) switch (toy_face->weight)
{
case CAIRO_FONT_WEIGHT_BOLD:
fcweight = FC_WEIGHT_BOLD;
break;
case CAIRO_FONT_WEIGHT_NORMAL:
default:
fcweight = FC_WEIGHT_MEDIUM;
break;
}
if (!FcPatternAddInteger (pattern, FC_WEIGHT, fcweight)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FREE_PATTERN; goto FREE_PATTERN;
}
cairo_matrix_multiply (&scale, font_matrix, ctm); cairo_matrix_multiply (&scale, font_matrix, ctm);
_compute_transform (&sf, &scale); _compute_transform (&sf, &scale);
FcPatternAddInteger (pattern, FC_PIXEL_SIZE, sf.y_scale); if (! FcPatternAddInteger (pattern, FC_PIXEL_SIZE, sf.y_scale)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FREE_PATTERN;
}
if (! FcConfigSubstitute (NULL, pattern, FcMatchPattern)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FREE_PATTERN;
}
status = _cairo_ft_font_options_substitute (font_options, pattern);
if (status)
goto FREE_PATTERN;
FcConfigSubstitute (NULL, pattern, FcMatchPattern);
cairo_ft_font_options_substitute (font_options, pattern);
FcDefaultSubstitute (pattern); FcDefaultSubstitute (pattern);
resolved = FcFontMatch (NULL, pattern, &result); resolved = FcFontMatch (NULL, pattern, &result);
if (!resolved) if (!resolved) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FREE_PATTERN; goto FREE_PATTERN;
}
unscaled = _cairo_ft_unscaled_font_create_for_pattern (resolved); unscaled = _cairo_ft_unscaled_font_create_for_pattern (resolved);
if (!unscaled) if (!unscaled) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FREE_RESOLVED; goto FREE_RESOLVED;
}
_get_pattern_ft_options (resolved, &ft_options); _get_pattern_ft_options (resolved, &ft_options);
new_font = _cairo_ft_scaled_font_create (unscaled, status = _cairo_ft_scaled_font_create (unscaled,
&toy_face->base, &toy_face->base,
font_matrix, ctm, font_matrix, ctm,
font_options, ft_options); font_options, ft_options,
font);
_cairo_unscaled_font_destroy (&unscaled->base); _cairo_unscaled_font_destroy (&unscaled->base);
@ -1673,13 +1714,7 @@ _cairo_ft_scaled_font_create_toy (cairo_toy_font_face_t *toy_face,
FREE_PATTERN: FREE_PATTERN:
FcPatternDestroy (pattern); FcPatternDestroy (pattern);
if (new_font) { return status;
*font = new_font;
return CAIRO_STATUS_SUCCESS;
} else {
_cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_NO_MEMORY;
}
} }
static void static void
@ -1736,8 +1771,7 @@ _conic_to (FT_Vector *control, FT_Vector *to, void *closure)
cairo_fixed_t x3, y3; cairo_fixed_t x3, y3;
cairo_point_t conic; cairo_point_t conic;
if (_cairo_path_fixed_get_current_point (path, &x0, &y0) != if (! _cairo_path_fixed_get_current_point (path, &x0, &y0))
CAIRO_STATUS_SUCCESS)
return 1; return 1;
conic.x = _cairo_fixed_from_26_6 (control->x); conic.x = _cairo_fixed_from_26_6 (control->x);
@ -1812,7 +1846,7 @@ _decompose_glyph_outline (FT_Face face,
path = _cairo_path_fixed_create (); path = _cairo_path_fixed_create ();
if (!path) if (!path)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
glyph = face->glyph; glyph = face->glyph;
@ -1820,8 +1854,7 @@ _decompose_glyph_outline (FT_Face face,
FT_Outline_Transform (&glyph->outline, &invert_y); FT_Outline_Transform (&glyph->outline, &invert_y);
if (FT_Outline_Decompose (&glyph->outline, &outline_funcs, path)) { if (FT_Outline_Decompose (&glyph->outline, &outline_funcs, path)) {
_cairo_path_fixed_destroy (path); _cairo_path_fixed_destroy (path);
_cairo_error (CAIRO_STATUS_NO_MEMORY); return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_NO_MEMORY;
} }
status = _cairo_path_fixed_close_path (path); status = _cairo_path_fixed_close_path (path);
@ -1876,7 +1909,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
face = _cairo_ft_unscaled_font_lock_face (unscaled); face = _cairo_ft_unscaled_font_lock_face (unscaled);
if (!face) if (!face)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled, status = _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled,
&scaled_font->base.scale); &scaled_font->base.scale);
@ -1905,7 +1938,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
/* XXX ignoring all other errors for now. They are not fatal, typically /* XXX ignoring all other errors for now. They are not fatal, typically
* just a glyph-not-found. */ * just a glyph-not-found. */
if (error == FT_Err_Out_Of_Memory) { if (error == FT_Err_Out_Of_Memory) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FAIL; goto FAIL;
} }
@ -2044,7 +2077,7 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
} }
if (info & CAIRO_SCALED_GLYPH_INFO_PATH) { if (info & CAIRO_SCALED_GLYPH_INFO_PATH) {
cairo_path_fixed_t *path; cairo_path_fixed_t *path = NULL; /* hide compiler warning */
/* /*
* A kludge -- the above code will trash the outline, * A kludge -- the above code will trash the outline,
@ -2057,9 +2090,8 @@ _cairo_ft_scaled_glyph_init (void *abstract_font,
/* XXX ignoring all other errors for now. They are not fatal, typically /* XXX ignoring all other errors for now. They are not fatal, typically
* just a glyph-not-found. */ * just a glyph-not-found. */
if (error == FT_Err_Out_Of_Memory) { if (error == FT_Err_Out_Of_Memory) {
_cairo_ft_unscaled_font_unlock_face (unscaled); status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
_cairo_error (CAIRO_STATUS_NO_MEMORY); goto FAIL;
return CAIRO_STATUS_NO_MEMORY;
} }
#if HAVE_FT_GLYPHSLOT_EMBOLDEN #if HAVE_FT_GLYPHSLOT_EMBOLDEN
/* /*
@ -2126,7 +2158,7 @@ _cairo_ft_load_truetype_table (void *abstract_font,
#if HAVE_FT_LOAD_SFNT_TABLE #if HAVE_FT_LOAD_SFNT_TABLE
face = _cairo_ft_unscaled_font_lock_face (unscaled); face = _cairo_ft_unscaled_font_lock_face (unscaled);
if (!face) if (!face)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (FT_IS_SFNT (face) && if (FT_IS_SFNT (face) &&
FT_Load_Sfnt_Table (face, tag, offset, buffer, length) == 0) FT_Load_Sfnt_Table (face, tag, offset, buffer, length) == 0)
@ -2211,7 +2243,7 @@ _cairo_ft_font_face_destroy (void *abstract_face)
if (font_face->unscaled && if (font_face->unscaled &&
font_face->unscaled->from_face && font_face->unscaled->from_face &&
font_face->unscaled->base.ref_count > 1) CAIRO_REFERENCE_COUNT_GET_VALUE (&font_face->unscaled->base.ref_count) > 1)
{ {
cairo_font_face_reference (&font_face->base); cairo_font_face_reference (&font_face->base);
@ -2264,16 +2296,11 @@ _cairo_ft_font_face_scaled_font_create (void *abstract_face,
ft_options = font_face->ft_options; ft_options = font_face->ft_options;
*scaled_font = _cairo_ft_scaled_font_create (font_face->unscaled, return _cairo_ft_scaled_font_create (font_face->unscaled,
&font_face->base, &font_face->base,
font_matrix, ctm, font_matrix, ctm,
options, ft_options); options, ft_options,
if (*scaled_font) { scaled_font);
return CAIRO_STATUS_SUCCESS;
} else {
_cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_NO_MEMORY;
}
} }
static const cairo_font_face_backend_t _cairo_ft_font_face_backend = { static const cairo_font_face_backend_t _cairo_ft_font_face_backend = {
@ -2309,7 +2336,7 @@ _cairo_ft_font_face_create (cairo_ft_unscaled_font_t *unscaled,
/* No match found, create a new one */ /* No match found, create a new one */
font_face = malloc (sizeof (cairo_ft_font_face_t)); font_face = malloc (sizeof (cairo_ft_font_face_t));
if (!font_face) { if (!font_face) {
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
} }
@ -2328,20 +2355,9 @@ _cairo_ft_font_face_create (cairo_ft_unscaled_font_t *unscaled,
/* implement the platform-specific interface */ /* implement the platform-specific interface */
/** static cairo_status_t
* cairo_ft_font_options_substitute: _cairo_ft_font_options_substitute (const cairo_font_options_t *options,
* @options: a #cairo_font_options_t object FcPattern *pattern)
* @pattern: an existing #FcPattern
*
* Add options to a #FcPattern based on a #cairo_font_options_t font
* options object. Options that are already in the pattern, are not overridden,
* so you should call this function after calling FcConfigSubstitute() (the
* user's settings should override options based on the surface type), but
* before calling FcDefaultSubstitute().
**/
void
cairo_ft_font_options_substitute (const cairo_font_options_t *options,
FcPattern *pattern)
{ {
FcValue v; FcValue v;
@ -2349,10 +2365,15 @@ cairo_ft_font_options_substitute (const cairo_font_options_t *options,
{ {
if (FcPatternGet (pattern, FC_ANTIALIAS, 0, &v) == FcResultNoMatch) if (FcPatternGet (pattern, FC_ANTIALIAS, 0, &v) == FcResultNoMatch)
{ {
FcPatternAddBool (pattern, FC_ANTIALIAS, options->antialias != CAIRO_ANTIALIAS_NONE); if (! FcPatternAddBool (pattern,
FC_ANTIALIAS,
options->antialias != CAIRO_ANTIALIAS_NONE))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (options->antialias != CAIRO_ANTIALIAS_SUBPIXEL) { if (options->antialias != CAIRO_ANTIALIAS_SUBPIXEL) {
FcPatternDel (pattern, FC_RGBA); FcPatternDel (pattern, FC_RGBA);
FcPatternAddInteger (pattern, FC_RGBA, FC_RGBA_NONE); if (! FcPatternAddInteger (pattern, FC_RGBA, FC_RGBA_NONE))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
} }
} }
@ -2384,7 +2405,8 @@ cairo_ft_font_options_substitute (const cairo_font_options_t *options,
rgba = FC_RGBA_NONE; rgba = FC_RGBA_NONE;
} }
FcPatternAddInteger (pattern, FC_RGBA, rgba); if (! FcPatternAddInteger (pattern, FC_RGBA, rgba))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
} }
@ -2392,7 +2414,10 @@ cairo_ft_font_options_substitute (const cairo_font_options_t *options,
{ {
if (FcPatternGet (pattern, FC_HINTING, 0, &v) == FcResultNoMatch) if (FcPatternGet (pattern, FC_HINTING, 0, &v) == FcResultNoMatch)
{ {
FcPatternAddBool (pattern, FC_HINTING, options->hint_style != CAIRO_HINT_STYLE_NONE); if (! FcPatternAddBool (pattern,
FC_HINTING,
options->hint_style != CAIRO_HINT_STYLE_NONE))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
#ifdef FC_HINT_STYLE #ifdef FC_HINT_STYLE
@ -2417,12 +2442,32 @@ cairo_ft_font_options_substitute (const cairo_font_options_t *options,
break; break;
} }
FcPatternAddInteger (pattern, FC_HINT_STYLE, hint_style); if (! FcPatternAddInteger (pattern, FC_HINT_STYLE, hint_style))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
#endif #endif
} }
return CAIRO_STATUS_SUCCESS;
}
/**
* cairo_ft_font_options_substitute:
* @options: a #cairo_font_options_t object
* @pattern: an existing #FcPattern
*
* Add options to a #FcPattern based on a #cairo_font_options_t font
* options object. Options that are already in the pattern, are not overridden,
* so you should call this function after calling FcConfigSubstitute() (the
* user's settings should override options based on the surface type), but
* before calling FcDefaultSubstitute().
**/
void
cairo_ft_font_options_substitute (const cairo_font_options_t *options,
FcPattern *pattern)
{
_cairo_ft_font_options_substitute (options, pattern);
} }
slim_hidden_def (cairo_ft_font_options_substitute);
/** /**
* cairo_ft_font_face_create_for_pattern: * cairo_ft_font_face_create_for_pattern:
@ -2459,7 +2504,7 @@ cairo_ft_font_face_create_for_pattern (FcPattern *pattern)
unscaled = _cairo_ft_unscaled_font_create_for_pattern (pattern); unscaled = _cairo_ft_unscaled_font_create_for_pattern (pattern);
if (unscaled == NULL) { if (unscaled == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_font_face_t *)&_cairo_font_face_nil; return (cairo_font_face_t *)&_cairo_font_face_nil;
} }
@ -2509,7 +2554,7 @@ cairo_ft_font_face_create_for_ft_face (FT_Face face,
unscaled = _cairo_ft_unscaled_font_create_from_face (face); unscaled = _cairo_ft_unscaled_font_create_from_face (face);
if (unscaled == NULL) { if (unscaled == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_font_face_t *)&_cairo_font_face_nil; return (cairo_font_face_t *)&_cairo_font_face_nil;
} }
@ -2568,7 +2613,7 @@ cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font)
face = _cairo_ft_unscaled_font_lock_face (scaled_font->unscaled); face = _cairo_ft_unscaled_font_lock_face (scaled_font->unscaled);
if (face == NULL) { if (face == NULL) {
_cairo_scaled_font_set_error (&scaled_font->base, CAIRO_STATUS_NO_MEMORY); status = _cairo_scaled_font_set_error (&scaled_font->base, CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
} }
@ -2576,7 +2621,7 @@ cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font)
&scaled_font->base.scale); &scaled_font->base.scale);
if (status) { if (status) {
_cairo_ft_unscaled_font_unlock_face (scaled_font->unscaled); _cairo_ft_unscaled_font_unlock_face (scaled_font->unscaled);
_cairo_scaled_font_set_error (&scaled_font->base, status); status = _cairo_scaled_font_set_error (&scaled_font->base, status);
return NULL; return NULL;
} }

View File

@ -67,7 +67,6 @@ _cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled);
cairo_private cairo_bool_t cairo_private cairo_bool_t
_cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font); _cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font);
slim_hidden_proto (cairo_ft_font_options_substitute);
slim_hidden_proto (cairo_ft_scaled_font_lock_face); slim_hidden_proto (cairo_ft_scaled_font_lock_face);
slim_hidden_proto (cairo_ft_scaled_font_unlock_face); slim_hidden_proto (cairo_ft_scaled_font_unlock_face);

View File

@ -89,7 +89,7 @@ _cairo_glitz_surface_create_similar (void *abstract_src,
glitz_find_standard_format (drawable, glitz_find_standard_format (drawable,
_glitz_format_from_content (content)); _glitz_format_from_content (content));
if (!gformat) { if (!gformat) {
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
} }
@ -99,7 +99,7 @@ _cairo_glitz_surface_create_similar (void *abstract_src,
0, NULL); 0, NULL);
if (surface == NULL) { if (surface == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
} }
@ -165,8 +165,10 @@ _cairo_glitz_get_boxes_from_region (cairo_region_t *region, int *nboxes)
return NULL; return NULL;
gboxes = _cairo_malloc_ab (n, sizeof(glitz_box_t)); gboxes = _cairo_malloc_ab (n, sizeof(glitz_box_t));
if (gboxes == NULL) if (gboxes == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
goto done; goto done;
}
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
gboxes[i].x1 = cboxes[i].p1.x; gboxes[i].x1 = cboxes[i].p1.x;
@ -270,12 +272,12 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
pixels = _cairo_malloc_ab (height, pf.bytes_per_line); pixels = _cairo_malloc_ab (height, pf.bytes_per_line);
if (!pixels) if (!pixels)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
buffer = glitz_buffer_create_for_data (pixels); buffer = glitz_buffer_create_for_data (pixels);
if (!buffer) { if (!buffer) {
free (pixels); free (pixels);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
/* clear out the glitz clip; the clip affects glitz_get_pixels */ /* clear out the glitz clip; the clip affects glitz_get_pixels */
@ -299,7 +301,7 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
box = _cairo_glitz_get_boxes_from_region (&surface->clip, &n); box = _cairo_glitz_get_boxes_from_region (&surface->clip, &n);
if (box == NULL && n != 0) { if (box == NULL && n != 0) {
free (pixels); free (pixels);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
glitz_surface_set_clip_region (surface->surface, 0, 0, box, n); glitz_surface_set_clip_region (surface->surface, 0, 0, box, n);
@ -345,7 +347,7 @@ _cairo_glitz_surface_get_image (cairo_glitz_surface_t *surface,
FAIL: FAIL:
free (pixels); free (pixels);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
static void static void
@ -428,7 +430,7 @@ _cairo_glitz_surface_set_image (void *abstract_surface,
buffer = glitz_buffer_create_for_data (data); buffer = glitz_buffer_create_for_data (data);
if (!buffer) if (!buffer)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
glitz_set_pixels (surface->surface, glitz_set_pixels (surface->surface,
x_dst, y_dst, x_dst, y_dst,
@ -491,10 +493,13 @@ _cairo_glitz_surface_release_dest_image (void *abstract_surfa
void *image_extra) void *image_extra)
{ {
cairo_glitz_surface_t *surface = abstract_surface; cairo_glitz_surface_t *surface = abstract_surface;
cairo_status_t status;
_cairo_glitz_surface_set_image (surface, image, 0, 0, status = _cairo_glitz_surface_set_image (surface, image, 0, 0,
image->width, image->height, image->width, image->height,
image_rect->x, image_rect->y); image_rect->x, image_rect->y);
if (status)
status = _cairo_surface_set_error (&surface->base, status);
cairo_surface_destroy (&image->base); cairo_surface_destroy (&image->base);
} }
@ -510,6 +515,7 @@ _cairo_glitz_surface_clone_similar (void *abstract_surface,
{ {
cairo_glitz_surface_t *surface = abstract_surface; cairo_glitz_surface_t *surface = abstract_surface;
cairo_glitz_surface_t *clone; cairo_glitz_surface_t *clone;
cairo_status_t status;
if (surface->base.status) if (surface->base.status)
return surface->base.status; return surface->base.status;
@ -534,7 +540,7 @@ _cairo_glitz_surface_clone_similar (void *abstract_surface,
image_src->width, image_src->width,
image_src->height); image_src->height);
if (clone->base.status) if (clone->base.status)
return CAIRO_STATUS_NO_MEMORY; return clone->base.status;
image_extent.x = 0; image_extent.x = 0;
image_extent.y = 0; image_extent.y = 0;
@ -547,10 +553,14 @@ _cairo_glitz_surface_clone_similar (void *abstract_surface,
_cairo_rectangle_intersect(&extent, &image_extent); _cairo_rectangle_intersect(&extent, &image_extent);
_cairo_glitz_surface_set_image (clone, image_src, status = _cairo_glitz_surface_set_image (clone, image_src,
extent.x, extent.y, extent.x, extent.y,
extent.width, extent.height, extent.width, extent.height,
extent.x, extent.y); extent.x, extent.y);
if (status) {
cairo_surface_destroy (&clone->base);
return status;
}
*clone_out = &clone->base; *clone_out = &clone->base;
@ -764,29 +774,28 @@ _cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern,
int size1, size2; int size1, size2;
if (n_params >= INT32_MAX / sizeof (glitz_fixed16_16_t) || if (n_params >= INT32_MAX / sizeof (glitz_fixed16_16_t) ||
gradient->n_stops >= INT32_MAX / sizeof (unsigned int)) gradient->n_stops >= INT32_MAX / sizeof (unsigned int))
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
size1 = n_params * sizeof (glitz_fixed16_16_t); size1 = n_params * sizeof (glitz_fixed16_16_t);
size2 = gradient->n_stops * sizeof (unsigned int); size2 = gradient->n_stops * sizeof (unsigned int);
if (size1 >= INT32_MAX - size2) if (size1 >= INT32_MAX - size2)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
data = malloc (size1 + size2); data = malloc (size1 + size2);
} }
if (!data) if (!data)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
params = (glitz_fixed16_16_t *) data; params = (glitz_fixed16_16_t *) data;
pixels = (unsigned int *) pixels = (unsigned int *)
(data + sizeof (glitz_fixed16_16_t) * n_params); (data + sizeof (glitz_fixed16_16_t) * n_params);
buffer = glitz_buffer_create_for_data (pixels); buffer = glitz_buffer_create_for_data (pixels);
if (!buffer) if (!buffer) {
{
free (data); free (data);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
src = (cairo_glitz_surface_t *) src = (cairo_glitz_surface_t *)
@ -797,7 +806,7 @@ _cairo_glitz_pattern_acquire_surface (cairo_pattern_t *pattern,
{ {
glitz_buffer_destroy (buffer); glitz_buffer_destroy (buffer);
free (data); free (data);
return CAIRO_STATUS_NO_MEMORY; return src->base.status;
} }
for (i = 0; i < gradient->n_stops; i++) for (i = 0; i < gradient->n_stops; i++)
@ -1158,7 +1167,7 @@ _cairo_glitz_surface_fill_rectangles (void *abstract_dst,
(cairo_color_t *) color, (cairo_color_t *) color,
NULL); NULL);
if (src->base.status) if (src->base.status)
return CAIRO_STATUS_NO_MEMORY; return src->base.status;
glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT); glitz_surface_set_fill (src->surface, GLITZ_FILL_REPEAT);
@ -1277,7 +1286,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
if (src_pattern == &tmp_src_pattern.base) if (src_pattern == &tmp_src_pattern.base)
_cairo_pattern_fini (&tmp_src_pattern.base); _cairo_pattern_fini (&tmp_src_pattern.base);
return CAIRO_STATUS_NO_MEMORY; return mask->base.status;
} }
color.red = color.green = color.blue = color.alpha = 0xffff; color.red = color.green = color.blue = color.alpha = 0xffff;
@ -1304,7 +1313,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
&attributes); &attributes);
if (src_pattern == &tmp_src_pattern.base) if (src_pattern == &tmp_src_pattern.base)
_cairo_pattern_fini (&tmp_src_pattern.base); _cairo_pattern_fini (&tmp_src_pattern.base);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
if (buffer) if (buffer)
@ -1317,7 +1326,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
&attributes); &attributes);
if (src_pattern == &tmp_src_pattern.base) if (src_pattern == &tmp_src_pattern.base)
_cairo_pattern_fini (&tmp_src_pattern.base); _cairo_pattern_fini (&tmp_src_pattern.base);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
} }
@ -1347,13 +1356,13 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
int stride; int stride;
stride = (width + 3) & -4; stride = (width + 3) & -4;
data = calloc (stride * height, 1); data = calloc (stride, height);
if (!data) if (!data)
{ {
_cairo_glitz_pattern_release_surface (src_pattern, src, &attributes); _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes);
if (src_pattern == &tmp_src_pattern.base) if (src_pattern == &tmp_src_pattern.base)
_cairo_pattern_fini (&tmp_src_pattern.base); _cairo_pattern_fini (&tmp_src_pattern.base);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
/* using negative stride */ /* using negative stride */
@ -1368,7 +1377,7 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
{ {
cairo_surface_destroy (&src->base); cairo_surface_destroy (&src->base);
free (data); free (data);
return CAIRO_STATUS_NO_MEMORY; return image->base.status;
} }
pixman_add_trapezoids (image->pixman_image, -dst_x, -dst_y, pixman_add_trapezoids (image->pixman_image, -dst_x, -dst_y,
@ -1383,12 +1392,16 @@ _cairo_glitz_surface_composite_trapezoids (cairo_operator_t op,
_cairo_glitz_pattern_release_surface (src_pattern, src, &attributes); _cairo_glitz_pattern_release_surface (src_pattern, src, &attributes);
free (data); free (data);
cairo_surface_destroy (&image->base); cairo_surface_destroy (&image->base);
return CAIRO_STATUS_NO_MEMORY; return mask->base.status;
} }
_cairo_glitz_surface_set_image (mask, image, 0, 0, width, height, 0, 0); status = _cairo_glitz_surface_set_image (mask, image,
0, 0, width, height, 0, 0);
cairo_surface_destroy(&image->base); cairo_surface_destroy(&image->base);
if (status)
return status;
} }
_cairo_glitz_surface_set_attributes (src, &attributes); _cairo_glitz_surface_set_attributes (src, &attributes);
@ -1438,24 +1451,25 @@ _cairo_glitz_surface_set_clip_region (void *abstract_surface,
{ {
glitz_box_t *box; glitz_box_t *box;
int n; int n;
cairo_status_t status;
if (!surface->has_clip) { if (!surface->has_clip) {
_cairo_region_init (&surface->clip); _cairo_region_init (&surface->clip);
surface->has_clip = TRUE; surface->has_clip = TRUE;
} }
if (_cairo_region_copy (&surface->clip, region) != CAIRO_STATUS_SUCCESS) status = _cairo_region_copy (&surface->clip, region);
{ if (status) {
_cairo_region_fini (&surface->clip); _cairo_region_fini (&surface->clip);
surface->has_clip = FALSE; surface->has_clip = FALSE;
return CAIRO_STATUS_NO_MEMORY; return status;
} }
box = _cairo_glitz_get_boxes_from_region (&surface->clip, &n); box = _cairo_glitz_get_boxes_from_region (&surface->clip, &n);
if (box == NULL && n != 0) { if (box == NULL && n != 0) {
_cairo_region_fini (&surface->clip); _cairo_region_fini (&surface->clip);
surface->has_clip = FALSE; surface->has_clip = FALSE;
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
glitz_surface_set_clip_region (surface->surface, 0, 0, box, n); glitz_surface_set_clip_region (surface->surface, 0, 0, box, n);
@ -1565,8 +1579,10 @@ _cairo_glitz_area_create (cairo_glitz_root_area_t *root,
int n = 4; int n = 4;
area = malloc (sizeof (cairo_glitz_area_t)); area = malloc (sizeof (cairo_glitz_area_t));
if (!area) if (!area) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
}
area->level = level; area->level = level;
area->x = x; area->x = x;
@ -1788,7 +1804,7 @@ _cairo_glitz_root_area_init (cairo_glitz_root_area_t *root,
root->area = _cairo_glitz_area_create (root, 0, 0, 0, width, height); root->area = _cairo_glitz_area_create (root, 0, 0, 0, width, height);
if (!root->area) if (!root->area)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -1901,7 +1917,7 @@ _cairo_glitz_surface_font_init (cairo_glitz_surface_t *surface,
font_private = malloc (sizeof (cairo_glitz_surface_font_private_t)); font_private = malloc (sizeof (cairo_glitz_surface_font_private_t));
if (!font_private) if (!font_private)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font_private->surface = glitz_surface_create (drawable, surface_format, font_private->surface = glitz_surface_create (drawable, surface_format,
GLYPH_CACHE_TEXTURE_SIZE, GLYPH_CACHE_TEXTURE_SIZE,
@ -1987,7 +2003,7 @@ _cairo_glitz_surface_add_glyph (cairo_glitz_surface_t *surface,
{ {
glyph_private = malloc (sizeof (cairo_glitz_surface_glyph_private_t)); glyph_private = malloc (sizeof (cairo_glitz_surface_glyph_private_t));
if (!glyph_private) if (!glyph_private)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
glyph_private->area = NULL; glyph_private->area = NULL;
glyph_private->locked = FALSE; glyph_private->locked = FALSE;
@ -2031,7 +2047,7 @@ _cairo_glitz_surface_add_glyph (cairo_glitz_surface_t *surface,
if (!buffer) if (!buffer)
{ {
_cairo_glitz_area_move_out (glyph_private->area); _cairo_glitz_area_move_out (glyph_private->area);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
cairo_format_get_masks (glyph_surface->format, &bpp, &am, &rm, &gm, &bm); cairo_format_get_masks (glyph_surface->format, &bpp, &am, &rm, &gm, &bm);
@ -2151,8 +2167,10 @@ _cairo_glitz_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
goto FAIL1; goto FAIL1;
data = malloc (size1 + size2); data = malloc (size1 + size2);
if (!data) if (!data) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
goto FAIL1; goto FAIL1;
}
scaled_glyphs = (cairo_scaled_glyph_t **) data; scaled_glyphs = (cairo_scaled_glyph_t **) data;
vertices = (glitz_float_t *) (data + num_glyphs * sizeof (void *)); vertices = (glitz_float_t *) (data + num_glyphs * sizeof (void *));
@ -2440,7 +2458,7 @@ cairo_glitz_surface_create (glitz_surface_t *surface)
crsurface = malloc (sizeof (cairo_glitz_surface_t)); crsurface = malloc (sizeof (cairo_glitz_surface_t));
if (crsurface == NULL) { if (crsurface == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
} }

View File

@ -62,6 +62,8 @@ cairo_status_t
_cairo_gstate_init (cairo_gstate_t *gstate, _cairo_gstate_init (cairo_gstate_t *gstate,
cairo_surface_t *target) cairo_surface_t *target)
{ {
cairo_status_t status;
gstate->next = NULL; gstate->next = NULL;
gstate->op = CAIRO_GSTATE_OPERATOR_DEFAULT; gstate->op = CAIRO_GSTATE_OPERATOR_DEFAULT;
@ -93,10 +95,23 @@ _cairo_gstate_init (cairo_gstate_t *gstate,
gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK, gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK,
CAIRO_CONTENT_COLOR); CAIRO_CONTENT_COLOR);
if (gstate->source->status)
return CAIRO_STATUS_NO_MEMORY;
return target ? target->status : CAIRO_STATUS_NULL_POINTER; /* Now that the gstate is fully initialized and ready for the eventual
* _cairo_gstate_fini(), we can check for errors (and not worry about
* the resource deallocation). */
if (target == NULL)
return _cairo_error (CAIRO_STATUS_NULL_POINTER);
status = target->status;
if (status)
return status;
status = gstate->source->status;
if (status)
return status;
return CAIRO_STATUS_SUCCESS;
} }
/** /**
@ -131,8 +146,12 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
_cairo_font_options_init_copy (&gstate->font_options , &other->font_options); _cairo_font_options_init_copy (&gstate->font_options , &other->font_options);
status = _cairo_clip_init_copy (&gstate->clip, &other->clip); status = _cairo_clip_init_copy (&gstate->clip, &other->clip);
if (status) if (status) {
_cairo_stroke_style_fini (&gstate->stroke_style);
cairo_font_face_destroy (gstate->font_face);
cairo_scaled_font_destroy (gstate->scaled_font);
return status; return status;
}
gstate->target = cairo_surface_reference (other->target); gstate->target = cairo_surface_reference (other->target);
/* parent_target is always set to NULL; it's only ever set by redirect_target */ /* parent_target is always set to NULL; it's only ever set by redirect_target */
@ -170,7 +189,7 @@ _cairo_gstate_fini (cairo_gstate_t *gstate)
gstate->parent_target = NULL; gstate->parent_target = NULL;
cairo_surface_destroy (gstate->original_target); cairo_surface_destroy (gstate->original_target);
gstate->target = NULL; gstate->original_target = NULL;
cairo_pattern_destroy (gstate->source); cairo_pattern_destroy (gstate->source);
gstate->source = NULL; gstate->source = NULL;
@ -207,8 +226,10 @@ _cairo_gstate_clone (cairo_gstate_t *other)
assert (other != NULL); assert (other != NULL);
gstate = malloc (sizeof (cairo_gstate_t)); gstate = malloc (sizeof (cairo_gstate_t));
if (gstate == NULL) if (gstate == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
}
status = _cairo_gstate_init_copy (gstate, other); status = _cairo_gstate_init_copy (gstate, other);
if (status) { if (status) {
@ -233,10 +254,8 @@ _cairo_gstate_save (cairo_gstate_t **gstate)
cairo_gstate_t *top; cairo_gstate_t *top;
top = _cairo_gstate_clone (*gstate); top = _cairo_gstate_clone (*gstate);
if (top == NULL)
if (top == NULL) { return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_NO_MEMORY;
}
top->next = *gstate; top->next = *gstate;
*gstate = top; *gstate = top;
@ -256,10 +275,8 @@ _cairo_gstate_restore (cairo_gstate_t **gstate)
cairo_gstate_t *top; cairo_gstate_t *top;
top = *gstate; top = *gstate;
if (top->next == NULL)
if (top->next == NULL) { return _cairo_error (CAIRO_STATUS_INVALID_RESTORE);
return CAIRO_STATUS_INVALID_RESTORE;
}
*gstate = top->next; *gstate = top->next;
@ -533,7 +550,7 @@ _cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dash
gstate->stroke_style.dash = _cairo_malloc_ab (gstate->stroke_style.num_dashes, sizeof (double)); gstate->stroke_style.dash = _cairo_malloc_ab (gstate->stroke_style.num_dashes, sizeof (double));
if (gstate->stroke_style.dash == NULL) { if (gstate->stroke_style.dash == NULL) {
gstate->stroke_style.num_dashes = 0; gstate->stroke_style.num_dashes = 0;
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
memcpy (gstate->stroke_style.dash, dash, gstate->stroke_style.num_dashes * sizeof (double)); memcpy (gstate->stroke_style.dash, dash, gstate->stroke_style.num_dashes * sizeof (double));
@ -541,12 +558,12 @@ _cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dash
dash_total = 0.0; dash_total = 0.0;
for (i = 0; i < gstate->stroke_style.num_dashes; i++) { for (i = 0; i < gstate->stroke_style.num_dashes; i++) {
if (gstate->stroke_style.dash[i] < 0) if (gstate->stroke_style.dash[i] < 0)
return CAIRO_STATUS_INVALID_DASH; return _cairo_error (CAIRO_STATUS_INVALID_DASH);
dash_total += gstate->stroke_style.dash[i]; dash_total += gstate->stroke_style.dash[i];
} }
if (dash_total == 0.0) if (dash_total == 0.0)
return CAIRO_STATUS_INVALID_DASH; return _cairo_error (CAIRO_STATUS_INVALID_DASH);
/* A single dash value indicate symmetric repeating, so the total /* A single dash value indicate symmetric repeating, so the total
* is twice as long. */ * is twice as long. */
@ -606,6 +623,9 @@ _cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty)
{ {
cairo_matrix_t tmp; cairo_matrix_t tmp;
if (! (tx * tx >= 0.) || ! (ty * ty >= 0.)) /* check for NaNs */
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
_cairo_gstate_unset_scaled_font (gstate); _cairo_gstate_unset_scaled_font (gstate);
cairo_matrix_init_translate (&tmp, tx, ty); cairo_matrix_init_translate (&tmp, tx, ty);
@ -622,8 +642,10 @@ _cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy)
{ {
cairo_matrix_t tmp; cairo_matrix_t tmp;
if (sx == 0 || sy == 0) if (sx * sy == 0.) /* either sx or sy is 0, or det == 0 due to underflow */
return CAIRO_STATUS_INVALID_MATRIX; return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
if (! (sx * sx > 0.) || ! (sy * sy > 0.)) /* check for NaNs */
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
_cairo_gstate_unset_scaled_font (gstate); _cairo_gstate_unset_scaled_font (gstate);
@ -641,6 +663,12 @@ _cairo_gstate_rotate (cairo_gstate_t *gstate, double angle)
{ {
cairo_matrix_t tmp; cairo_matrix_t tmp;
if (angle == 0.)
return CAIRO_STATUS_SUCCESS;
if (! (angle * angle >= 0.)) /* check for NaNs */
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
_cairo_gstate_unset_scaled_font (gstate); _cairo_gstate_unset_scaled_font (gstate);
cairo_matrix_init_rotate (&tmp, angle); cairo_matrix_init_rotate (&tmp, angle);
@ -996,7 +1024,7 @@ _cairo_gstate_in_stroke (cairo_gstate_t *gstate,
double y, double y,
cairo_bool_t *inside_ret) cairo_bool_t *inside_ret)
{ {
cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_status_t status;
cairo_traps_t traps; cairo_traps_t traps;
if (gstate->stroke_style.line_width <= 0.0) { if (gstate->stroke_style.line_width <= 0.0) {
@ -1062,7 +1090,7 @@ _cairo_gstate_in_fill (cairo_gstate_t *gstate,
double y, double y,
cairo_bool_t *inside_ret) cairo_bool_t *inside_ret)
{ {
cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_status_t status;
cairo_traps_t traps; cairo_traps_t traps;
_cairo_gstate_user_to_backend (gstate, &x, &y); _cairo_gstate_user_to_backend (gstate, &x, &y);
@ -1269,11 +1297,9 @@ _cairo_gstate_select_font_face (cairo_gstate_t *gstate,
return font_face->status; return font_face->status;
status = _cairo_gstate_set_font_face (gstate, font_face); status = _cairo_gstate_set_font_face (gstate, font_face);
if (status)
return status;
cairo_font_face_destroy (font_face); cairo_font_face_destroy (font_face);
return CAIRO_STATUS_SUCCESS; return status;
} }
cairo_status_t cairo_status_t
@ -1291,6 +1317,9 @@ cairo_status_t
_cairo_gstate_set_font_matrix (cairo_gstate_t *gstate, _cairo_gstate_set_font_matrix (cairo_gstate_t *gstate,
const cairo_matrix_t *matrix) const cairo_matrix_t *matrix)
{ {
if (! _cairo_matrix_is_invertible (matrix))
return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
_cairo_gstate_unset_scaled_font (gstate); _cairo_gstate_unset_scaled_font (gstate);
gstate->font_matrix = *matrix; gstate->font_matrix = *matrix;
@ -1557,7 +1586,6 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
cairo_glyph_t *transformed_glyphs; cairo_glyph_t *transformed_glyphs;
cairo_glyph_t stack_transformed_glyphs[STACK_GLYPHS_LEN]; cairo_glyph_t stack_transformed_glyphs[STACK_GLYPHS_LEN];
if (gstate->source->status) if (gstate->source->status)
return gstate->source->status; return gstate->source->status;
@ -1574,7 +1602,7 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
} else { } else {
transformed_glyphs = _cairo_malloc_ab (num_glyphs, sizeof(cairo_glyph_t)); transformed_glyphs = _cairo_malloc_ab (num_glyphs, sizeof(cairo_glyph_t));
if (transformed_glyphs == NULL) if (transformed_glyphs == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
_cairo_gstate_transform_glyphs_to_backend (gstate, glyphs, num_glyphs, _cairo_gstate_transform_glyphs_to_backend (gstate, glyphs, num_glyphs,
@ -1619,14 +1647,16 @@ _cairo_gstate_glyph_path (cairo_gstate_t *gstate,
else else
transformed_glyphs = _cairo_malloc_ab (num_glyphs, sizeof(cairo_glyph_t)); transformed_glyphs = _cairo_malloc_ab (num_glyphs, sizeof(cairo_glyph_t));
if (transformed_glyphs == NULL) if (transformed_glyphs == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_cairo_gstate_transform_glyphs_to_backend (gstate, glyphs, num_glyphs, _cairo_gstate_transform_glyphs_to_backend (gstate, glyphs, num_glyphs,
transformed_glyphs); transformed_glyphs);
CAIRO_MUTEX_LOCK (gstate->scaled_font->mutex);
status = _cairo_scaled_font_glyph_path (gstate->scaled_font, status = _cairo_scaled_font_glyph_path (gstate->scaled_font,
transformed_glyphs, num_glyphs, transformed_glyphs, num_glyphs,
path); path);
CAIRO_MUTEX_UNLOCK (gstate->scaled_font->mutex);
if (transformed_glyphs != stack_transformed_glyphs) if (transformed_glyphs != stack_transformed_glyphs)
free (transformed_glyphs); free (transformed_glyphs);

View File

@ -39,6 +39,7 @@
#ifndef CAIRO_HASH_PRIVATE_H #ifndef CAIRO_HASH_PRIVATE_H
#define CAIRO_HASH_PRIVATE_H #define CAIRO_HASH_PRIVATE_H
#include "cairo-compiler-private.h"
#include "cairo-types-private.h" #include "cairo-types-private.h"
/* XXX: I'd like this file to be self-contained in terms of /* XXX: I'd like this file to be self-contained in terms of

View File

@ -149,8 +149,10 @@ _cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal)
cairo_hash_table_t *hash_table; cairo_hash_table_t *hash_table;
hash_table = malloc (sizeof (cairo_hash_table_t)); hash_table = malloc (sizeof (cairo_hash_table_t));
if (hash_table == NULL) if (hash_table == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
}
hash_table->keys_equal = keys_equal; hash_table->keys_equal = keys_equal;
@ -159,6 +161,7 @@ _cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal)
hash_table->entries = calloc (hash_table->arrangement->size, hash_table->entries = calloc (hash_table->arrangement->size,
sizeof(cairo_hash_entry_t *)); sizeof(cairo_hash_entry_t *));
if (hash_table->entries == NULL) { if (hash_table->entries == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
free (hash_table); free (hash_table);
return NULL; return NULL;
} }
@ -329,7 +332,7 @@ _cairo_hash_table_resize (cairo_hash_table_t *hash_table)
new_size = tmp.arrangement->size; new_size = tmp.arrangement->size;
tmp.entries = calloc (new_size, sizeof (cairo_hash_entry_t*)); tmp.entries = calloc (new_size, sizeof (cairo_hash_entry_t*));
if (tmp.entries == NULL) if (tmp.entries == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
for (i = 0; i < hash_table->arrangement->size; ++i) { for (i = 0; i < hash_table->arrangement->size; ++i) {
if (ENTRY_IS_LIVE (hash_table->entries[i])) { if (ENTRY_IS_LIVE (hash_table->entries[i])) {

View File

@ -63,8 +63,10 @@ _cairo_hull_create (cairo_pen_vertex_t *vertices, int num_vertices)
vertices[0].point = tmp; vertices[0].point = tmp;
hull = _cairo_malloc_ab (num_vertices, sizeof (cairo_hull_t)); hull = _cairo_malloc_ab (num_vertices, sizeof (cairo_hull_t));
if (hull == NULL) if (hull == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
}
for (i = 0; i < num_vertices; i++) { for (i = 0; i < num_vertices; i++) {
hull[i].point = vertices[i].point; hull[i].point = vertices[i].point;
@ -140,7 +142,7 @@ _cairo_hull_next_valid (cairo_hull_t *hull, int num_hull, int index)
return index; return index;
} }
static cairo_status_t static void
_cairo_hull_eliminate_concave (cairo_hull_t *hull, int num_hull) _cairo_hull_eliminate_concave (cairo_hull_t *hull, int num_hull)
{ {
int i, j, k; int i, j, k;
@ -157,7 +159,7 @@ _cairo_hull_eliminate_concave (cairo_hull_t *hull, int num_hull)
/* Is the angle formed by ij and jk concave? */ /* Is the angle formed by ij and jk concave? */
if (_cairo_slope_compare (&slope_ij, &slope_jk) >= 0) { if (_cairo_slope_compare (&slope_ij, &slope_jk) >= 0) {
if (i == k) if (i == k)
return CAIRO_STATUS_SUCCESS; return;
hull[j].discard = 1; hull[j].discard = 1;
j = i; j = i;
i = _cairo_hull_prev_valid (hull, num_hull, j); i = _cairo_hull_prev_valid (hull, num_hull, j);
@ -167,11 +169,9 @@ _cairo_hull_eliminate_concave (cairo_hull_t *hull, int num_hull)
k = _cairo_hull_next_valid (hull, num_hull, j); k = _cairo_hull_next_valid (hull, num_hull, j);
} }
} while (j != 0); } while (j != 0);
return CAIRO_STATUS_SUCCESS;
} }
static cairo_status_t static void
_cairo_hull_to_pen (cairo_hull_t *hull, cairo_pen_vertex_t *vertices, int *num_vertices) _cairo_hull_to_pen (cairo_hull_t *hull, cairo_pen_vertex_t *vertices, int *num_vertices)
{ {
int i, j = 0; int i, j = 0;
@ -183,8 +183,6 @@ _cairo_hull_to_pen (cairo_hull_t *hull, cairo_pen_vertex_t *vertices, int *num_v
} }
*num_vertices = j; *num_vertices = j;
return CAIRO_STATUS_SUCCESS;
} }
/* Given a set of vertices, compute the convex hull using the Graham /* Given a set of vertices, compute the convex hull using the Graham

View File

@ -42,7 +42,7 @@ static const cairo_image_surface_t _cairo_image_surface_nil_invalid_format = {
&cairo_image_surface_backend, /* backend */ &cairo_image_surface_backend, /* backend */
CAIRO_SURFACE_TYPE_IMAGE, CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR, CAIRO_CONTENT_COLOR,
CAIRO_REF_COUNT_INVALID, /* ref_count */ CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_INVALID_FORMAT, /* status */ CAIRO_STATUS_INVALID_FORMAT, /* status */
FALSE, /* finished */ FALSE, /* finished */
{ 0, /* size */ { 0, /* size */
@ -84,6 +84,53 @@ static const cairo_image_surface_t _cairo_image_surface_nil_invalid_format = {
0, /* depth */ 0, /* depth */
NULL /* pixman_image */ NULL /* pixman_image */
}; };
static const cairo_image_surface_t _cairo_image_surface_nil_invalid_content = {
{
&cairo_image_surface_backend, /* backend */
CAIRO_SURFACE_TYPE_IMAGE,
CAIRO_CONTENT_COLOR,
CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_INVALID_CONTENT, /* status */
FALSE, /* finished */
{ 0, /* size */
0, /* num_elements */
0, /* element_size */
NULL, /* elements */
}, /* user_data */
{ 1.0, 0.0,
0.0, 1.0,
0.0, 0.0
}, /* device_transform */
{ 1.0, 0.0,
0.0, 1.0,
0.0, 0.0
}, /* device_transform_inverse */
0.0, /* x_resolution */
0.0, /* y_resolution */
0.0, /* x_fallback_resolution */
0.0, /* y_fallback_resolution */
NULL, /* clip */
0, /* next_clip_serial */
0, /* current_clip_serial */
FALSE, /* is_snapshot */
FALSE, /* has_font_options */
{ CAIRO_ANTIALIAS_DEFAULT,
CAIRO_SUBPIXEL_ORDER_DEFAULT,
CAIRO_HINT_STYLE_DEFAULT,
CAIRO_HINT_METRICS_DEFAULT
} /* font_options */
}, /* base */
PIXMAN_a8r8g8b8, /* pixman_format */
CAIRO_FORMAT_ARGB32, /* format */
NULL, /* data */
FALSE, /* owns_data */
FALSE, /* has_clip */
0, /* width */
0, /* height */
0, /* stride */
0, /* depth */
NULL /* pixman_image */
};
static cairo_format_t static cairo_format_t
_cairo_format_from_pixman_format (pixman_format_code_t pixman_format) _cairo_format_from_pixman_format (pixman_format_code_t pixman_format)
@ -167,7 +214,7 @@ _cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image,
surface = malloc (sizeof (cairo_image_surface_t)); surface = malloc (sizeof (cairo_image_surface_t));
if (surface == NULL) { if (surface == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
} }
@ -386,7 +433,7 @@ _cairo_image_surface_create_with_pixman_format (unsigned char *data,
(uint32_t *) data, stride); (uint32_t *) data, stride);
if (pixman_image == NULL) { if (pixman_image == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
} }
@ -424,11 +471,10 @@ cairo_image_surface_create (cairo_format_t format,
int width, int width,
int height) int height)
{ {
cairo_surface_t *surface;
pixman_format_code_t pixman_format; pixman_format_code_t pixman_format;
if (! CAIRO_FORMAT_VALID (format)) { if (! CAIRO_FORMAT_VALID (format)) {
_cairo_error (CAIRO_STATUS_INVALID_FORMAT); _cairo_error_throw (CAIRO_STATUS_INVALID_FORMAT);
return (cairo_surface_t*) &_cairo_image_surface_nil_invalid_format; return (cairo_surface_t*) &_cairo_image_surface_nil_invalid_format;
} }
@ -436,8 +482,6 @@ cairo_image_surface_create (cairo_format_t format,
return _cairo_image_surface_create_with_pixman_format (NULL, pixman_format, return _cairo_image_surface_create_with_pixman_format (NULL, pixman_format,
width, height, -1); width, height, -1);
return surface;
} }
slim_hidden_def (cairo_image_surface_create); slim_hidden_def (cairo_image_surface_create);
@ -446,8 +490,10 @@ _cairo_image_surface_create_with_content (cairo_content_t content,
int width, int width,
int height) int height)
{ {
if (! CAIRO_CONTENT_VALID (content)) if (! CAIRO_CONTENT_VALID (content)) {
return (cairo_surface_t*) &_cairo_surface_nil; _cairo_error_throw (CAIRO_STATUS_INVALID_CONTENT);
return (cairo_surface_t*) &_cairo_image_surface_nil_invalid_content;
}
return cairo_image_surface_create (_cairo_format_from_content (content), return cairo_image_surface_create (_cairo_format_from_content (content),
width, height); width, height);
@ -492,8 +538,13 @@ cairo_image_surface_create_for_data (unsigned char *data,
{ {
pixman_format_code_t pixman_format; pixman_format_code_t pixman_format;
if (! CAIRO_FORMAT_VALID (format)) /* XXX pixman does not support images with arbitrary strides and
return (cairo_surface_t*) &_cairo_surface_nil; * attempting to create such surfaces will failure but we will interpret
* such failure as CAIRO_STATUS_NO_MEMORY. */
if (! CAIRO_FORMAT_VALID (format) || stride % sizeof (uint32_t) != 0) {
_cairo_error_throw (CAIRO_STATUS_INVALID_FORMAT);
return (cairo_surface_t*) &_cairo_image_surface_nil_invalid_format;
}
pixman_format = _cairo_format_to_pixman_format_code (format); pixman_format = _cairo_format_to_pixman_format_code (format);
@ -509,8 +560,10 @@ _cairo_image_surface_create_for_data_with_content (unsigned char *data,
int height, int height,
int stride) int stride)
{ {
if (! CAIRO_CONTENT_VALID (content)) if (! CAIRO_CONTENT_VALID (content)) {
return (cairo_surface_t*) &_cairo_surface_nil; _cairo_error_throw (CAIRO_STATUS_INVALID_CONTENT);
return (cairo_surface_t*) &_cairo_image_surface_nil_invalid_content;
}
return cairo_image_surface_create_for_data (data, return cairo_image_surface_create_for_data (data,
_cairo_format_from_content (content), _cairo_format_from_content (content),
@ -535,7 +588,7 @@ cairo_image_surface_get_data (cairo_surface_t *surface)
cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
if (!_cairo_surface_is_image (surface)) { if (!_cairo_surface_is_image (surface)) {
_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return NULL; return NULL;
} }
@ -558,7 +611,7 @@ cairo_image_surface_get_format (cairo_surface_t *surface)
cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
if (!_cairo_surface_is_image (surface)) { if (!_cairo_surface_is_image (surface)) {
_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return 0; return 0;
} }
@ -581,7 +634,7 @@ cairo_image_surface_get_width (cairo_surface_t *surface)
cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
if (!_cairo_surface_is_image (surface)) { if (!_cairo_surface_is_image (surface)) {
_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return 0; return 0;
} }
@ -603,7 +656,7 @@ cairo_image_surface_get_height (cairo_surface_t *surface)
cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
if (!_cairo_surface_is_image (surface)) { if (!_cairo_surface_is_image (surface)) {
_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return 0; return 0;
} }
@ -631,7 +684,7 @@ cairo_image_surface_get_stride (cairo_surface_t *surface)
cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface;
if (!_cairo_surface_is_image (surface)) { if (!_cairo_surface_is_image (surface)) {
_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return 0; return 0;
} }
@ -783,7 +836,7 @@ _cairo_image_surface_set_matrix (cairo_image_surface_t *surface,
_cairo_matrix_to_pixman_matrix (matrix, &pixman_transform); _cairo_matrix_to_pixman_matrix (matrix, &pixman_transform);
if (!pixman_image_set_transform (surface->pixman_image, &pixman_transform)) if (!pixman_image_set_transform (surface->pixman_image, &pixman_transform))
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -1007,7 +1060,7 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
if (num_rects > ARRAY_LENGTH(stack_rects)) { if (num_rects > ARRAY_LENGTH(stack_rects)) {
pixman_rects = _cairo_malloc_ab (num_rects, sizeof(pixman_rectangle16_t)); pixman_rects = _cairo_malloc_ab (num_rects, sizeof(pixman_rectangle16_t));
if (pixman_rects == NULL) if (pixman_rects == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
for (i = 0; i < num_rects; i++) { for (i = 0; i < num_rects; i++) {
@ -1022,8 +1075,9 @@ _cairo_image_surface_fill_rectangles (void *abstract_surface,
surface->pixman_image, surface->pixman_image,
&pixman_color, &pixman_color,
num_rects, num_rects,
pixman_rects)) pixman_rects)) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
if (pixman_rects != stack_rects) if (pixman_rects != stack_rects)
free (pixman_rects); free (pixman_rects);
@ -1069,7 +1123,7 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op,
if (num_traps > ARRAY_LENGTH(stack_traps)) { if (num_traps > ARRAY_LENGTH(stack_traps)) {
pixman_traps = _cairo_malloc_ab (num_traps, sizeof(pixman_trapezoid_t)); pixman_traps = _cairo_malloc_ab (num_traps, sizeof(pixman_trapezoid_t));
if (pixman_traps == NULL) if (pixman_traps == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
for (i = 0; i < num_traps; i++) { for (i = 0; i < num_traps; i++) {
@ -1142,16 +1196,16 @@ _cairo_image_surface_composite_trapezoids (cairo_operator_t op,
} }
/* The image must be initially transparent */ /* The image must be initially transparent */
mask_data = calloc (1, mask_stride * height); mask_data = calloc (mask_stride, height);
if (mask_data == NULL) { if (mask_data == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_SOURCE; goto CLEANUP_SOURCE;
} }
mask = pixman_image_create_bits (format, width, height, mask = pixman_image_create_bits (format, width, height,
mask_data, mask_stride); mask_data, mask_stride);
if (mask == NULL) { if (mask == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_IMAGE_DATA; goto CLEANUP_IMAGE_DATA;
} }
@ -1199,7 +1253,7 @@ _cairo_image_surface_set_clip_region (void *abstract_surface,
cairo_image_surface_t *surface = (cairo_image_surface_t *) abstract_surface; cairo_image_surface_t *surface = (cairo_image_surface_t *) abstract_surface;
if (!pixman_image_set_clip_region (surface->pixman_image, &region->rgn)) if (!pixman_image_set_clip_region (surface->pixman_image, &region->rgn))
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
surface->has_clip = region != NULL; surface->has_clip = region != NULL;
@ -1297,6 +1351,7 @@ _cairo_image_surface_clone (cairo_image_surface_t *surface,
cairo_format_t format) cairo_format_t format)
{ {
cairo_image_surface_t *clone; cairo_image_surface_t *clone;
cairo_status_t status;
cairo_t *cr; cairo_t *cr;
double x, y; double x, y;
@ -1312,7 +1367,13 @@ _cairo_image_surface_clone (cairo_image_surface_t *surface,
cairo_set_source_surface (cr, &surface->base, 0, 0); cairo_set_source_surface (cr, &surface->base, 0, 0);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (cr); cairo_paint (cr);
status = cairo_status (cr);
cairo_destroy (cr); cairo_destroy (cr);
if (status) {
cairo_surface_destroy (&clone->base);
return (cairo_image_surface_t *) &_cairo_surface_nil;
}
return clone; return clone;
} }

View File

@ -75,7 +75,7 @@ _lzw_buf_init (lzw_buf_t *buf, int size)
buf->data = malloc (size); buf->data = malloc (size);
if (buf->data == NULL) { if (buf->data == NULL) {
buf->data_size = 0; buf->data_size = 0;
buf->status = CAIRO_STATUS_NO_MEMORY; buf->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return; return;
} }
} }
@ -93,11 +93,15 @@ _lzw_buf_grow (lzw_buf_t *buf)
if (buf->status) if (buf->status)
return buf->status; return buf->status;
new_data = realloc (buf->data, new_size); new_data = NULL;
/* check for integer overflow */
if (new_size / 2 == buf->data_size)
new_data = realloc (buf->data, new_size);
if (new_data == NULL) { if (new_data == NULL) {
free (buf->data); free (buf->data);
buf->data_size = 0; buf->data_size = 0;
buf->status = CAIRO_STATUS_NO_MEMORY; buf->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return buf->status; return buf->status;
} }

View File

@ -59,7 +59,7 @@
* @n: number of elements to allocate * @n: number of elements to allocate
* @size: size of each element * @size: size of each element
* *
* Allocates @a*@size memory using _cairo_malloc(), taking care to not * Allocates @n*@size memory using _cairo_malloc(), taking care to not
* overflow when doing the multiplication. Behaves much like * overflow when doing the multiplication. Behaves much like
* calloc(), except that the returned memory is not set to zero. * calloc(), except that the returned memory is not set to zero.
* The memory should be freed using free(). * The memory should be freed using free().
@ -75,13 +75,35 @@
((size) && (unsigned) (a) >= INT32_MAX / (unsigned) (size) ? NULL : \ ((size) && (unsigned) (a) >= INT32_MAX / (unsigned) (size) ? NULL : \
_cairo_malloc((unsigned) (a) * (unsigned) (size))) _cairo_malloc((unsigned) (a) * (unsigned) (size)))
/**
* _cairo_realloc_ab:
* @ptr: original pointer to block of memory to be resized
* @n: number of elements to allocate
* @size: size of each element
*
* Reallocates @ptr a block of @n*@size memory using realloc(), taking
* care to not overflow when doing the multiplication. The memory
* should be freed using free().
*
* @size should be a constant so that the compiler can optimize
* out a constant division.
*
* Return value: A pointer to the newly allocated memory, or %NULL in
* case of realloc() failure or overflow (whereupon the original block
* of memory * is left untouched).
*/
#define _cairo_realloc_ab(ptr, a, size) \
((size) && (unsigned) (a) >= INT32_MAX / (unsigned) (size) ? NULL : \
realloc(ptr, (unsigned) (a) * (unsigned) (size)))
/** /**
* _cairo_malloc_abc: * _cairo_malloc_abc:
* @a: first factor of number of elements to allocate * @n: first factor of number of elements to allocate
* @b: second factor of number of elements to allocate * @b: second factor of number of elements to allocate
* @size: size of each element * @size: size of each element
* *
* Allocates @a*@b*@size memory using _cairo_malloc(), taking care to not * Allocates @n*@b*@size memory using _cairo_malloc(), taking care to not
* overflow when doing the multiplication. Behaves like * overflow when doing the multiplication. Behaves like
* _cairo_malloc_ab(). The memory should be freed using free(). * _cairo_malloc_ab(). The memory should be freed using free().
* *
@ -103,7 +125,7 @@
* @size: size of each element * @size: size of each element
* @k: additional size to allocate * @k: additional size to allocate
* *
* Allocates @a*@ksize+@k memory using _cairo_malloc(), taking care to not * Allocates @n*@ksize+@k memory using _cairo_malloc(), taking care to not
* overflow when doing the arithmetic. Behaves like * overflow when doing the arithmetic. Behaves like
* _cairo_malloc_ab(). The memory should be freed using free(). * _cairo_malloc_ab(). The memory should be freed using free().
* *

View File

@ -473,11 +473,11 @@ cairo_matrix_invert (cairo_matrix_t *matrix)
_cairo_matrix_compute_determinant (matrix, &det); _cairo_matrix_compute_determinant (matrix, &det);
if (det == 0) if (det == 0)
return CAIRO_STATUS_INVALID_MATRIX; return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
/* this weird construct is for detecting NaNs */ /* this weird construct is for detecting NaNs */
if (! (det * det > 0.)) if (! (det * det > 0.))
return CAIRO_STATUS_INVALID_MATRIX; return _cairo_error (CAIRO_STATUS_INVALID_MATRIX);
_cairo_matrix_compute_adjoint (matrix); _cairo_matrix_compute_adjoint (matrix);
_cairo_matrix_scalar_multiply (matrix, 1 / det); _cairo_matrix_scalar_multiply (matrix, 1 / det);
@ -486,6 +486,16 @@ cairo_matrix_invert (cairo_matrix_t *matrix)
} }
slim_hidden_def(cairo_matrix_invert); slim_hidden_def(cairo_matrix_invert);
cairo_bool_t
_cairo_matrix_is_invertible (const cairo_matrix_t *matrix)
{
double det;
_cairo_matrix_compute_determinant (matrix, &det);
return det != 0. && det * det > 0.;
}
void void
_cairo_matrix_compute_determinant (const cairo_matrix_t *matrix, _cairo_matrix_compute_determinant (const cairo_matrix_t *matrix,
double *det) double *det)

View File

@ -61,7 +61,7 @@ typedef enum {
typedef enum { typedef enum {
CAIRO_META_REGION_ALL, CAIRO_META_REGION_ALL,
CAIRO_META_REGION_NATIVE, CAIRO_META_REGION_NATIVE,
CAIRO_META_REGION_IMAGE_FALLBACK, CAIRO_META_REGION_IMAGE_FALLBACK
} cairo_meta_region_type_t; } cairo_meta_region_type_t;
typedef struct _cairo_command_header { typedef struct _cairo_command_header {

View File

@ -85,7 +85,7 @@ _cairo_meta_surface_create (cairo_content_t content,
meta = malloc (sizeof (cairo_meta_surface_t)); meta = malloc (sizeof (cairo_meta_surface_t));
if (meta == NULL) { if (meta == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
} }
@ -253,7 +253,7 @@ _cairo_meta_surface_paint (void *abstract_surface,
command = malloc (sizeof (cairo_command_paint_t)); command = malloc (sizeof (cairo_command_paint_t));
if (command == NULL) if (command == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
command->header.type = CAIRO_COMMAND_PAINT; command->header.type = CAIRO_COMMAND_PAINT;
command->header.region = CAIRO_META_REGION_ALL; command->header.region = CAIRO_META_REGION_ALL;
@ -294,7 +294,7 @@ _cairo_meta_surface_mask (void *abstract_surface,
command = malloc (sizeof (cairo_command_mask_t)); command = malloc (sizeof (cairo_command_mask_t));
if (command == NULL) if (command == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
command->header.type = CAIRO_COMMAND_MASK; command->header.type = CAIRO_COMMAND_MASK;
command->header.region = CAIRO_META_REGION_ALL; command->header.region = CAIRO_META_REGION_ALL;
@ -340,7 +340,7 @@ _cairo_meta_surface_stroke (void *abstract_surface,
command = malloc (sizeof (cairo_command_stroke_t)); command = malloc (sizeof (cairo_command_stroke_t));
if (command == NULL) if (command == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
command->header.type = CAIRO_COMMAND_STROKE; command->header.type = CAIRO_COMMAND_STROKE;
command->header.region = CAIRO_META_REGION_ALL; command->header.region = CAIRO_META_REGION_ALL;
@ -395,7 +395,7 @@ _cairo_meta_surface_fill (void *abstract_surface,
command = malloc (sizeof (cairo_command_fill_t)); command = malloc (sizeof (cairo_command_fill_t));
if (command == NULL) if (command == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
command->header.type = CAIRO_COMMAND_FILL; command->header.type = CAIRO_COMMAND_FILL;
command->header.region = CAIRO_META_REGION_ALL; command->header.region = CAIRO_META_REGION_ALL;
@ -442,7 +442,7 @@ _cairo_meta_surface_show_glyphs (void *abstract_surface,
command = malloc (sizeof (cairo_command_show_glyphs_t)); command = malloc (sizeof (cairo_command_show_glyphs_t));
if (command == NULL) if (command == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
command->header.type = CAIRO_COMMAND_SHOW_GLYPHS; command->header.type = CAIRO_COMMAND_SHOW_GLYPHS;
command->header.region = CAIRO_META_REGION_ALL; command->header.region = CAIRO_META_REGION_ALL;
@ -454,7 +454,7 @@ _cairo_meta_surface_show_glyphs (void *abstract_surface,
command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
if (command->glyphs == NULL) { if (command->glyphs == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_SOURCE; goto CLEANUP_SOURCE;
} }
memcpy (command->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs); memcpy (command->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
@ -476,7 +476,7 @@ _cairo_meta_surface_show_glyphs (void *abstract_surface,
_cairo_pattern_fini (&command->source.base); _cairo_pattern_fini (&command->source.base);
CLEANUP_COMMAND: CLEANUP_COMMAND:
free (command); free (command);
return status; return _cairo_error (status);
} }
/** /**
@ -500,7 +500,7 @@ _cairo_meta_surface_snapshot (void *abstract_other)
meta = malloc (sizeof (cairo_meta_surface_t)); meta = malloc (sizeof (cairo_meta_surface_t));
if (meta == NULL) { if (meta == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
} }
@ -532,7 +532,7 @@ _cairo_meta_surface_intersect_clip_path (void *dst,
command = malloc (sizeof (cairo_command_intersect_clip_path_t)); command = malloc (sizeof (cairo_command_intersect_clip_path_t));
if (command == NULL) if (command == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
command->header.type = CAIRO_COMMAND_INTERSECT_CLIP_PATH; command->header.type = CAIRO_COMMAND_INTERSECT_CLIP_PATH;
command->header.region = CAIRO_META_REGION_ALL; command->header.region = CAIRO_META_REGION_ALL;
@ -667,10 +667,14 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
cairo_bool_t has_device_transform = _cairo_surface_has_device_transform (target); cairo_bool_t has_device_transform = _cairo_surface_has_device_transform (target);
cairo_matrix_t *device_transform = &target->device_transform; cairo_matrix_t *device_transform = &target->device_transform;
cairo_path_fixed_t path_copy, *dev_path; cairo_path_fixed_t path_copy, *dev_path;
double tolerance_multiplier = _cairo_matrix_transformed_circle_major_axis (device_transform, 1.0);
if (surface->status) if (surface->status)
return surface->status; return surface->status;
if (target->status)
return _cairo_surface_set_error (surface, target->status);
meta = (cairo_meta_surface_t *) surface; meta = (cairo_meta_surface_t *) surface;
status = CAIRO_STATUS_SUCCESS; status = CAIRO_STATUS_SUCCESS;
@ -736,7 +740,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
&command->stroke.style, &command->stroke.style,
&dev_ctm, &dev_ctm,
&dev_ctm_inverse, &dev_ctm_inverse,
command->stroke.tolerance, command->stroke.tolerance * tolerance_multiplier,
command->stroke.antialias); command->stroke.antialias);
break; break;
} }
@ -768,7 +772,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
command->fill.op, command->fill.op,
&command->fill.source.base, &command->fill.source.base,
command->fill.fill_rule, command->fill.fill_rule,
command->fill.tolerance, command->fill.tolerance * tolerance_multiplier,
command->fill.antialias, command->fill.antialias,
dev_path, dev_path,
stroke_command->stroke.op, stroke_command->stroke.op,
@ -776,7 +780,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
&stroke_command->stroke.style, &stroke_command->stroke.style,
&dev_ctm, &dev_ctm,
&dev_ctm_inverse, &dev_ctm_inverse,
stroke_command->stroke.tolerance, stroke_command->stroke.tolerance * tolerance_multiplier,
stroke_command->stroke.antialias); stroke_command->stroke.antialias);
i++; i++;
} else } else
@ -785,7 +789,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
&command->fill.source.base, &command->fill.source.base,
dev_path, dev_path,
command->fill.fill_rule, command->fill.fill_rule,
command->fill.tolerance, command->fill.tolerance * tolerance_multiplier,
command->fill.antialias); command->fill.antialias);
break; break;
} }
@ -798,7 +802,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
if (has_device_transform) { if (has_device_transform) {
dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
if (dev_glyphs == NULL) { if (dev_glyphs == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
break; break;
} }
for (i = 0; i < num_glyphs; i++) { for (i = 0; i < num_glyphs; i++) {
@ -828,7 +832,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
else else
status = _cairo_clip_clip (&clip, dev_path, status = _cairo_clip_clip (&clip, dev_path,
command->intersect_clip_path.fill_rule, command->intersect_clip_path.fill_rule,
command->intersect_clip_path.tolerance, command->intersect_clip_path.tolerance * tolerance_multiplier,
command->intersect_clip_path.antialias, command->intersect_clip_path.antialias,
target); target);
assert (status == 0); assert (status == 0);
@ -860,7 +864,7 @@ _cairo_meta_surface_replay_internal (cairo_surface_t *surface,
_cairo_clip_reset (&clip); _cairo_clip_reset (&clip);
return status; return _cairo_surface_set_error (surface, status);
} }
cairo_status_t cairo_status_t

View File

@ -46,6 +46,9 @@ CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex);
CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex); CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex);
#endif #endif
#if !defined (CAIRO_HAS_ATOMIC_OPS) || defined (CAIRO_ATOMIC_OP_NEEDS_MEMORY_BARRIER)
CAIRO_MUTEX_DECLARE (_cairo_atomic_mutex);
#endif
/* Undefine, to err on unintended inclusion */ /* Undefine, to err on unintended inclusion */
#undef CAIRO_MUTEX_DECLARE #undef CAIRO_MUTEX_DECLARE

View File

@ -47,6 +47,7 @@
#include <cairo-features.h> #include <cairo-features.h>
#include "cairo-compiler-private.h"
#include "cairo-mutex-type-private.h" #include "cairo-mutex-type-private.h"
/* Only the following three are mandatory at this point */ /* Only the following three are mandatory at this point */

View File

@ -473,7 +473,7 @@ _cairo_os2_surface_acquire_source_image (void *abstract_surfac
(local_os2_surface->base.backend != &cairo_os2_surface_backend)) (local_os2_surface->base.backend != &cairo_os2_surface_backend))
{ {
/* Invalid parameter (wrong surface)! */ /* Invalid parameter (wrong surface)! */
return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
} }
DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT); DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT);
@ -529,7 +529,7 @@ _cairo_os2_surface_acquire_dest_image (void *abstract_surfac
(local_os2_surface->base.backend != &cairo_os2_surface_backend)) (local_os2_surface->base.backend != &cairo_os2_surface_backend))
{ {
/* Invalid parameter (wrong surface)! */ /* Invalid parameter (wrong surface)! */
return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
} }
DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT); DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT);
@ -637,7 +637,7 @@ _cairo_os2_surface_get_extents (void *abstract_surface,
(local_os2_surface->base.backend != &cairo_os2_surface_backend)) (local_os2_surface->base.backend != &cairo_os2_surface_backend))
{ {
/* Invalid parameter (wrong surface)! */ /* Invalid parameter (wrong surface)! */
return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
} }
rectangle->x = 0; rectangle->x = 0;
@ -773,14 +773,14 @@ cairo_os2_surface_set_size (cairo_surface_t *surface,
(local_os2_surface->base.backend != &cairo_os2_surface_backend)) (local_os2_surface->base.backend != &cairo_os2_surface_backend))
{ {
/* Invalid parameter (wrong surface)! */ /* Invalid parameter (wrong surface)! */
return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
} }
if ((new_width <= 0) || if ((new_width <= 0) ||
(new_height <= 0)) (new_height <= 0))
{ {
/* Invalid size! */ /* Invalid size! */
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
/* Allocate memory for new stuffs */ /* Allocate memory for new stuffs */
@ -789,7 +789,7 @@ cairo_os2_surface_set_size (cairo_surface_t *surface,
/* Not enough memory for the pixels! /* Not enough memory for the pixels!
* Everything remains the same! * Everything remains the same!
*/ */
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
/* This is possibly not needed, malloc'd space is usually /* This is possibly not needed, malloc'd space is usually
@ -812,7 +812,7 @@ cairo_os2_surface_set_size (cairo_surface_t *surface,
* Everything remains the same! * Everything remains the same!
*/ */
free (pchNewPixels); free (pchNewPixels);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
/* Okay, new memory allocated, so it's time to swap old buffers /* Okay, new memory allocated, so it's time to swap old buffers
@ -824,7 +824,7 @@ cairo_os2_surface_set_size (cairo_surface_t *surface,
*/ */
cairo_surface_destroy ((cairo_surface_t *) pNewImageSurface); cairo_surface_destroy ((cairo_surface_t *) pNewImageSurface);
free (pchNewPixels); free (pchNewPixels);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
/* We have to make sure that we won't destroy a surface which /* We have to make sure that we won't destroy a surface which
@ -840,7 +840,7 @@ cairo_os2_surface_set_size (cairo_surface_t *surface,
/* Either timeout or something wrong... Exit. */ /* Either timeout or something wrong... Exit. */
cairo_surface_destroy ((cairo_surface_t *) pNewImageSurface); cairo_surface_destroy ((cairo_surface_t *) pNewImageSurface);
free (pchNewPixels); free (pchNewPixels);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
/* Okay, grab mutex and check counter again! */ /* Okay, grab mutex and check counter again! */
if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT) if (DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT)
@ -851,7 +851,7 @@ cairo_os2_surface_set_size (cairo_surface_t *surface,
*/ */
cairo_surface_destroy ((cairo_surface_t *) pNewImageSurface); cairo_surface_destroy ((cairo_surface_t *) pNewImageSurface);
free (pchNewPixels); free (pchNewPixels);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
} }
@ -949,7 +949,7 @@ _cairo_os2_surface_finish (void *abstract_surface)
(local_os2_surface->base.backend != &cairo_os2_surface_backend)) (local_os2_surface->base.backend != &cairo_os2_surface_backend))
{ {
/* Invalid parameter (wrong surface)! */ /* Invalid parameter (wrong surface)! */
return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
} }
DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT); DosRequestMutexSem (local_os2_surface->hmtx_use_private_fields, SEM_INDEFINITE_WAIT);
@ -1042,7 +1042,7 @@ _cairo_os2_surface_mark_dirty_rectangle (void *surface,
(local_os2_surface->base.backend != &cairo_os2_surface_backend)) (local_os2_surface->base.backend != &cairo_os2_surface_backend))
{ {
/* Invalid parameter (wrong surface)! */ /* Invalid parameter (wrong surface)! */
return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
} }
/* Get mutex, we'll work with the pixel array! */ /* Get mutex, we'll work with the pixel array! */

View File

@ -37,6 +37,7 @@
#ifndef CAIRO_OUTPUT_STREAM_PRIVATE_H #ifndef CAIRO_OUTPUT_STREAM_PRIVATE_H
#define CAIRO_OUTPUT_STREAM_PRIVATE_H #define CAIRO_OUTPUT_STREAM_PRIVATE_H
#include "cairo-compiler-private.h"
#include "cairo-types-private.h" #include "cairo-types-private.h"
typedef cairo_status_t (*cairo_output_stream_write_func_t) (cairo_output_stream_t *output_stream, typedef cairo_status_t (*cairo_output_stream_write_func_t) (cairo_output_stream_t *output_stream,

View File

@ -46,7 +46,7 @@
#endif /* _MSC_VER */ #endif /* _MSC_VER */
cairo_private void void
_cairo_output_stream_init (cairo_output_stream_t *stream, _cairo_output_stream_init (cairo_output_stream_t *stream,
cairo_output_stream_write_func_t write_func, cairo_output_stream_write_func_t write_func,
cairo_output_stream_close_func_t close_func) cairo_output_stream_close_func_t close_func)
@ -58,7 +58,7 @@ _cairo_output_stream_init (cairo_output_stream_t *stream,
stream->closed = FALSE; stream->closed = FALSE;
} }
cairo_private cairo_status_t cairo_status_t
_cairo_output_stream_fini (cairo_output_stream_t *stream) _cairo_output_stream_fini (cairo_output_stream_t *stream)
{ {
return _cairo_output_stream_close (stream); return _cairo_output_stream_close (stream);
@ -119,8 +119,10 @@ _cairo_output_stream_create (cairo_write_func_t write_func,
cairo_output_stream_with_closure_t *stream; cairo_output_stream_with_closure_t *stream;
stream = malloc (sizeof (cairo_output_stream_with_closure_t)); stream = malloc (sizeof (cairo_output_stream_with_closure_t));
if (stream == NULL) if (stream == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil; return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base, closure_write, closure_close); _cairo_output_stream_init (&stream->base, closure_write, closure_close);
stream->write_func = write_func; stream->write_func = write_func;
@ -162,7 +164,13 @@ _cairo_output_stream_destroy (cairo_output_stream_t *stream)
cairo_status_t status; cairo_status_t status;
if (stream == NULL) if (stream == NULL)
return CAIRO_STATUS_NULL_POINTER; return _cairo_error (CAIRO_STATUS_NULL_POINTER);
if (stream == &_cairo_output_stream_nil ||
stream == &_cairo_output_stream_nil_write_error)
{
return stream->status;
}
status = _cairo_output_stream_fini (stream); status = _cairo_output_stream_fini (stream);
free (stream); free (stream);
@ -207,6 +215,8 @@ _cairo_output_stream_write_hex_string (cairo_output_stream_t *stream,
} }
} }
#define SIGNIFICANT_DIGITS_AFTER_DECIMAL 6
/* Format a double in a locale independent way and trim trailing /* Format a double in a locale independent way and trim trailing
* zeros. Based on code from Alex Larson <alexl@redhat.com>. * zeros. Based on code from Alex Larson <alexl@redhat.com>.
* http://mail.gnome.org/archives/gtk-devel-list/2001-October/msg00087.html * http://mail.gnome.org/archives/gtk-devel-list/2001-October/msg00087.html
@ -223,18 +233,53 @@ _cairo_dtostr (char *buffer, size_t size, double d)
int decimal_point_len; int decimal_point_len;
char *p; char *p;
int decimal_len; int decimal_len;
int num_zeros, decimal_digits;
/* Omit the minus sign from negative zero. */ /* Omit the minus sign from negative zero. */
if (d == 0.0) if (d == 0.0)
d = 0.0; d = 0.0;
snprintf (buffer, size, "%f", d);
locale_data = localeconv (); locale_data = localeconv ();
decimal_point = locale_data->decimal_point; decimal_point = locale_data->decimal_point;
decimal_point_len = strlen (decimal_point); decimal_point_len = strlen (decimal_point);
assert (decimal_point_len != 0); assert (decimal_point_len != 0);
/* Using "%f" to print numbers less than 0.1 will result in
* reduced precision due to the default 6 digits after the
* decimal point.
*
* For numbers is < 0.1, we print with maximum precision and count
* the number of zeros between the decimal point and the first
* significant digit. We then print the number again with the
* number of decimal places that gives us the required number of
* significant digits. This ensures the number is correctly
* rounded.
*/
if (fabs (d) >= 0.1) {
snprintf (buffer, size, "%f", d);
} else {
snprintf (buffer, size, "%.18f", d);
p = buffer;
if (*p == '+' || *p == '-')
p++;
while (isdigit (*p))
p++;
if (strncmp (p, decimal_point, decimal_point_len) == 0)
p += decimal_point_len;
num_zeros = 0;
while (*p++ == '0')
num_zeros++;
decimal_digits = num_zeros + SIGNIFICANT_DIGITS_AFTER_DECIMAL;
if (decimal_digits < 18)
snprintf (buffer, size, "%.*f", decimal_digits, d);
}
p = buffer; p = buffer;
if (*p == '+' || *p == '-') if (*p == '+' || *p == '-')
@ -432,7 +477,7 @@ stdio_write (cairo_output_stream_t *base,
stdio_stream_t *stream = (stdio_stream_t *) base; stdio_stream_t *stream = (stdio_stream_t *) base;
if (fwrite (data, 1, length, stream->file) != length) if (fwrite (data, 1, length, stream->file) != length)
return CAIRO_STATUS_WRITE_ERROR; return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -445,7 +490,7 @@ stdio_flush (cairo_output_stream_t *base)
fflush (stream->file); fflush (stream->file);
if (ferror (stream->file)) if (ferror (stream->file))
return CAIRO_STATUS_WRITE_ERROR; return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
else else
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -468,12 +513,16 @@ _cairo_output_stream_create_for_file (FILE *file)
{ {
stdio_stream_t *stream; stdio_stream_t *stream;
if (file == NULL) if (file == NULL) {
_cairo_error_throw (CAIRO_STATUS_WRITE_ERROR);
return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error; return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
}
stream = malloc (sizeof *stream); stream = malloc (sizeof *stream);
if (stream == NULL) if (stream == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil; return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base, stdio_write, stdio_flush); _cairo_output_stream_init (&stream->base, stdio_write, stdio_flush);
stream->file = file; stream->file = file;
@ -488,12 +537,15 @@ _cairo_output_stream_create_for_filename (const char *filename)
FILE *file; FILE *file;
file = fopen (filename, "wb"); file = fopen (filename, "wb");
if (file == NULL) if (file == NULL) {
_cairo_error_throw (CAIRO_STATUS_WRITE_ERROR);
return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error; return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error;
}
stream = malloc (sizeof *stream); stream = malloc (sizeof *stream);
if (stream == NULL) { if (stream == NULL) {
fclose (file); fclose (file);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil; return (cairo_output_stream_t *) &_cairo_output_stream_nil;
} }
@ -534,8 +586,10 @@ _cairo_memory_stream_create (void)
memory_stream_t *stream; memory_stream_t *stream;
stream = malloc (sizeof *stream); stream = malloc (sizeof *stream);
if (stream == NULL) if (stream == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_output_stream_t *) &_cairo_output_stream_nil; return (cairo_output_stream_t *) &_cairo_output_stream_nil;
}
_cairo_output_stream_init (&stream->base, memory_write, memory_close); _cairo_output_stream_init (&stream->base, memory_write, memory_close);
_cairo_array_init (&stream->array, 1); _cairo_array_init (&stream->array, 1);
@ -549,6 +603,14 @@ _cairo_memory_stream_copy (cairo_output_stream_t *base,
{ {
memory_stream_t *stream = (memory_stream_t *) base; memory_stream_t *stream = (memory_stream_t *) base;
if (dest->status)
return;
if (base->status) {
dest->status = base->status;
return;
}
_cairo_output_stream_write (dest, _cairo_output_stream_write (dest,
_cairo_array_index (&stream->array, 0), _cairo_array_index (&stream->array, 0),
_cairo_array_num_elements (&stream->array)); _cairo_array_num_elements (&stream->array));

View File

@ -59,6 +59,14 @@ struct _cairo_paginated_surface_backend {
void void
(*set_paginated_mode) (void *surface, (*set_paginated_mode) (void *surface,
cairo_paginated_mode_t mode); cairo_paginated_mode_t mode);
/* Optional. Specifies the smallest box that encloses all objects
* on the page. Will be called at the end of the ANALYZE phase but
* before the mode is changed to RENDER.
*/
cairo_warn cairo_int_status_t
(*set_bounding_box) (void *surface,
cairo_box_t *bbox);
}; };
/* A cairo_paginated_surface provides a very convenient wrapper that /* A cairo_paginated_surface provides a very convenient wrapper that
@ -95,11 +103,14 @@ struct _cairo_paginated_surface_backend {
* from each operation). This analysis stage is used to decide which * from each operation). This analysis stage is used to decide which
* operations will require fallbacks. * operations will require fallbacks.
* *
* 4. Calls set_paginated_mode with an argument of CAIRO_PAGINATED_MODE_RENDER * 4. Calls set_bounding_box to provide the target surface with the
* tight bounding box of the page.
* *
* 5. Replays a subset of the meta-surface operations to the target surface * 5. Calls set_paginated_mode with an argument of CAIRO_PAGINATED_MODE_RENDER
* *
* 6. Replays the remaining operations to an image surface, sets an * 6. Replays a subset of the meta-surface operations to the target surface
*
* 7. Replays the remaining operations to an image surface, sets an
* appropriate clip on the target, then paints the resulting image * appropriate clip on the target, then paints the resulting image
* surface to the target. * surface to the target.
* *
@ -114,7 +125,7 @@ struct _cairo_paginated_surface_backend {
* *
* NOTE: The paginated surface layer assumes that the target surface * NOTE: The paginated surface layer assumes that the target surface
* is "blank" by default at the beginning of each page, without any * is "blank" by default at the beginning of each page, without any
* need for an explicit erasea operation, (as opposed to an image * need for an explicit erase operation, (as opposed to an image
* surface, for example, which might have uninitialized content * surface, for example, which might have uninitialized content
* originally). As such, it optimizes away CLEAR operations that * originally). As such, it optimizes away CLEAR operations that
* happen at the beginning of each page---the target surface will not * happen at the beginning of each page---the target surface will not

View File

@ -49,7 +49,7 @@
#include "cairo-meta-surface-private.h" #include "cairo-meta-surface-private.h"
#include "cairo-analysis-surface-private.h" #include "cairo-analysis-surface-private.h"
const cairo_private cairo_surface_backend_t cairo_paginated_surface_backend; static const cairo_private cairo_surface_backend_t cairo_paginated_surface_backend;
static cairo_int_status_t static cairo_int_status_t
_cairo_paginated_surface_show_page (void *abstract_surface); _cairo_paginated_surface_show_page (void *abstract_surface);
@ -76,8 +76,10 @@ _cairo_paginated_surface_create (cairo_surface_t *target,
cairo_paginated_surface_t *surface; cairo_paginated_surface_t *surface;
surface = malloc (sizeof (cairo_paginated_surface_t)); surface = malloc (sizeof (cairo_paginated_surface_t));
if (surface == NULL) if (surface == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
goto FAIL; goto FAIL;
}
_cairo_surface_init (&surface->base, &cairo_paginated_surface_backend, _cairo_surface_init (&surface->base, &cairo_paginated_surface_backend,
content); content);
@ -106,7 +108,6 @@ _cairo_paginated_surface_create (cairo_surface_t *target,
FAIL_CLEANUP_SURFACE: FAIL_CLEANUP_SURFACE:
free (surface); free (surface);
FAIL: FAIL:
_cairo_error (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
} }
@ -129,11 +130,12 @@ _cairo_paginated_surface_get_target (cairo_surface_t *surface)
} }
cairo_status_t cairo_status_t
_cairo_paginated_surface_set_size (cairo_surface_t *surface, _cairo_paginated_surface_set_size (cairo_surface_t *surface,
int width, int width,
int height) int height)
{ {
cairo_paginated_surface_t *paginated_surface; cairo_paginated_surface_t *paginated_surface;
cairo_status_t status;
assert (_cairo_surface_is_paginated (surface)); assert (_cairo_surface_is_paginated (surface));
@ -145,8 +147,9 @@ _cairo_paginated_surface_set_size (cairo_surface_t *surface,
cairo_surface_destroy (paginated_surface->meta); cairo_surface_destroy (paginated_surface->meta);
paginated_surface->meta = _cairo_meta_surface_create (paginated_surface->content, paginated_surface->meta = _cairo_meta_surface_create (paginated_surface->content,
width, height); width, height);
if (cairo_surface_status (paginated_surface->meta)) status = cairo_surface_status (paginated_surface->meta);
return cairo_surface_status (paginated_surface->meta); if (status)
return status;
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -284,22 +287,33 @@ _paint_page (cairo_paginated_surface_t *surface)
cairo_status_t status; cairo_status_t status;
cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback; cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback;
if (surface->target->status)
return surface->target->status;
analysis = _cairo_analysis_surface_create (surface->target, analysis = _cairo_analysis_surface_create (surface->target,
surface->width, surface->height); surface->width, surface->height);
if (analysis == NULL) if (analysis == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_ANALYZE); surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_ANALYZE);
status = _cairo_meta_surface_replay_and_create_regions (surface->meta, analysis); status = _cairo_meta_surface_replay_and_create_regions (surface->meta, analysis);
surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_RENDER);
if (status || analysis->status) { if (status || analysis->status) {
if (status == CAIRO_STATUS_SUCCESS) if (status == CAIRO_STATUS_SUCCESS)
status = analysis->status; status = analysis->status;
cairo_surface_destroy (analysis); goto FAIL;
return status;
} }
if (surface->backend->set_bounding_box) {
cairo_box_t bbox;
_cairo_analysis_surface_get_bounding_box (analysis, &bbox);
status = surface->backend->set_bounding_box (surface->target, &bbox);
if (status)
goto FAIL;
}
surface->backend->set_paginated_mode (surface->target, CAIRO_PAGINATED_MODE_RENDER);
/* Finer grained fallbacks are currently only supported for some /* Finer grained fallbacks are currently only supported for some
* surface types */ * surface types */
switch (surface->target->type) { switch (surface->target->type) {
@ -328,7 +342,7 @@ _paint_page (cairo_paginated_surface_t *surface)
surface->target, surface->target,
CAIRO_META_REGION_NATIVE); CAIRO_META_REGION_NATIVE);
if (status) if (status)
return status; goto FAIL;
} }
if (has_page_fallback) if (has_page_fallback)
@ -341,7 +355,7 @@ _paint_page (cairo_paginated_surface_t *surface)
box.p2.y = surface->height; box.p2.y = surface->height;
status = _paint_fallback_image (surface, &box); status = _paint_fallback_image (surface, &box);
if (status) if (status)
return status; goto FAIL;
} }
if (has_finegrained_fallback) if (has_finegrained_fallback)
@ -357,34 +371,39 @@ _paint_page (cairo_paginated_surface_t *surface)
CAIRO_GSTATE_TOLERANCE_DEFAULT, CAIRO_GSTATE_TOLERANCE_DEFAULT,
CAIRO_ANTIALIAS_DEFAULT); CAIRO_ANTIALIAS_DEFAULT);
if (status) if (status)
return status; goto FAIL;
region = _cairo_analysis_surface_get_unsupported (analysis); region = _cairo_analysis_surface_get_unsupported (analysis);
status = _cairo_region_get_boxes (region, &num_boxes, &boxes); status = _cairo_region_get_boxes (region, &num_boxes, &boxes);
if (status) if (status)
return status; goto FAIL;
for (i = 0; i < num_boxes; i++) { for (i = 0; i < num_boxes; i++) {
status = _paint_fallback_image (surface, &boxes[i]); status = _paint_fallback_image (surface, &boxes[i]);
if (status) { if (status) {
_cairo_region_boxes_fini (region, boxes); _cairo_region_boxes_fini (region, boxes);
return status; goto FAIL;
} }
} }
_cairo_region_boxes_fini (region, boxes); _cairo_region_boxes_fini (region, boxes);
} }
FAIL:
cairo_surface_destroy (analysis); cairo_surface_destroy (analysis);
return status; return _cairo_surface_set_error (surface->target, status);
} }
static cairo_status_t static cairo_status_t
_start_page (cairo_paginated_surface_t *surface) _start_page (cairo_paginated_surface_t *surface)
{ {
if (surface->target->status)
return surface->target->status;
if (! surface->backend->start_page) if (! surface->backend->start_page)
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
return (surface->backend->start_page) (surface->target); return _cairo_surface_set_error (surface->target,
surface->backend->start_page (surface->target));
} }
static cairo_int_status_t static cairo_int_status_t
@ -431,15 +450,18 @@ _cairo_paginated_surface_show_page (void *abstract_surface)
if (status) if (status)
return status; return status;
if (cairo_surface_status (surface->meta)) status = cairo_surface_status (surface->meta);
return cairo_surface_status (surface->meta); if (status)
return status;
cairo_surface_destroy (surface->meta); cairo_surface_destroy (surface->meta);
surface->meta = _cairo_meta_surface_create (surface->content, surface->meta = _cairo_meta_surface_create (surface->content,
surface->width, surface->height); surface->width,
if (cairo_surface_status (surface->meta)) surface->height);
return cairo_surface_status (surface->meta); status = cairo_surface_status (surface->meta);
if (status)
return status;
surface->page_num++; surface->page_num++;
surface->page_is_blank = TRUE; surface->page_is_blank = TRUE;
@ -631,7 +653,7 @@ _cairo_paginated_surface_snapshot (void *abstract_other)
#endif #endif
} }
const cairo_surface_backend_t cairo_paginated_surface_backend = { static const cairo_surface_backend_t cairo_paginated_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED, CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED,
_cairo_paginated_surface_create_similar, _cairo_paginated_surface_create_similar,
_cairo_paginated_surface_finish, _cairo_paginated_surface_finish,

View File

@ -214,7 +214,7 @@ static cairo_int_status_t
_cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path, _cairo_path_fixed_fill_rectangle (cairo_path_fixed_t *path,
cairo_traps_t *traps) cairo_traps_t *traps)
{ {
cairo_path_buf_t *buf = path->buf_head; cairo_path_buf_t *buf = &path->buf_head.base;
int final; int final;
/* Ensure the path has the operators we expect for a rectangular path. /* Ensure the path has the operators we expect for a rectangular path.

View File

@ -46,18 +46,24 @@ enum cairo_path_op {
typedef char cairo_path_op_t; typedef char cairo_path_op_t;
/* make cairo_path_fixed fit a 512 bytes. about 50 items */ /* make cairo_path_fixed fit a 512 bytes. about 50 items */
#define CAIRO_PATH_BUF_SIZE ((512 - 12 * sizeof (void*)) \ #define CAIRO_PATH_BUF_SIZE ((512 - 4 * sizeof (void*) - sizeof (cairo_path_buf_t)) \
/ (sizeof (cairo_point_t) + sizeof (cairo_path_op_t))) / (2 * sizeof (cairo_point_t) + sizeof (cairo_path_op_t)))
typedef struct _cairo_path_buf { typedef struct _cairo_path_buf {
struct _cairo_path_buf *next, *prev; struct _cairo_path_buf *next, *prev;
int buf_size;
int num_ops; int num_ops;
int num_points; int num_points;
cairo_path_op_t op[CAIRO_PATH_BUF_SIZE]; cairo_path_op_t *op;
cairo_point_t points[CAIRO_PATH_BUF_SIZE]; cairo_point_t *points;
} cairo_path_buf_t; } cairo_path_buf_t;
typedef struct _cairo_path_buf_fixed {
cairo_path_buf_t base;
cairo_path_op_t op[CAIRO_PATH_BUF_SIZE];
cairo_point_t points[2 * CAIRO_PATH_BUF_SIZE];
} cairo_path_buf_fixed_t;
struct _cairo_path_fixed { struct _cairo_path_fixed {
cairo_point_t last_move_point; cairo_point_t last_move_point;
@ -65,8 +71,8 @@ struct _cairo_path_fixed {
unsigned int has_current_point : 1; unsigned int has_current_point : 1;
unsigned int has_curve_to : 1; unsigned int has_curve_to : 1;
cairo_path_buf_t *buf_tail; cairo_path_buf_t *buf_tail;
cairo_path_buf_t buf_head[1]; cairo_path_buf_fixed_t buf_head;
}; };
#endif /* CAIRO_PATH_FIXED_PRIVATE_H */ #endif /* CAIRO_PATH_FIXED_PRIVATE_H */

View File

@ -52,7 +52,7 @@ _cairo_path_fixed_add_buf (cairo_path_fixed_t *path,
cairo_path_buf_t *buf); cairo_path_buf_t *buf);
static cairo_path_buf_t * static cairo_path_buf_t *
_cairo_path_buf_create (void); _cairo_path_buf_create (int buf_size);
static void static void
_cairo_path_buf_destroy (cairo_path_buf_t *buf); _cairo_path_buf_destroy (cairo_path_buf_t *buf);
@ -69,12 +69,15 @@ _cairo_path_buf_add_points (cairo_path_buf_t *buf,
void void
_cairo_path_fixed_init (cairo_path_fixed_t *path) _cairo_path_fixed_init (cairo_path_fixed_t *path)
{ {
path->buf_head->next = NULL; path->buf_head.base.next = NULL;
path->buf_head->prev = NULL; path->buf_head.base.prev = NULL;
path->buf_tail = path->buf_head; path->buf_tail = &path->buf_head.base;
path->buf_head->num_ops = 0; path->buf_head.base.num_ops = 0;
path->buf_head->num_points = 0; path->buf_head.base.num_points = 0;
path->buf_head.base.buf_size = CAIRO_PATH_BUF_SIZE;
path->buf_head.base.op = path->buf_head.op;
path->buf_head.base.points = path->buf_head.points;
path->current_point.x = 0; path->current_point.x = 0;
path->current_point.y = 0; path->current_point.y = 0;
@ -90,27 +93,34 @@ _cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
cairo_path_buf_t *buf, *other_buf; cairo_path_buf_t *buf, *other_buf;
_cairo_path_fixed_init (path); _cairo_path_fixed_init (path);
path->current_point = other->current_point; path->current_point = other->current_point;
path->has_current_point = other->has_current_point; path->has_current_point = other->has_current_point;
path->has_curve_to = other->has_curve_to; path->has_curve_to = other->has_curve_to;
path->last_move_point = other->last_move_point; path->last_move_point = other->last_move_point;
path->buf_head->num_ops = other->buf_head->num_ops; path->buf_head.base.num_ops = other->buf_head.base.num_ops;
path->buf_head->num_points = other->buf_head->num_points; path->buf_head.base.num_points = other->buf_head.base.num_points;
memcpy (path->buf_head->op, other->buf_head->op, path->buf_head.base.buf_size = other->buf_head.base.buf_size;
other->buf_head->num_ops * sizeof (other->buf_head->op[0])); memcpy (path->buf_head.op, other->buf_head.base.op,
memcpy (path->buf_head->points, other->buf_head->points, other->buf_head.base.num_ops * sizeof (other->buf_head.op[0]));
other->buf_head->num_points * sizeof (other->buf_head->points[0])); memcpy (path->buf_head.points, other->buf_head.points,
for (other_buf = other->buf_head->next; other->buf_head.base.num_points * sizeof (other->buf_head.points[0]));
for (other_buf = other->buf_head.base.next;
other_buf; other_buf;
other_buf = other_buf->next) other_buf = other_buf->next)
{ {
buf = _cairo_path_buf_create (); buf = _cairo_path_buf_create (other_buf->buf_size);
if (buf == NULL) { if (buf == NULL) {
_cairo_path_fixed_fini (path); _cairo_path_fixed_fini (path);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
memcpy (buf, other_buf, sizeof (cairo_path_buf_t)); buf->num_ops = other_buf->num_ops;
buf->num_points = other_buf->num_points;
memcpy (buf->op, other_buf->op,
buf->num_ops * sizeof (buf->op[0]));
memcpy (buf->points, other_buf->points,
buf->num_points * sizeof (buf->points[0]));
_cairo_path_fixed_add_buf (path, buf); _cairo_path_fixed_add_buf (path, buf);
} }
@ -120,10 +130,14 @@ _cairo_path_fixed_init_copy (cairo_path_fixed_t *path,
cairo_path_fixed_t * cairo_path_fixed_t *
_cairo_path_fixed_create (void) _cairo_path_fixed_create (void)
{ {
cairo_path_fixed_t *path = malloc (sizeof (cairo_path_fixed_t)); cairo_path_fixed_t *path;
if (!path) path = malloc (sizeof (cairo_path_fixed_t));
if (!path) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
}
_cairo_path_fixed_init (path); _cairo_path_fixed_init (path);
return path; return path;
} }
@ -133,17 +147,17 @@ _cairo_path_fixed_fini (cairo_path_fixed_t *path)
{ {
cairo_path_buf_t *buf; cairo_path_buf_t *buf;
buf = path->buf_head->next; buf = path->buf_head.base.next;
while (buf) { while (buf) {
cairo_path_buf_t *this = buf; cairo_path_buf_t *this = buf;
buf = buf->next; buf = buf->next;
_cairo_path_buf_destroy (this); _cairo_path_buf_destroy (this);
} }
path->buf_head->next = NULL; path->buf_head.base.next = NULL;
path->buf_head->prev = NULL; path->buf_head.base.prev = NULL;
path->buf_tail = path->buf_head; path->buf_tail = &path->buf_head.base;
path->buf_head->num_ops = 0; path->buf_head.base.num_ops = 0;
path->buf_head->num_points = 0; path->buf_head.base.num_points = 0;
path->has_current_point = FALSE; path->has_current_point = FALSE;
path->has_curve_to = FALSE; path->has_curve_to = FALSE;
@ -202,7 +216,7 @@ _cairo_path_fixed_rel_move_to (cairo_path_fixed_t *path,
cairo_fixed_t x, y; cairo_fixed_t x, y;
if (! path->has_current_point) if (! path->has_current_point)
return CAIRO_STATUS_NO_CURRENT_POINT; return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT);
x = path->current_point.x + dx; x = path->current_point.x + dx;
y = path->current_point.y + dy; y = path->current_point.y + dy;
@ -248,7 +262,7 @@ _cairo_path_fixed_rel_line_to (cairo_path_fixed_t *path,
cairo_fixed_t x, y; cairo_fixed_t x, y;
if (! path->has_current_point) if (! path->has_current_point)
return CAIRO_STATUS_NO_CURRENT_POINT; return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT);
x = path->current_point.x + dx; x = path->current_point.x + dx;
y = path->current_point.y + dy; y = path->current_point.y + dy;
@ -298,7 +312,7 @@ _cairo_path_fixed_rel_curve_to (cairo_path_fixed_t *path,
cairo_fixed_t x2, y2; cairo_fixed_t x2, y2;
if (! path->has_current_point) if (! path->has_current_point)
return CAIRO_STATUS_NO_CURRENT_POINT; return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT);
x0 = path->current_point.x + dx0; x0 = path->current_point.x + dx0;
y0 = path->current_point.y + dy0; y0 = path->current_point.y + dy0;
@ -336,18 +350,18 @@ _cairo_path_fixed_close_path (cairo_path_fixed_t *path)
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
cairo_status_t cairo_bool_t
_cairo_path_fixed_get_current_point (cairo_path_fixed_t *path, _cairo_path_fixed_get_current_point (cairo_path_fixed_t *path,
cairo_fixed_t *x, cairo_fixed_t *x,
cairo_fixed_t *y) cairo_fixed_t *y)
{ {
if (! path->has_current_point) if (! path->has_current_point)
return CAIRO_STATUS_NO_CURRENT_POINT; return FALSE;
*x = path->current_point.x; *x = path->current_point.x;
*y = path->current_point.y; *y = path->current_point.y;
return CAIRO_STATUS_SUCCESS; return TRUE;
} }
static cairo_status_t static cairo_status_t
@ -356,20 +370,20 @@ _cairo_path_fixed_add (cairo_path_fixed_t *path,
cairo_point_t *points, cairo_point_t *points,
int num_points) int num_points)
{ {
if ((unsigned int) path->buf_tail->num_ops + 1 > CAIRO_PATH_BUF_SIZE || cairo_path_buf_t *buf = path->buf_tail;
(unsigned int) path->buf_tail->num_points + num_points > CAIRO_PATH_BUF_SIZE)
{
cairo_path_buf_t *buf;
buf = _cairo_path_buf_create (); if (buf->num_ops + 1 > buf->buf_size ||
buf->num_points + num_points > 2 * buf->buf_size)
{
buf = _cairo_path_buf_create (buf->buf_size * 2);
if (buf == NULL) if (buf == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_cairo_path_fixed_add_buf (path, buf); _cairo_path_fixed_add_buf (path, buf);
} }
_cairo_path_buf_add_op (path->buf_tail, op); _cairo_path_buf_add_op (buf, op);
_cairo_path_buf_add_points (path->buf_tail, points, num_points); _cairo_path_buf_add_points (buf, points, num_points);
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -386,17 +400,23 @@ _cairo_path_fixed_add_buf (cairo_path_fixed_t *path,
} }
static cairo_path_buf_t * static cairo_path_buf_t *
_cairo_path_buf_create (void) _cairo_path_buf_create (int buf_size)
{ {
cairo_path_buf_t *buf; cairo_path_buf_t *buf;
buf = malloc (sizeof (cairo_path_buf_t)); buf = _cairo_malloc_ab_plus_c (buf_size,
sizeof (cairo_path_op_t) +
2 * sizeof (cairo_point_t),
sizeof (cairo_path_buf_t));
if (buf) { if (buf) {
buf->next = NULL; buf->next = NULL;
buf->prev = NULL; buf->prev = NULL;
buf->num_ops = 0; buf->num_ops = 0;
buf->num_points = 0; buf->num_points = 0;
buf->buf_size = buf_size;
buf->op = (cairo_path_op_t *) (buf + 1);
buf->points = (cairo_point_t *) (buf->op + buf_size);
} }
return buf; return buf;
@ -450,7 +470,7 @@ _cairo_path_fixed_interpret (cairo_path_fixed_t *path,
cairo_bool_t forward = (dir == CAIRO_DIRECTION_FORWARD); cairo_bool_t forward = (dir == CAIRO_DIRECTION_FORWARD);
int step = forward ? 1 : -1; int step = forward ? 1 : -1;
for (buf = forward ? path->buf_head : path->buf_tail; for (buf = forward ? &path->buf_head.base : path->buf_tail;
buf; buf;
buf = forward ? buf->next : buf->prev) buf = forward ? buf->next : buf->prev)
{ {
@ -470,7 +490,7 @@ _cairo_path_fixed_interpret (cairo_path_fixed_t *path,
op = buf->op[i]; op = buf->op[i];
if (! forward) { if (! forward) {
points -= num_args[op]; points -= num_args[(int) op];
} }
switch (op) { switch (op) {
@ -492,7 +512,7 @@ _cairo_path_fixed_interpret (cairo_path_fixed_t *path,
return status; return status;
if (forward) { if (forward) {
points += num_args[op]; points += num_args[(int) op];
} }
} }
@ -508,7 +528,7 @@ _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path,
cairo_fixed_t scalex, cairo_fixed_t scalex,
cairo_fixed_t scaley) cairo_fixed_t scaley)
{ {
cairo_path_buf_t *buf = path->buf_head; cairo_path_buf_t *buf = &path->buf_head.base;
int i; int i;
while (buf) { while (buf) {
@ -565,14 +585,19 @@ _cairo_path_fixed_is_equal (cairo_path_fixed_t *path,
path->last_move_point.y != other->last_move_point.y) path->last_move_point.y != other->last_move_point.y)
return FALSE; return FALSE;
other_buf = other->buf_head; other_buf = &other->buf_head.base;
for (path_buf = path->buf_head; path_buf != NULL; path_buf = path_buf->next) { for (path_buf = &path->buf_head.base;
path_buf != NULL;
path_buf = path_buf->next)
{
if (other_buf == NULL || if (other_buf == NULL ||
path_buf->num_ops != other_buf->num_ops || path_buf->num_ops != other_buf->num_ops ||
path_buf->num_points != other_buf->num_points || path_buf->num_points != other_buf->num_points ||
memcmp (path_buf->op, other_buf->op, path_buf->num_ops) != 0 || memcmp (path_buf->op, other_buf->op, path_buf->num_ops) != 0 ||
memcmp (path_buf->points, other_buf->points, path_buf->num_points != 0)) memcmp (path_buf->points, other_buf->points, path_buf->num_points != 0))
{
return FALSE; return FALSE;
}
other_buf = other_buf->next; other_buf = other_buf->next;
} }
return TRUE; return TRUE;

View File

@ -39,8 +39,6 @@
#include "cairoint.h" #include "cairoint.h"
extern const cairo_private cairo_path_t _cairo_path_nil;
cairo_private cairo_path_t * cairo_private cairo_path_t *
_cairo_path_create (cairo_path_fixed_t *path, _cairo_path_create (cairo_path_fixed_t *path,
cairo_gstate_t *gstate); cairo_gstate_t *gstate);

View File

@ -272,19 +272,51 @@ _cairo_stroker_join (cairo_stroker_t *stroker, cairo_stroke_face_t *in, cairo_st
double in_dot_out = ((-in->usr_vector.x * out->usr_vector.x)+ double in_dot_out = ((-in->usr_vector.x * out->usr_vector.x)+
(-in->usr_vector.y * out->usr_vector.y)); (-in->usr_vector.y * out->usr_vector.y));
double ml = stroker->style->miter_limit; double ml = stroker->style->miter_limit;
double tolerance_squared = stroker->tolerance * stroker->tolerance;
double line_width_squared = (stroker->style->line_width *
stroker->style->line_width);
/* /* Check the miter limit -- lines meeting at an acute angle
* Check the miter limit -- lines meeting at an acute angle
* can generate long miters, the limit converts them to bevel * can generate long miters, the limit converts them to bevel
* *
* We want to know when the miter is within the miter limit. * Consider the miter join formed when two line segments
* That's straightforward to specify: * meet at an angle psi:
* *
* secant (psi / 2) <= ml * /.\
* /. .\
* /./ \.\
* /./psi\.\
* *
* where psi is the angle between in and out * We can zoom in on the right half of that to see:
*
* |\
* | \ psi/2
* | \
* | \
* | \
* | \
* miter \
* length \
* | \
* | .\
* | . \
* |. line \
* \ width \
* \ \
*
*
* The right triangle in that figure, (the line-width side is
* shown faintly with three '.' characters), gives us the
* following expression relating miter length, angle and line
* width:
*
* 1 /sin (psi/2) = miter_length / line_width
*
* The right-hand side of this relationship is the same ratio
* in which the miter limit (ml) is expressed. We want to know
* when the miter length is within the miter limit. That is
* when the following condition holds:
* *
* secant(psi/2) = 1/sin(psi/2)
* 1/sin(psi/2) <= ml * 1/sin(psi/2) <= ml
* 1 <= ml sin(psi/2) * 1 <= ml sin(psi/2)
* 1 <= ml² sin²(psi/2) * 1 <= ml² sin²(psi/2)
@ -300,8 +332,79 @@ _cairo_stroker_join (cairo_stroker_t *stroker, cairo_stroke_face_t *in, cairo_st
* *
* 2 <= ml² (1 - in · out) * 2 <= ml² (1 - in · out)
* *
*
* That gives us the condition to avoid generating miters that
* are too large from angles that are too large. But we also
* need to avoid generating miters when the angle is very small.
*
* The miter formed from a tiny angle is also tiny, so the
* miter limit is not a concern. But with a tiny angle we will
* be computing the intersection of two lines that are very
* near parallel. Also, the limits of the fixed-point grid on
* the input face coordinates mean that the resulting
* intersection could be wildly wrong. (See the
* get-path-extents test case for a call to cairo_arc that
* results in two problematic faces.)
*
* Fortunately we can also derive an expression for when using
* a bevel join instead of a miter will introduce an error no
* larger than the tolerance. Consider the same join from
* before but with the miter now chopped off and replaced with
* a bevel join. The drawing is zoomed in a bit again, the
* point marked as '*' is the center of the stroke---the point
* where the two line segments of interest intersect:
*
* ----- .
* ^ ..
* | . .
* | . .
* 1/2 . .
* miter . . |
* length . . |
* | .______. ___v___
* | | . \ 1/2 bevel
* v | . \ width
* ---- * \ -------
* | \ ^
*
*
* The length of interest here is the vertical length of the
* miter that is eliminated. It's length can be obtained by
* starting with 1/2 the miter length and the subtracting off
* the vertical length that is included by the bevel join,
* (here termed 1/2 bevel width). To determine this new bevel
* width, we have a small right triangle shown, the hypotenuse
* of which has a length of 1/2 the line width, and the small
* angle at the upper right of the figure is psi/2.
*
* So we have:
*
* sin (psi/2) = (bevel_width / 2) / (line_width / 2)
*
* And we can determine when the miter is required by
* calculating when the eliminated portion of the miter is
* greater than the tolerance:
*
* (miter_length / 2) - (bevel_width / 2) > tolerance
*
* Substituting in the above expressions for miter_length and
* bevel_width:
*
* (line_width/2) / sin (psi/2) - (line_width/2) * sin (psi/2) > tolerance
* 1 / sin(psi/2) - sin (psi/2) > 2 * tolerance / line_width
* 1 / sin²(psi/2) -2 + sin²(psi/2) > 4 * (tolerance/line_width)²
*
* Use identity: sin²(psi/2) = (1-cos(psi))/2
* 2/(1 - cos(psi)) - 2 + (1-cos(psi))/2 > 4 * (tolerance/line_width)²
* 4/(1 - cos(psi)) - 4 + (1-cos(psi)) > 8 * (tolerance/line_width)²
* 4/(1 - cos(psi)) + (1-cos(psi)) > 8 * ((tolerance/line_width)² + 0.5)
*/ */
if (2 <= ml * ml * (1 - in_dot_out)) { if ((2 <= ml * ml * (1 - in_dot_out)) &&
((8 * (tolerance_squared / line_width_squared + 0.5)) <
4 / (1 - in_dot_out) + (1 - in_dot_out))
)
{
double x1, y1, x2, y2; double x1, y1, x2, y2;
double mx, my; double mx, my;
double dx1, dx2, dy1, dy2; double dx1, dx2, dy1, dy2;
@ -816,7 +919,7 @@ _cairo_stroker_curve_to (void *closure,
if (stroker->has_current_face) { if (stroker->has_current_face) {
status = _cairo_stroker_join (stroker, &stroker->current_face, &start); status = _cairo_stroker_join (stroker, &stroker->current_face, &start);
if (status) if (status)
return status; goto CLEANUP_PEN;
} else if (!stroker->has_first_face) { } else if (!stroker->has_first_face) {
stroker->first_face = start; stroker->first_face = start;
stroker->has_first_face = TRUE; stroker->has_first_face = TRUE;
@ -1064,9 +1167,11 @@ _cairo_rectilinear_stroker_add_segment (cairo_rectilinear_stroker_t *stroker,
/* Common case is one rectangle of exactly 4 segments. */ /* Common case is one rectangle of exactly 4 segments. */
if (new_size == 0) if (new_size == 0)
new_size = 4; new_size = 4;
new_segments = realloc (stroker->segments, new_size * sizeof (cairo_line_t)); new_segments = _cairo_realloc_ab (stroker->segments,
new_size, sizeof (cairo_line_t));
if (new_segments == NULL) if (new_segments == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
stroker->segments_size = new_size; stroker->segments_size = new_size;
stroker->segments = new_segments; stroker->segments = new_segments;
} }

View File

@ -39,7 +39,7 @@
#include "cairo-path-private.h" #include "cairo-path-private.h"
#include "cairo-path-fixed-private.h" #include "cairo-path-fixed-private.h"
const cairo_path_t _cairo_path_nil = { CAIRO_STATUS_NO_MEMORY, NULL, 0 }; static const cairo_path_t _cairo_path_nil = { CAIRO_STATUS_NO_MEMORY, NULL, 0 };
/* Closure for path interpretation. */ /* Closure for path interpretation. */
typedef struct cairo_path_count { typedef struct cairo_path_count {
@ -339,7 +339,7 @@ _cairo_path_populate (cairo_path_t *path,
/* Sanity check the count */ /* Sanity check the count */
assert (cpp.data - path->data == path->num_data); assert (cpp.data - path->data == path->num_data);
return status; return CAIRO_STATUS_SUCCESS;
} }
cairo_path_t * cairo_path_t *
@ -352,8 +352,10 @@ _cairo_path_create_in_error (cairo_status_t status)
return (cairo_path_t*) &_cairo_path_nil; return (cairo_path_t*) &_cairo_path_nil;
path = malloc (sizeof (cairo_path_t)); path = malloc (sizeof (cairo_path_t));
if (path == NULL) if (path == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_path_t*) &_cairo_path_nil; return (cairo_path_t*) &_cairo_path_nil;
}
path->num_data = 0; path->num_data = 0;
path->data = NULL; path->data = NULL;
@ -370,25 +372,34 @@ _cairo_path_create_internal (cairo_path_fixed_t *path_fixed,
cairo_path_t *path; cairo_path_t *path;
path = malloc (sizeof (cairo_path_t)); path = malloc (sizeof (cairo_path_t));
if (path == NULL) if (path == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_path_t*) &_cairo_path_nil; return (cairo_path_t*) &_cairo_path_nil;
}
path->num_data = _cairo_path_count (path, path_fixed, path->num_data = _cairo_path_count (path, path_fixed,
_cairo_gstate_get_tolerance (gstate), _cairo_gstate_get_tolerance (gstate),
flatten); flatten);
if (path->num_data <= 0) { if (path->num_data < 0) {
free (path); free (path);
return (cairo_path_t*) &_cairo_path_nil; return (cairo_path_t*) &_cairo_path_nil;
} }
path->data = _cairo_malloc_ab (path->num_data, sizeof (cairo_path_data_t)); if (path->num_data) {
if (path->data == NULL) { path->data = _cairo_malloc_ab (path->num_data,
free (path); sizeof (cairo_path_data_t));
return (cairo_path_t*) &_cairo_path_nil; if (path->data == NULL) {
} free (path);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_path_t*) &_cairo_path_nil;
}
path->status = _cairo_path_populate (path, path_fixed, path->status = _cairo_path_populate (path, path_fixed,
gstate, flatten); gstate, flatten);
} else {
path->data = NULL;
path->status = CAIRO_STATUS_SUCCESS;
}
return path; return path;
} }
@ -413,8 +424,9 @@ cairo_path_destroy (cairo_path_t *path)
if (path == NULL || path == &_cairo_path_nil) if (path == NULL || path == &_cairo_path_nil)
return; return;
free (path->data); if (path->data)
path->num_data = 0; free (path->data);
free (path); free (path);
} }
@ -484,19 +496,19 @@ _cairo_path_append_to_context (const cairo_path_t *path,
switch (p->header.type) { switch (p->header.type) {
case CAIRO_PATH_MOVE_TO: case CAIRO_PATH_MOVE_TO:
if (p->header.length < 2) if (p->header.length < 2)
return CAIRO_STATUS_INVALID_PATH_DATA; return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
cairo_move_to (cr, cairo_move_to (cr,
p[1].point.x, p[1].point.y); p[1].point.x, p[1].point.y);
break; break;
case CAIRO_PATH_LINE_TO: case CAIRO_PATH_LINE_TO:
if (p->header.length < 2) if (p->header.length < 2)
return CAIRO_STATUS_INVALID_PATH_DATA; return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
cairo_line_to (cr, cairo_line_to (cr,
p[1].point.x, p[1].point.y); p[1].point.x, p[1].point.y);
break; break;
case CAIRO_PATH_CURVE_TO: case CAIRO_PATH_CURVE_TO:
if (p->header.length < 4) if (p->header.length < 4)
return CAIRO_STATUS_INVALID_PATH_DATA; return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
cairo_curve_to (cr, cairo_curve_to (cr,
p[1].point.x, p[1].point.y, p[1].point.x, p[1].point.y,
p[2].point.x, p[2].point.y, p[2].point.x, p[2].point.y,
@ -504,11 +516,11 @@ _cairo_path_append_to_context (const cairo_path_t *path,
break; break;
case CAIRO_PATH_CLOSE_PATH: case CAIRO_PATH_CLOSE_PATH:
if (p->header.length < 1) if (p->header.length < 1)
return CAIRO_STATUS_INVALID_PATH_DATA; return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
cairo_close_path (cr); cairo_close_path (cr);
break; break;
default: default:
return CAIRO_STATUS_INVALID_PATH_DATA; return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA);
} }
status = cairo_status (cr); status = cairo_status (cr);

View File

@ -32,31 +32,31 @@
const cairo_solid_pattern_t _cairo_pattern_nil = { const cairo_solid_pattern_t _cairo_pattern_nil = {
{ CAIRO_PATTERN_TYPE_SOLID, /* type */ { CAIRO_PATTERN_TYPE_SOLID, /* type */
CAIRO_REF_COUNT_INVALID, /* ref_count */ CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_NO_MEMORY, /* status */ CAIRO_STATUS_NO_MEMORY, /* status */
{ 0, 0, 0, NULL }, /* user_data */ { 0, 0, 0, NULL }, /* user_data */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */ { 1., 0., 0., 1., 0., 0., }, /* matrix */
CAIRO_FILTER_DEFAULT, /* filter */ CAIRO_FILTER_DEFAULT, /* filter */
CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */ CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */
}; };
static const cairo_solid_pattern_t _cairo_pattern_nil_null_pointer = { static const cairo_solid_pattern_t _cairo_pattern_nil_null_pointer = {
{ CAIRO_PATTERN_TYPE_SOLID, /* type */ { CAIRO_PATTERN_TYPE_SOLID, /* type */
CAIRO_REF_COUNT_INVALID, /* ref_count */ CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_NULL_POINTER,/* status */ CAIRO_STATUS_NULL_POINTER, /* status */
{ 0, 0, 0, NULL }, /* user_data */ { 0, 0, 0, NULL }, /* user_data */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */ { 1., 0., 0., 1., 0., 0., }, /* matrix */
CAIRO_FILTER_DEFAULT, /* filter */ CAIRO_FILTER_DEFAULT, /* filter */
CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */ CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */
}; };
const cairo_solid_pattern_t cairo_pattern_none = { const cairo_solid_pattern_t cairo_pattern_none = {
{ CAIRO_PATTERN_TYPE_SOLID, /* type */ { CAIRO_PATTERN_TYPE_SOLID, /* type */
CAIRO_REF_COUNT_INVALID, /* ref_count */ CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_SUCCESS, /* status */ CAIRO_STATUS_SUCCESS, /* status */
{ 0, 0, 0, NULL }, /* user_data */ { 0, 0, 0, NULL }, /* user_data */
{ 1., 0., 0., 1., 0., 0., }, /* matrix */ { 1., 0., 0., 1., 0., 0., }, /* matrix */
CAIRO_FILTER_DEFAULT, /* filter */ CAIRO_FILTER_DEFAULT, /* filter */
CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */ CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */
}; };
@ -66,27 +66,26 @@ const cairo_solid_pattern_t cairo_pattern_none = {
* @status: a status value indicating an error, (eg. not * @status: a status value indicating an error, (eg. not
* CAIRO_STATUS_SUCCESS) * CAIRO_STATUS_SUCCESS)
* *
* Sets pattern->status to @status and calls _cairo_error; * Atomically sets pattern->status to @status and calls _cairo_error;
* *
* All assignments of an error status to pattern->status should happen * All assignments of an error status to pattern->status should happen
* through _cairo_pattern_set_error() or else _cairo_error() should be * through _cairo_pattern_set_error(). Note that due to the nature of
* called immediately after the assignment. * the atomic operation, it is not safe to call this function on the nil
* objects.
* *
* The purpose of this function is to allow the user to set a * The purpose of this function is to allow the user to set a
* breakpoint in _cairo_error() to generate a stack trace for when the * breakpoint in _cairo_error() to generate a stack trace for when the
* user causes cairo to detect an error. * user causes cairo to detect an error.
**/ **/
static void static cairo_status_t
_cairo_pattern_set_error (cairo_pattern_t *pattern, _cairo_pattern_set_error (cairo_pattern_t *pattern,
cairo_status_t status) cairo_status_t status)
{ {
/* Don't overwrite an existing error. This preserves the first /* Don't overwrite an existing error. This preserves the first
* error, which is the most significant. It also avoids attempting * error, which is the most significant. */
* to write to read-only data (eg. from a nil pattern). */ _cairo_status_set_error (&pattern->status, status);
if (pattern->status == CAIRO_STATUS_SUCCESS)
pattern->status = status;
_cairo_error (status); return _cairo_error (status);
} }
static void static void
@ -95,7 +94,7 @@ _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
CAIRO_MUTEX_INITIALIZE (); CAIRO_MUTEX_INITIALIZE ();
pattern->type = type; pattern->type = type;
pattern->ref_count = 1; CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 1);
pattern->status = CAIRO_STATUS_SUCCESS; pattern->status = CAIRO_STATUS_SUCCESS;
_cairo_user_data_array_init (&pattern->user_data); _cairo_user_data_array_init (&pattern->user_data);
@ -138,8 +137,7 @@ _cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern,
if (pattern->stops == NULL) { if (pattern->stops == NULL) {
pattern->stops_size = 0; pattern->stops_size = 0;
pattern->n_stops = 0; pattern->n_stops = 0;
_cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY); return _cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_NO_MEMORY;
} }
memcpy (pattern->stops, other->stops, memcpy (pattern->stops, other->stops,
@ -153,10 +151,8 @@ cairo_status_t
_cairo_pattern_init_copy (cairo_pattern_t *pattern, _cairo_pattern_init_copy (cairo_pattern_t *pattern,
const cairo_pattern_t *other) const cairo_pattern_t *other)
{ {
if (other->status) { if (other->status)
_cairo_pattern_set_error (pattern, other->status); return _cairo_pattern_set_error (pattern, other->status);
return other->status;
}
switch (other->type) { switch (other->type) {
case CAIRO_PATTERN_TYPE_SOLID: { case CAIRO_PATTERN_TYPE_SOLID: {
@ -186,7 +182,7 @@ _cairo_pattern_init_copy (cairo_pattern_t *pattern,
} }
/* The reference count and user_data array are unique to the copy. */ /* The reference count and user_data array are unique to the copy. */
pattern->ref_count = 1; CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 1);
_cairo_user_data_array_init (&pattern->user_data); _cairo_user_data_array_init (&pattern->user_data);
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
@ -345,8 +341,8 @@ _cairo_pattern_create_in_error (cairo_status_t status)
pattern = _cairo_pattern_create_solid (_cairo_stock_color (CAIRO_STOCK_BLACK), pattern = _cairo_pattern_create_solid (_cairo_stock_color (CAIRO_STOCK_BLACK),
CAIRO_CONTENT_COLOR); CAIRO_CONTENT_COLOR);
/* no-op on a pattern already in error i.e the _cairo_pattern_nil */ if (pattern->status == CAIRO_STATUS_SUCCESS)
_cairo_pattern_set_error (pattern, status); status = _cairo_pattern_set_error (pattern, status);
return pattern; return pattern;
} }
@ -386,7 +382,7 @@ cairo_pattern_create_rgb (double red, double green, double blue)
pattern = _cairo_pattern_create_solid (&color, pattern = _cairo_pattern_create_solid (&color,
CAIRO_CONTENT_COLOR); CAIRO_CONTENT_COLOR);
if (pattern->status) if (pattern->status)
_cairo_error (pattern->status); _cairo_error_throw (pattern->status);
return pattern; return pattern;
} }
@ -430,7 +426,7 @@ cairo_pattern_create_rgba (double red, double green, double blue,
pattern = _cairo_pattern_create_solid (&color, pattern = _cairo_pattern_create_solid (&color,
CAIRO_CONTENT_COLOR_ALPHA); CAIRO_CONTENT_COLOR_ALPHA);
if (pattern->status) if (pattern->status)
_cairo_error (pattern->status); _cairo_error_throw (pattern->status);
return pattern; return pattern;
} }
@ -464,7 +460,7 @@ cairo_pattern_create_for_surface (cairo_surface_t *surface)
pattern = malloc (sizeof (cairo_surface_pattern_t)); pattern = malloc (sizeof (cairo_surface_pattern_t));
if (pattern == NULL) { if (pattern == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_pattern_t *)&_cairo_pattern_nil.base; return (cairo_pattern_t *)&_cairo_pattern_nil.base;
} }
@ -507,7 +503,7 @@ cairo_pattern_create_linear (double x0, double y0, double x1, double y1)
pattern = malloc (sizeof (cairo_linear_pattern_t)); pattern = malloc (sizeof (cairo_linear_pattern_t));
if (pattern == NULL) { if (pattern == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_pattern_t *) &_cairo_pattern_nil.base; return (cairo_pattern_t *) &_cairo_pattern_nil.base;
} }
@ -552,7 +548,7 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0,
pattern = malloc (sizeof (cairo_radial_pattern_t)); pattern = malloc (sizeof (cairo_radial_pattern_t));
if (pattern == NULL) { if (pattern == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_pattern_t *) &_cairo_pattern_nil.base; return (cairo_pattern_t *) &_cairo_pattern_nil.base;
} }
@ -577,12 +573,13 @@ cairo_pattern_create_radial (double cx0, double cy0, double radius0,
cairo_pattern_t * cairo_pattern_t *
cairo_pattern_reference (cairo_pattern_t *pattern) cairo_pattern_reference (cairo_pattern_t *pattern)
{ {
if (pattern == NULL || pattern->ref_count == CAIRO_REF_COUNT_INVALID) if (pattern == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
return pattern; return pattern;
assert (pattern->ref_count > 0); assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&pattern->ref_count));
pattern->ref_count++; _cairo_reference_count_inc (&pattern->ref_count);
return pattern; return pattern;
} }
@ -634,13 +631,13 @@ slim_hidden_def (cairo_pattern_status);
void void
cairo_pattern_destroy (cairo_pattern_t *pattern) cairo_pattern_destroy (cairo_pattern_t *pattern)
{ {
if (pattern == NULL || pattern->ref_count == CAIRO_REF_COUNT_INVALID) if (pattern == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
return; return;
assert (pattern->ref_count > 0); assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&pattern->ref_count));
pattern->ref_count--; if (! _cairo_reference_count_dec_and_test (&pattern->ref_count))
if (pattern->ref_count)
return; return;
_cairo_pattern_fini (pattern); _cairo_pattern_fini (pattern);
@ -680,10 +677,11 @@ slim_hidden_def (cairo_pattern_destroy);
unsigned int unsigned int
cairo_pattern_get_reference_count (cairo_pattern_t *pattern) cairo_pattern_get_reference_count (cairo_pattern_t *pattern)
{ {
if (pattern == NULL || pattern->ref_count == CAIRO_REF_COUNT_INVALID) if (pattern == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
return 0; return 0;
return pattern->ref_count; return CAIRO_REFERENCE_COUNT_GET_VALUE (&pattern->ref_count);
} }
/** /**
@ -732,8 +730,8 @@ cairo_pattern_set_user_data (cairo_pattern_t *pattern,
void *user_data, void *user_data,
cairo_destroy_func_t destroy) cairo_destroy_func_t destroy)
{ {
if (pattern->ref_count == CAIRO_REF_COUNT_INVALID) if (CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return _cairo_user_data_array_set_data (&pattern->user_data, return _cairo_user_data_array_set_data (&pattern->user_data,
key, user_data, destroy); key, user_data, destroy);
@ -763,12 +761,13 @@ _cairo_pattern_gradient_grow (cairo_gradient_pattern_t *pattern)
if (new_stops) if (new_stops)
memcpy (new_stops, pattern->stops, old_size * sizeof (cairo_gradient_stop_t)); memcpy (new_stops, pattern->stops, old_size * sizeof (cairo_gradient_stop_t));
} else { } else {
new_stops = realloc (pattern->stops, new_size * sizeof (cairo_gradient_stop_t)); new_stops = _cairo_realloc_ab (pattern->stops,
new_size,
sizeof (cairo_gradient_stop_t));
} }
if (new_stops == NULL) { if (new_stops == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
pattern->stops = new_stops; pattern->stops = new_stops;
pattern->stops_size = new_size; pattern->stops_size = new_size;
@ -791,7 +790,7 @@ _cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern,
if (pattern->n_stops >= pattern->stops_size) { if (pattern->n_stops >= pattern->stops_size) {
cairo_status_t status = _cairo_pattern_gradient_grow (pattern); cairo_status_t status = _cairo_pattern_gradient_grow (pattern);
if (status) { if (status) {
_cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY); status = _cairo_pattern_set_error (&pattern->base, status);
return; return;
} }
} }
@ -980,7 +979,7 @@ cairo_pattern_set_matrix (cairo_pattern_t *pattern,
inverse = *matrix; inverse = *matrix;
status = cairo_matrix_invert (&inverse); status = cairo_matrix_invert (&inverse);
if (status) if (status)
_cairo_pattern_set_error (pattern, status); status = _cairo_pattern_set_error (pattern, status);
} }
slim_hidden_def (cairo_pattern_set_matrix); slim_hidden_def (cairo_pattern_set_matrix);
@ -1157,7 +1156,7 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) { if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
pixman_stops = _cairo_malloc_ab (pattern->n_stops, sizeof(pixman_gradient_stop_t)); pixman_stops = _cairo_malloc_ab (pattern->n_stops, sizeof(pixman_gradient_stop_t));
if (pixman_stops == NULL) if (pixman_stops == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
for (i = 0; i < pattern->n_stops; i++) { for (i = 0; i < pattern->n_stops; i++) {
@ -1206,7 +1205,7 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
free (pixman_stops); free (pixman_stops);
if (pixman_image == NULL) if (pixman_image == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (_cairo_surface_is_image (dst)) if (_cairo_surface_is_image (dst))
{ {
@ -1216,7 +1215,7 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
if (image->base.status) if (image->base.status)
{ {
pixman_image_unref (pixman_image); pixman_image_unref (pixman_image);
return CAIRO_STATUS_NO_MEMORY; return image->base.status;
} }
attr->x_offset = attr->y_offset = 0; attr->x_offset = attr->y_offset = 0;
@ -1258,7 +1257,7 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
if (image->base.status) { if (image->base.status) {
pixman_image_unref (pixman_image); pixman_image_unref (pixman_image);
return CAIRO_STATUS_NO_MEMORY; return image->base.status;
} }
pixman_image_set_filter (pixman_image, PIXMAN_FILTER_BILINEAR, NULL, 0); pixman_image_set_filter (pixman_image, PIXMAN_FILTER_BILINEAR, NULL, 0);
@ -1267,7 +1266,7 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
if (!pixman_image_set_transform (pixman_image, &pixman_transform)) { if (!pixman_image_set_transform (pixman_image, &pixman_transform)) {
cairo_surface_destroy (&image->base); cairo_surface_destroy (&image->base);
pixman_image_unref (pixman_image); pixman_image_unref (pixman_image);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
switch (pattern->base.extend) { switch (pattern->base.extend) {
@ -1328,7 +1327,7 @@ _cairo_pattern_solid_surface_matches (
const cairo_solid_pattern_t *pattern, const cairo_solid_pattern_t *pattern,
cairo_surface_t *dst) cairo_surface_t *dst)
{ {
if (cache->surface->ref_count != 1) if (CAIRO_REFERENCE_COUNT_GET_VALUE (&cache->surface->ref_count) != 1)
return FALSE; return FALSE;
if (! _cairo_color_equal (&cache->color, &pattern->color)) if (! _cairo_color_equal (&cache->color, &pattern->color))
@ -1470,7 +1469,7 @@ _gradient_is_opaque (const cairo_gradient_pattern_t *gradient)
unsigned int i; unsigned int i;
for (i = 0; i < gradient->n_stops; i++) for (i = 0; i < gradient->n_stops; i++)
if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (gradient->stops[i].color.alpha)) if (! CAIRO_COLOR_IS_OPAQUE (&gradient->stops[i].color))
return FALSE; return FALSE;
return TRUE; return TRUE;
@ -2024,7 +2023,7 @@ cairo_pattern_get_rgba (cairo_pattern_t *pattern,
double r0, g0, b0, a0; double r0, g0, b0, a0;
if (pattern->type != CAIRO_PATTERN_TYPE_SOLID) if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
return CAIRO_STATUS_PATTERN_TYPE_MISMATCH; return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
_cairo_color_get_rgba (&solid->color, &r0, &g0, &b0, &a0); _cairo_color_get_rgba (&solid->color, &r0, &g0, &b0, &a0);
@ -2062,7 +2061,7 @@ cairo_pattern_get_surface (cairo_pattern_t *pattern,
cairo_surface_pattern_t *spat = (cairo_surface_pattern_t*) pattern; cairo_surface_pattern_t *spat = (cairo_surface_pattern_t*) pattern;
if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE) if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
return CAIRO_STATUS_PATTERN_TYPE_MISMATCH; return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
if (surface) if (surface)
*surface = spat->surface; *surface = spat->surface;
@ -2101,10 +2100,10 @@ cairo_pattern_get_color_stop_rgba (cairo_pattern_t *pattern,
if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR && if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR &&
pattern->type != CAIRO_PATTERN_TYPE_RADIAL) pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
return CAIRO_STATUS_PATTERN_TYPE_MISMATCH; return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
if (index < 0 || (unsigned int) index >= gradient->n_stops) if (index < 0 || (unsigned int) index >= gradient->n_stops)
return CAIRO_STATUS_INVALID_INDEX; return _cairo_error (CAIRO_STATUS_INVALID_INDEX);
if (offset) if (offset)
*offset = _cairo_fixed_to_double(gradient->stops[index].x); *offset = _cairo_fixed_to_double(gradient->stops[index].x);
@ -2142,7 +2141,7 @@ cairo_pattern_get_color_stop_count (cairo_pattern_t *pattern,
if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR && if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR &&
pattern->type != CAIRO_PATTERN_TYPE_RADIAL) pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
return CAIRO_STATUS_PATTERN_TYPE_MISMATCH; return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
if (count) if (count)
*count = gradient->n_stops; *count = gradient->n_stops;
@ -2174,7 +2173,7 @@ cairo_pattern_get_linear_points (cairo_pattern_t *pattern,
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t*) pattern; cairo_linear_pattern_t *linear = (cairo_linear_pattern_t*) pattern;
if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR) if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR)
return CAIRO_STATUS_PATTERN_TYPE_MISMATCH; return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
if (x0) if (x0)
*x0 = _cairo_fixed_to_double (linear->p1.x); *x0 = _cairo_fixed_to_double (linear->p1.x);
@ -2215,7 +2214,7 @@ cairo_pattern_get_radial_circles (cairo_pattern_t *pattern,
cairo_radial_pattern_t *radial = (cairo_radial_pattern_t*) pattern; cairo_radial_pattern_t *radial = (cairo_radial_pattern_t*) pattern;
if (pattern->type != CAIRO_PATTERN_TYPE_RADIAL) if (pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
return CAIRO_STATUS_PATTERN_TYPE_MISMATCH; return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
if (x0) if (x0)
*x0 = _cairo_fixed_to_double (radial->c1.x); *x0 = _cairo_fixed_to_double (radial->c1.x);

View File

@ -83,6 +83,8 @@ struct _cairo_pdf_surface {
cairo_pdf_resource_t next_available_resource; cairo_pdf_resource_t next_available_resource;
cairo_pdf_resource_t pages_resource; cairo_pdf_resource_t pages_resource;
cairo_bool_t compress_content;
struct { struct {
cairo_bool_t active; cairo_bool_t active;
cairo_pdf_resource_t self; cairo_pdf_resource_t self;
@ -95,6 +97,7 @@ struct _cairo_pdf_surface {
struct { struct {
cairo_bool_t active; cairo_bool_t active;
cairo_output_stream_t *stream; cairo_output_stream_t *stream;
cairo_output_stream_t *mem_stream;
cairo_output_stream_t *old_output; cairo_output_stream_t *old_output;
cairo_pdf_group_resources_t resources; cairo_pdf_group_resources_t resources;
cairo_bool_t is_knockout; cairo_bool_t is_knockout;
@ -104,6 +107,7 @@ struct _cairo_pdf_surface {
struct { struct {
cairo_bool_t active; cairo_bool_t active;
cairo_output_stream_t *stream; cairo_output_stream_t *stream;
cairo_output_stream_t *mem_stream;
cairo_output_stream_t *old_output; cairo_output_stream_t *old_output;
cairo_pdf_group_resources_t resources; cairo_pdf_group_resources_t resources;
} content_stream; } content_stream;

File diff suppressed because it is too large Load Diff

View File

@ -78,10 +78,10 @@ _cairo_pen_init (cairo_pen_t *pen,
radius, radius,
ctm); ctm);
pen->vertices = _cairo_malloc_ab (pen->num_vertices, sizeof (cairo_pen_vertex_t)); pen->vertices = _cairo_malloc_ab (pen->num_vertices,
if (pen->vertices == NULL) { sizeof (cairo_pen_vertex_t));
return CAIRO_STATUS_NO_MEMORY; if (pen->vertices == NULL)
} return _cairo_error (CAIRO_STATUS_NO_MEMORY);
/* /*
* Compute pen coordinates. To generate the right ellipse, compute points around * Compute pen coordinates. To generate the right ellipse, compute points around
@ -119,10 +119,11 @@ _cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
*pen = *other; *pen = *other;
if (pen->num_vertices) { if (pen->num_vertices) {
pen->vertices = _cairo_malloc_ab (pen->num_vertices, sizeof (cairo_pen_vertex_t)); pen->vertices = _cairo_malloc_ab (pen->num_vertices,
if (pen->vertices == NULL) { sizeof (cairo_pen_vertex_t));
return CAIRO_STATUS_NO_MEMORY; if (pen->vertices == NULL)
} return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (pen->vertices, other->vertices, pen->num_vertices * sizeof (cairo_pen_vertex_t)); memcpy (pen->vertices, other->vertices, pen->num_vertices * sizeof (cairo_pen_vertex_t));
} }
@ -138,9 +139,10 @@ _cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points)
int i; int i;
num_vertices = pen->num_vertices + num_points; num_vertices = pen->num_vertices + num_points;
vertices = realloc (pen->vertices, num_vertices * sizeof (cairo_pen_vertex_t)); vertices = _cairo_realloc_ab (pen->vertices,
num_vertices, sizeof (cairo_pen_vertex_t));
if (vertices == NULL) if (vertices == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
pen->vertices = vertices; pen->vertices = vertices;
pen->num_vertices = num_vertices; pen->num_vertices = num_vertices;
@ -321,7 +323,13 @@ _cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen,
break; break;
} }
assert (i < pen->num_vertices); /* If the desired slope cannot be found between any of the pen
* vertices, then we must have a degenerate pen, (such as a pen
* that's been transformed to a line). In that case, we consider
* the first pen vertex as the appropriate clockwise vertex.
*/
if (i == pen->num_vertices)
i = 0;
*active = i; *active = i;
} }
@ -349,6 +357,14 @@ _cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen,
break; break;
} }
/* If the desired slope cannot be found between any of the pen
* vertices, then we must have a degenerate pen, (such as a pen
* that's been transformed to a line). In that case, we consider
* the last pen vertex as the appropriate counterclockwise vertex.
*/
if (i < 0)
i = pen->num_vertices - 1;
*active = i; *active = i;
} }

View File

@ -88,15 +88,24 @@ convert_data_to_bytes (png_structp png, png_row_infop row_info, png_bytep data)
* return. * return.
*/ */
static void static void
png_simple_error_callback (png_structp png_save_ptr, png_simple_error_callback (png_structp png,
png_const_charp error_msg) png_const_charp error_msg)
{ {
_cairo_error (CAIRO_STATUS_NO_MEMORY); cairo_status_t *error = png_get_error_ptr (png);
longjmp (png_save_ptr->jmpbuf, CAIRO_STATUS_NO_MEMORY);
/* default to the most likely error */
if (*error == CAIRO_STATUS_SUCCESS)
*error = _cairo_error (CAIRO_STATUS_NO_MEMORY);
#ifdef PNG_SETJMP_SUPPORTED
longjmp (png_jmpbuf (png), 1);
#endif
/* if we get here, then we have to choice but to abort ... */
} }
static void static void
png_simple_warning_callback (png_structp png_save_ptr, png_simple_warning_callback (png_structp png,
png_const_charp error_msg) png_const_charp error_msg)
{ {
} }
@ -108,13 +117,13 @@ write_png (cairo_surface_t *surface,
void *closure) void *closure)
{ {
int i; int i;
volatile cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_status_t status;
cairo_image_surface_t *image; cairo_image_surface_t *image;
void *image_extra; void *image_extra;
png_struct *png; png_struct *png;
png_info *info; png_info *info;
png_time pt; png_time pt;
png_byte **rows = NULL; png_byte **volatile rows = NULL;
png_color_16 white; png_color_16 white;
int png_color_type; int png_color_type;
int depth; int depth;
@ -124,14 +133,14 @@ write_png (cairo_surface_t *surface,
&image_extra); &image_extra);
if (status == CAIRO_STATUS_NO_MEMORY) if (status == CAIRO_STATUS_NO_MEMORY)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
else if (status != CAIRO_STATUS_SUCCESS) else if (status != CAIRO_STATUS_SUCCESS)
return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
if (image->height && image->width) { if (image->height && image->width) {
rows = _cairo_malloc_ab (image->height, sizeof(png_byte*)); rows = _cairo_malloc_ab (image->height, sizeof (png_byte*));
if (rows == NULL) { if (rows == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL1; goto BAIL1;
} }
@ -139,23 +148,24 @@ write_png (cairo_surface_t *surface,
rows[i] = (png_byte *) image->data + i * image->stride; rows[i] = (png_byte *) image->data + i * image->stride;
} }
png = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, png = png_create_write_struct (PNG_LIBPNG_VER_STRING, &status,
png_simple_error_callback, png_simple_error_callback,
png_simple_warning_callback); png_simple_warning_callback);
if (png == NULL) { if (png == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL2; goto BAIL2;
} }
info = png_create_info_struct (png); info = png_create_info_struct (png);
if (info == NULL) { if (info == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL3; goto BAIL3;
} }
status = setjmp (png_jmpbuf (png)); #ifdef PNG_SETJMP_SUPPORTED
if (status) if (setjmp (png_jmpbuf (png)))
goto BAIL3; goto BAIL3;
#endif
png_set_write_fn (png, closure, write_func, NULL); png_set_write_fn (png, closure, write_func, NULL);
@ -177,7 +187,7 @@ write_png (cairo_surface_t *surface,
png_color_type = PNG_COLOR_TYPE_GRAY; png_color_type = PNG_COLOR_TYPE_GRAY;
break; break;
default: default:
status = CAIRO_STATUS_INVALID_FORMAT; status = _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
goto BAIL3; goto BAIL3;
} }
@ -234,8 +244,11 @@ stdio_write_func (png_structp png, png_bytep data, png_size_t size)
size_t ret = fwrite (data, 1, size, fp); size_t ret = fwrite (data, 1, size, fp);
size -= ret; size -= ret;
data += ret; data += ret;
if (size && ferror (fp)) if (size && ferror (fp)) {
png_error(png, "Write Error"); cairo_status_t *error = png_get_error_ptr (png);
*error = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
png_error (png, NULL);
}
} }
} }
@ -263,12 +276,12 @@ cairo_surface_write_to_png (cairo_surface_t *surface,
fp = fopen (filename, "wb"); fp = fopen (filename, "wb");
if (fp == NULL) if (fp == NULL)
return CAIRO_STATUS_WRITE_ERROR; return _cairo_error (CAIRO_STATUS_WRITE_ERROR);
status = write_png (surface, stdio_write_func, fp); status = write_png (surface, stdio_write_func, fp);
if (fclose (fp) && status == CAIRO_STATUS_SUCCESS) if (fclose (fp) && status == CAIRO_STATUS_SUCCESS)
status = CAIRO_STATUS_WRITE_ERROR; status = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
return status; return status;
} }
@ -286,8 +299,11 @@ stream_write_func (png_structp png, png_bytep data, png_size_t size)
png_closure = png_get_io_ptr (png); png_closure = png_get_io_ptr (png);
status = png_closure->write_func (png_closure->closure, data, size); status = png_closure->write_func (png_closure->closure, data, size);
if (status) if (status) {
png_error(png, "Write Error"); cairo_status_t *error = png_get_error_ptr (png);
*error = status;
png_error (png, NULL);
}
} }
/** /**
@ -369,10 +385,11 @@ read_png (png_rw_ptr read_func,
int depth, color_type, interlace; int depth, color_type, interlace;
unsigned int i; unsigned int i;
unsigned int pixel_size; unsigned int pixel_size;
cairo_status_t status;
/* XXX: Perhaps we'll want some other error handlers? */ /* XXX: Perhaps we'll want some other error handlers? */
png = png_create_read_struct (PNG_LIBPNG_VER_STRING, png = png_create_read_struct (PNG_LIBPNG_VER_STRING,
NULL, &status,
png_simple_error_callback, png_simple_error_callback,
png_simple_warning_callback); png_simple_warning_callback);
if (png == NULL) if (png == NULL)
@ -384,10 +401,14 @@ read_png (png_rw_ptr read_func,
png_set_read_fn (png, closure, read_func); png_set_read_fn (png, closure, read_func);
status = CAIRO_STATUS_SUCCESS;
#ifdef PNG_SETJMP_SUPPORTED
if (setjmp (png_jmpbuf (png))) { if (setjmp (png_jmpbuf (png))) {
surface = (cairo_surface_t*) &_cairo_surface_nil_read_error; if (status != CAIRO_STATUS_NO_MEMORY)
surface = (cairo_surface_t*) &_cairo_surface_nil_read_error;
goto BAIL; goto BAIL;
} }
#endif
png_read_info (png, info); png_read_info (png, info);
@ -408,7 +429,7 @@ read_png (png_rw_ptr read_func,
png_set_gray_1_2_4_to_8 (png); png_set_gray_1_2_4_to_8 (png);
#endif #endif
/* transform transparency to alpha */ /* transform transparency to alpha */
if (png_get_valid(png, info, PNG_INFO_tRNS)) if (png_get_valid (png, info, PNG_INFO_tRNS))
png_set_tRNS_to_alpha (png); png_set_tRNS_to_alpha (png);
if (depth == 16) if (depth == 16)
@ -436,7 +457,7 @@ read_png (png_rw_ptr read_func,
if (data == NULL) if (data == NULL)
goto BAIL; goto BAIL;
row_pointers = _cairo_malloc_ab (png_height, sizeof(char *)); row_pointers = _cairo_malloc_ab (png_height, sizeof (char *));
if (row_pointers == NULL) if (row_pointers == NULL)
goto BAIL; goto BAIL;
@ -464,7 +485,7 @@ read_png (png_rw_ptr read_func,
png_destroy_read_struct (&png, &info, NULL); png_destroy_read_struct (&png, &info, NULL);
if (surface->status) if (surface->status)
_cairo_error (surface->status); _cairo_error_throw (surface->status);
return surface; return surface;
} }
@ -479,8 +500,11 @@ stdio_read_func (png_structp png, png_bytep data, png_size_t size)
size_t ret = fread (data, 1, size, fp); size_t ret = fread (data, 1, size, fp);
size -= ret; size -= ret;
data += ret; data += ret;
if (size && ferror (fp)) if (size && (feof (fp) || ferror (fp))) {
png_error(png, "Read Error"); cairo_status_t *error = png_get_error_ptr (png);
*error = _cairo_error (CAIRO_STATUS_READ_ERROR);
png_error (png, NULL);
}
} }
} }
@ -510,13 +534,13 @@ cairo_image_surface_create_from_png (const char *filename)
if (fp == NULL) { if (fp == NULL) {
switch (errno) { switch (errno) {
case ENOMEM: case ENOMEM:
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
case ENOENT: case ENOENT:
_cairo_error (CAIRO_STATUS_FILE_NOT_FOUND); _cairo_error_throw (CAIRO_STATUS_FILE_NOT_FOUND);
return (cairo_surface_t*) &_cairo_surface_nil_file_not_found; return (cairo_surface_t*) &_cairo_surface_nil_file_not_found;
default: default:
_cairo_error (CAIRO_STATUS_READ_ERROR); _cairo_error_throw (CAIRO_STATUS_READ_ERROR);
return (cairo_surface_t*) &_cairo_surface_nil_read_error; return (cairo_surface_t*) &_cairo_surface_nil_read_error;
} }
} }
@ -541,8 +565,11 @@ stream_read_func (png_structp png, png_bytep data, png_size_t size)
png_closure = png_get_io_ptr (png); png_closure = png_get_io_ptr (png);
status = png_closure->read_func (png_closure->closure, data, size); status = png_closure->read_func (png_closure->closure, data, size);
if (status) if (status) {
png_error(png, "Read Error"); cairo_status_t *error = png_get_error_ptr (png);
*error = status;
png_error (png, NULL);
}
} }
/** /**

View File

@ -97,12 +97,12 @@ _cairo_polygon_grow (cairo_polygon_t *polygon)
if (new_edges) if (new_edges)
memcpy (new_edges, polygon->edges, old_size * sizeof (cairo_edge_t)); memcpy (new_edges, polygon->edges, old_size * sizeof (cairo_edge_t));
} else { } else {
new_edges = realloc (polygon->edges, new_size * sizeof (cairo_edge_t)); new_edges = _cairo_realloc_ab (polygon->edges,
new_size, sizeof (cairo_edge_t));
} }
if (new_edges == NULL) { if (new_edges == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
polygon->edges = new_edges; polygon->edges = new_edges;
polygon->edges_size = new_size; polygon->edges_size = new_size;

View File

@ -36,11 +36,12 @@
#ifndef CAIRO_PRIVATE_H #ifndef CAIRO_PRIVATE_H
#define CAIRO_PRIVATE_H #define CAIRO_PRIVATE_H
#include "cairo-reference-count-private.h"
#include "cairo-gstate-private.h" #include "cairo-gstate-private.h"
#include "cairo-path-fixed-private.h" #include "cairo-path-fixed-private.h"
struct _cairo { struct _cairo {
unsigned int ref_count; cairo_reference_count_t ref_count;
cairo_status_t status; cairo_status_t status;

View File

@ -57,10 +57,11 @@ typedef struct cairo_ps_surface {
FILE *tmpfile; FILE *tmpfile;
cairo_output_stream_t *stream; cairo_output_stream_t *stream;
cairo_bool_t eps;
cairo_content_t content;
double width; double width;
double height; double height;
double max_width; int bbox_x1, bbox_y1, bbox_x2, bbox_y2;
double max_height;
int num_pages; int num_pages;
@ -76,6 +77,8 @@ typedef struct cairo_ps_surface {
cairo_array_t *dsc_comment_target; cairo_array_t *dsc_comment_target;
cairo_ps_level_t ps_level;
cairo_surface_t *paginated_surface; cairo_surface_t *paginated_surface;
} cairo_ps_surface_t; } cairo_ps_surface_t;

File diff suppressed because it is too large Load Diff

View File

@ -47,6 +47,20 @@ CAIRO_BEGIN_DECLS
/* PS-surface functions */ /* PS-surface functions */
/**
* cairo_ps_level_t
* @CAIRO_PS_LEVEL_2: The language level 2 of the PostScript specification.
* @CAIRO_PS_LEVEL_3: The language level 3 of the PostScript specification.
*
* #cairo_ps_level_t is used to describe the language level of the
* PostScript Language Reference that a generated PostScript file will
* conform to.
*/
typedef enum _cairo_ps_level {
CAIRO_PS_LEVEL_2,
CAIRO_PS_LEVEL_3
} cairo_ps_level_t;
cairo_public cairo_surface_t * cairo_public cairo_surface_t *
cairo_ps_surface_create (const char *filename, cairo_ps_surface_create (const char *filename,
double width_in_points, double width_in_points,
@ -58,6 +72,24 @@ cairo_ps_surface_create_for_stream (cairo_write_func_t write_func,
double width_in_points, double width_in_points,
double height_in_points); double height_in_points);
cairo_public void
cairo_ps_surface_restrict_to_level (cairo_surface_t *surface,
cairo_ps_level_t level);
cairo_public void
cairo_ps_get_levels (cairo_ps_level_t const **levels,
int *num_levels);
cairo_public const char *
cairo_ps_level_to_string (cairo_ps_level_t level);
cairo_public void
cairo_ps_surface_set_eps (cairo_surface_t *surface,
cairo_bool_t eps);
cairo_public cairo_bool_t
cairo_ps_surface_get_eps (cairo_surface_t *surface);
cairo_public void cairo_public void
cairo_ps_surface_set_size (cairo_surface_t *surface, cairo_ps_surface_set_size (cairo_surface_t *surface,
double width_in_points, double width_in_points,

View File

@ -72,9 +72,6 @@ _cairo_atsui_scaled_font_get_atsu_style (cairo_scaled_font_t *sfont);
ATSUFontID ATSUFontID
_cairo_atsui_scaled_font_get_atsu_font_id (cairo_scaled_font_t *sfont); _cairo_atsui_scaled_font_get_atsu_font_id (cairo_scaled_font_t *sfont);
CGFontRef
_cairo_atsui_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont);
#endif /* CAIRO_HAS_ATSUI_FONT */ #endif /* CAIRO_HAS_ATSUI_FONT */
#endif /* CAIRO_QUARTZ_PRIVATE_H */ #endif /* CAIRO_QUARTZ_PRIVATE_H */

View File

@ -38,6 +38,14 @@
#include "cairo-quartz-private.h" #include "cairo-quartz-private.h"
/* The 10.5 SDK includes a funky new definition of FloatToFixed which
* causes all sorts of breakage; so reset to old-style definition
*/
#ifdef FloatToFixed
#undef FloatToFixed
#define FloatToFixed(a) ((Fixed)((float)(a) * fixed1))
#endif
#include <Carbon/Carbon.h> #include <Carbon/Carbon.h>
#include <limits.h> #include <limits.h>
@ -90,6 +98,8 @@ CG_EXTERN void CGContextReplacePathWithStrokedPath (CGContextRef);
CG_EXTERN CGImageRef CGBitmapContextCreateImage (CGContextRef); CG_EXTERN CGImageRef CGBitmapContextCreateImage (CGContextRef);
#endif #endif
/* missing in 10.3.9 */
extern void CGContextClipToMask (CGContextRef, CGRect, CGImageRef) __attribute__((weak_import));
/* /*
* Utility functions * Utility functions
@ -315,10 +325,10 @@ ComputeGradientValue (void *info, const float *in, float *out)
if (i == 0 || i == grad->n_stops) { if (i == 0 || i == grad->n_stops) {
if (i == grad->n_stops) if (i == grad->n_stops)
--i; --i;
out[0] = grad->stops[i].color.red / 65535.; out[0] = grad->stops[i].color.red;
out[1] = grad->stops[i].color.green / 65535.; out[1] = grad->stops[i].color.green;
out[2] = grad->stops[i].color.blue / 65535.; out[2] = grad->stops[i].color.blue;
out[3] = grad->stops[i].color.alpha / 65535.; out[3] = grad->stops[i].color.alpha;
} else { } else {
float ax = _cairo_fixed_to_double(grad->stops[i-1].x); float ax = _cairo_fixed_to_double(grad->stops[i-1].x);
float bx = _cairo_fixed_to_double(grad->stops[i].x) - ax; float bx = _cairo_fixed_to_double(grad->stops[i].x) - ax;
@ -326,17 +336,17 @@ ComputeGradientValue (void *info, const float *in, float *out)
float ap = 1.0 - bp; float ap = 1.0 - bp;
out[0] = out[0] =
(grad->stops[i-1].color.red / 65535.) * ap + grad->stops[i-1].color.red * ap +
(grad->stops[i].color.red / 65535.) * bp; grad->stops[i].color.red * bp;
out[1] = out[1] =
(grad->stops[i-1].color.green / 65535.) * ap + grad->stops[i-1].color.green * ap +
(grad->stops[i].color.green / 65535.) * bp; grad->stops[i].color.green * bp;
out[2] = out[2] =
(grad->stops[i-1].color.blue / 65535.) * ap + grad->stops[i-1].color.blue * ap +
(grad->stops[i].color.blue / 65535.) * bp; grad->stops[i].color.blue * bp;
out[3] = out[3] =
(grad->stops[i-1].color.alpha / 65535.) * ap + grad->stops[i-1].color.alpha * ap +
(grad->stops[i].color.alpha / 65535.) * bp; grad->stops[i].color.alpha * bp;
} }
} }
@ -357,22 +367,23 @@ CreateGradientFunction (cairo_gradient_pattern_t *gpat)
&callbacks); &callbacks);
} }
static CGShadingRef static cairo_int_status_t
_cairo_quartz_cairo_gradient_pattern_to_quartz (cairo_pattern_t *abspat) _cairo_quartz_cairo_gradient_pattern_to_quartz (cairo_pattern_t *abspat,
CGShadingRef *shading)
{ {
cairo_matrix_t mat; cairo_matrix_t mat;
double x0, y0; double x0, y0;
if (abspat->type != CAIRO_PATTERN_TYPE_LINEAR && if (abspat->type != CAIRO_PATTERN_TYPE_LINEAR &&
abspat->type != CAIRO_PATTERN_TYPE_RADIAL) abspat->type != CAIRO_PATTERN_TYPE_RADIAL)
return NULL; return CAIRO_INT_STATUS_UNSUPPORTED;
/* bandaid for mozilla bug 379321, also visible in the /* bandaid for mozilla bug 379321, also visible in the
* linear-gradient-reflect test. * linear-gradient-reflect test.
*/ */
if (abspat->extend == CAIRO_EXTEND_REFLECT || if (abspat->extend == CAIRO_EXTEND_REFLECT ||
abspat->extend == CAIRO_EXTEND_REPEAT) abspat->extend == CAIRO_EXTEND_REPEAT)
return NULL; return CAIRO_INT_STATUS_UNSUPPORTED;
/* We can only do this if we have an identity pattern matrix; /* We can only do this if we have an identity pattern matrix;
* otherwise fall back through to the generic pattern case. * otherwise fall back through to the generic pattern case.
@ -383,17 +394,17 @@ _cairo_quartz_cairo_gradient_pattern_to_quartz (cairo_pattern_t *abspat)
*/ */
cairo_pattern_get_matrix (abspat, &mat); cairo_pattern_get_matrix (abspat, &mat);
if (mat.xx != 1.0 || mat.yy != 1.0 || mat.xy != 0.0 || mat.yx != 0.0) if (mat.xx != 1.0 || mat.yy != 1.0 || mat.xy != 0.0 || mat.yx != 0.0)
return NULL; return CAIRO_INT_STATUS_UNSUPPORTED;
x0 = mat.x0; x0 = mat.x0;
y0 = mat.y0; y0 = mat.y0;
if (abspat->type == CAIRO_PATTERN_TYPE_LINEAR) { if (abspat->type == CAIRO_PATTERN_TYPE_LINEAR) {
cairo_linear_pattern_t *lpat = (cairo_linear_pattern_t*) abspat; cairo_linear_pattern_t *lpat = (cairo_linear_pattern_t*) abspat;
CGShadingRef shading;
CGPoint start, end; CGPoint start, end;
CGFunctionRef gradFunc; CGFunctionRef gradFunc;
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB(); CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
bool extend = abspat->extend == CAIRO_EXTEND_PAD;
start = CGPointMake (_cairo_fixed_to_double (lpat->p1.x) - x0, start = CGPointMake (_cairo_fixed_to_double (lpat->p1.x) - x0,
_cairo_fixed_to_double (lpat->p1.y) - y0); _cairo_fixed_to_double (lpat->p1.y) - y0);
@ -402,22 +413,22 @@ _cairo_quartz_cairo_gradient_pattern_to_quartz (cairo_pattern_t *abspat)
cairo_pattern_reference (abspat); cairo_pattern_reference (abspat);
gradFunc = CreateGradientFunction ((cairo_gradient_pattern_t*) lpat); gradFunc = CreateGradientFunction ((cairo_gradient_pattern_t*) lpat);
shading = CGShadingCreateAxial (rgb, *shading = CGShadingCreateAxial (rgb,
start, end, start, end,
gradFunc, gradFunc,
true, true); extend, extend);
CGColorSpaceRelease(rgb); CGColorSpaceRelease(rgb);
CGFunctionRelease(gradFunc); CGFunctionRelease(gradFunc);
return shading; return CAIRO_STATUS_SUCCESS;
} }
if (abspat->type == CAIRO_PATTERN_TYPE_RADIAL) { if (abspat->type == CAIRO_PATTERN_TYPE_RADIAL) {
cairo_radial_pattern_t *rpat = (cairo_radial_pattern_t*) abspat; cairo_radial_pattern_t *rpat = (cairo_radial_pattern_t*) abspat;
CGShadingRef shading;
CGPoint start, end; CGPoint start, end;
CGFunctionRef gradFunc; CGFunctionRef gradFunc;
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB(); CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
bool extend = abspat->extend == CAIRO_EXTEND_PAD;
start = CGPointMake (_cairo_fixed_to_double (rpat->c1.x) - x0, start = CGPointMake (_cairo_fixed_to_double (rpat->c1.x) - x0,
_cairo_fixed_to_double (rpat->c1.y) - y0); _cairo_fixed_to_double (rpat->c1.y) - y0);
@ -426,29 +437,30 @@ _cairo_quartz_cairo_gradient_pattern_to_quartz (cairo_pattern_t *abspat)
cairo_pattern_reference (abspat); cairo_pattern_reference (abspat);
gradFunc = CreateGradientFunction ((cairo_gradient_pattern_t*) rpat); gradFunc = CreateGradientFunction ((cairo_gradient_pattern_t*) rpat);
shading = CGShadingCreateRadial (rgb, *shading = CGShadingCreateRadial (rgb,
start, start,
_cairo_fixed_to_double (rpat->r1), _cairo_fixed_to_double (rpat->r1),
end, end,
_cairo_fixed_to_double (rpat->r2), _cairo_fixed_to_double (rpat->r2),
gradFunc, gradFunc,
true, true); extend, extend);
CGColorSpaceRelease(rgb); CGColorSpaceRelease(rgb);
CGFunctionRelease(gradFunc); CGFunctionRelease(gradFunc);
return shading; return CAIRO_STATUS_SUCCESS;
} }
/* Shouldn't be reached */ /* Shouldn't be reached */
ASSERT_NOT_REACHED; ASSERT_NOT_REACHED;
return NULL; return CAIRO_STATUS_SUCCESS;
} }
/* generic cairo surface -> cairo_quartz_surface_t function */ /* generic cairo surface -> cairo_quartz_surface_t function */
static cairo_quartz_surface_t * static cairo_int_status_t
_cairo_quartz_surface_to_quartz (cairo_surface_t *target, cairo_surface_t *pat_surf) _cairo_quartz_surface_to_quartz (cairo_surface_t *target,
cairo_surface_t *pat_surf,
cairo_quartz_surface_t **quartz_surf)
{ {
cairo_quartz_surface_t *quartz_surf = NULL;
if (cairo_surface_get_type(pat_surf) != CAIRO_SURFACE_TYPE_QUARTZ) { if (cairo_surface_get_type(pat_surf) != CAIRO_SURFACE_TYPE_QUARTZ) {
/* XXXtodo/perf don't use clone if the source surface is an image surface! Instead, /* XXXtodo/perf don't use clone if the source surface is an image surface! Instead,
@ -458,35 +470,41 @@ _cairo_quartz_surface_to_quartz (cairo_surface_t *target, cairo_surface_t *pat_s
cairo_surface_t *ref_type = target; cairo_surface_t *ref_type = target;
cairo_surface_t *new_surf = NULL; cairo_surface_t *new_surf = NULL;
cairo_rectangle_int_t rect; cairo_rectangle_int_t rect;
cairo_status_t status;
if (ref_type == NULL) if (ref_type == NULL)
ref_type = cairo_quartz_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); ref_type = cairo_quartz_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
_cairo_surface_get_extents (pat_surf, &rect); status = _cairo_surface_get_extents (pat_surf, &rect);
if (status)
return status;
_cairo_surface_clone_similar (ref_type, pat_surf, rect.x, rect.y, status = _cairo_surface_clone_similar (ref_type, pat_surf, rect.x, rect.y,
rect.width, rect.height, &new_surf); rect.width, rect.height, &new_surf);
if (target == NULL) if (target == NULL)
cairo_surface_destroy(ref_type); cairo_surface_destroy(ref_type);
quartz_surf = (cairo_quartz_surface_t *) new_surf; if (status)
return status;
if (new_surf && if (new_surf &&
cairo_surface_get_type (new_surf) != CAIRO_SURFACE_TYPE_QUARTZ) { cairo_surface_get_type (new_surf) != CAIRO_SURFACE_TYPE_QUARTZ)
{
ND((stderr, "got a non-quartz surface, format=%d width=%u height=%u type=%d\n", cairo_surface_get_type (pat_surf), rect.width, rect.height, cairo_surface_get_type (new_surf))); ND((stderr, "got a non-quartz surface, format=%d width=%u height=%u type=%d\n", cairo_surface_get_type (pat_surf), rect.width, rect.height, cairo_surface_get_type (new_surf)));
cairo_surface_destroy (new_surf); cairo_surface_destroy (new_surf);
quartz_surf = NULL; return CAIRO_INT_STATUS_UNSUPPORTED;
} }
*quartz_surf = (cairo_quartz_surface_t *) new_surf;
} else { } else {
/* If it's a quartz surface, we can try to see if it's a CGBitmapContext; /* If it's a quartz surface, we can try to see if it's a CGBitmapContext;
* we do this when we call CGBitmapContextCreateImage below. * we do this when we call CGBitmapContextCreateImage below.
*/ */
cairo_surface_reference (pat_surf); cairo_surface_reference (pat_surf);
quartz_surf = (cairo_quartz_surface_t*) pat_surf; *quartz_surf = (cairo_quartz_surface_t*) pat_surf;
} }
return quartz_surf; return CAIRO_STATUS_SUCCESS;
} }
/* Generic cairo_pattern -> CGPattern function */ /* Generic cairo_pattern -> CGPattern function */
@ -495,17 +513,21 @@ SurfacePatternDrawFunc (void *info, CGContextRef context)
{ {
cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) info; cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) info;
cairo_surface_t *pat_surf = spat->surface; cairo_surface_t *pat_surf = spat->surface;
cairo_int_status_t status;
cairo_quartz_surface_t *quartz_surf = _cairo_quartz_surface_to_quartz (NULL, pat_surf); cairo_quartz_surface_t *quartz_surf;
if (!quartz_surf) CGImageRef img;
return;
CGImageRef img = CGBitmapContextCreateImage (quartz_surf->cgContext);
CGRect imageBounds; CGRect imageBounds;
status = _cairo_quartz_surface_to_quartz (NULL, pat_surf, &quartz_surf);
if (status)
return;
img = CGBitmapContextCreateImage (quartz_surf->cgContext);
if (!img) { if (!img) {
// ... give up. // ... give up.
ND((stderr, "CGBitmapContextCreateImage failed\n")); ND((stderr, "CGBitmapContextCreateImage failed\n"));
_cairo_error (CAIRO_STATUS_NO_MEMORY);
cairo_surface_destroy ((cairo_surface_t*)quartz_surf); cairo_surface_destroy ((cairo_surface_t*)quartz_surf);
return; return;
} }
@ -570,9 +592,10 @@ _init_pattern_with_snapshot (cairo_pattern_t *pattern,
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
static CGPatternRef static cairo_int_status_t
_cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t *dest, _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t *dest,
cairo_pattern_t *abspat) cairo_pattern_t *abspat,
CGPatternRef *cgpat)
{ {
cairo_surface_pattern_t *spat; cairo_surface_pattern_t *spat;
cairo_surface_t *pat_surf; cairo_surface_t *pat_surf;
@ -583,8 +606,8 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t
CGPatternCallbacks cb = { 0, CGPatternCallbacks cb = { 0,
SurfacePatternDrawFunc, SurfacePatternDrawFunc,
(CGFunctionReleaseInfoCallback) cairo_pattern_destroy }; (CGFunctionReleaseInfoCallback) cairo_pattern_destroy };
CGPatternRef cgpat;
float rw, rh; float rw, rh;
cairo_status_t status;
cairo_pattern_union_t *snap_pattern = NULL; cairo_pattern_union_t *snap_pattern = NULL;
cairo_pattern_t *target_pattern = abspat; cairo_pattern_t *target_pattern = abspat;
@ -592,12 +615,15 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t
cairo_matrix_t m; cairo_matrix_t m;
/* SURFACE is the only type we'll handle here */ /* SURFACE is the only type we'll handle here */
if (abspat->type != CAIRO_PATTERN_TYPE_SURFACE) if (abspat->type != CAIRO_PATTERN_TYPE_SURFACE)
return NULL; return CAIRO_INT_STATUS_UNSUPPORTED;
spat = (cairo_surface_pattern_t *) abspat; spat = (cairo_surface_pattern_t *) abspat;
pat_surf = spat->surface; pat_surf = spat->surface;
_cairo_surface_get_extents (pat_surf, &extents); status = _cairo_surface_get_extents (pat_surf, &extents);
if (status)
return status;
pbounds.origin.x = 0; pbounds.origin.x = 0;
pbounds.origin.y = 0; pbounds.origin.y = 0;
@ -649,14 +675,14 @@ _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t
target_pattern = abspat; target_pattern = abspat;
} }
cgpat = CGPatternCreate (target_pattern, *cgpat = CGPatternCreate (target_pattern,
pbounds, pbounds,
ptransform, ptransform,
rw, rh, rw, rh,
kCGPatternTilingConstantSpacing, /* kCGPatternTilingNoDistortion, */ kCGPatternTilingConstantSpacing, /* kCGPatternTilingNoDistortion, */
TRUE, TRUE,
&cb); &cb);
return cgpat; return CAIRO_STATUS_SUCCESS;
} }
typedef enum { typedef enum {
@ -691,8 +717,11 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
} else if (source->type == CAIRO_PATTERN_TYPE_LINEAR || } else if (source->type == CAIRO_PATTERN_TYPE_LINEAR ||
source->type == CAIRO_PATTERN_TYPE_RADIAL) source->type == CAIRO_PATTERN_TYPE_RADIAL)
{ {
CGShadingRef shading = _cairo_quartz_cairo_gradient_pattern_to_quartz (source); CGShadingRef shading = NULL;
if (!shading) cairo_int_status_t status;
status = _cairo_quartz_cairo_gradient_pattern_to_quartz (source, &shading);
if (status)
return DO_UNSUPPORTED; return DO_UNSUPPORTED;
surface->sourceShading = shading; surface->sourceShading = shading;
@ -703,14 +732,17 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
{ {
cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) source; cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) source;
cairo_surface_t *pat_surf = spat->surface; cairo_surface_t *pat_surf = spat->surface;
cairo_quartz_surface_t *quartz_surf = _cairo_quartz_surface_to_quartz ((cairo_surface_t *) surface, pat_surf); cairo_quartz_surface_t *quartz_surf;
if (!quartz_surf) CGImageRef img;
return DO_UNSUPPORTED;
CGImageRef img = CGBitmapContextCreateImage (quartz_surf->cgContext);
cairo_matrix_t m = spat->base.matrix; cairo_matrix_t m = spat->base.matrix;
cairo_rectangle_int_t extents; cairo_rectangle_int_t extents;
cairo_status_t status;
status = _cairo_quartz_surface_to_quartz ((cairo_surface_t *) surface, pat_surf, &quartz_surf);
if (status)
return DO_UNSUPPORTED;
img = CGBitmapContextCreateImage (quartz_surf->cgContext);
if (!img) if (!img)
return DO_UNSUPPORTED; return DO_UNSUPPORTED;
@ -719,7 +751,10 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
cairo_matrix_invert(&m); cairo_matrix_invert(&m);
_cairo_quartz_cairo_matrix_to_quartz (&m, &surface->sourceImageTransform); _cairo_quartz_cairo_matrix_to_quartz (&m, &surface->sourceImageTransform);
_cairo_surface_get_extents (pat_surf, &extents); status = _cairo_surface_get_extents (pat_surf, &extents);
if (status)
return DO_UNSUPPORTED;
surface->sourceImageRect = CGRectMake (0, 0, extents.width, extents.height); surface->sourceImageRect = CGRectMake (0, 0, extents.width, extents.height);
surface->sourceImageSurface = (cairo_surface_t *)quartz_surf; surface->sourceImageSurface = (cairo_surface_t *)quartz_surf;
@ -728,9 +763,11 @@ _cairo_quartz_setup_source (cairo_quartz_surface_t *surface,
} else if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { } else if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
float patternAlpha = 1.0f; float patternAlpha = 1.0f;
CGColorSpaceRef patternSpace; CGColorSpaceRef patternSpace;
CGPatternRef pattern;
cairo_int_status_t status;
CGPatternRef pattern = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source); status = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source, &pattern);
if (!pattern) if (status)
return DO_UNSUPPORTED; return DO_UNSUPPORTED;
// Save before we change the pattern, colorspace, etc. so that // Save before we change the pattern, colorspace, etc. so that
@ -910,13 +947,18 @@ _cairo_quartz_surface_acquire_source_image (void *abstract_surface,
cairo_image_surface_t **image_out, cairo_image_surface_t **image_out,
void **image_extra) void **image_extra)
{ {
cairo_int_status_t status;
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
//ND((stderr, "%p _cairo_quartz_surface_acquire_source_image\n", surface)); //ND((stderr, "%p _cairo_quartz_surface_acquire_source_image\n", surface));
*image_extra = NULL; *image_extra = NULL;
return _cairo_quartz_get_image (surface, image_out, NULL); status = _cairo_quartz_get_image (surface, image_out, NULL);
if (status)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_SUCCESS;
} }
static void static void
@ -945,7 +987,7 @@ _cairo_quartz_surface_acquire_dest_image (void *abstract_surface,
status = _cairo_quartz_get_image (surface, image_out, &data); status = _cairo_quartz_get_image (surface, image_out, &data);
if (status) if (status)
return status; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
*image_extra = data; *image_extra = data;
@ -966,6 +1008,7 @@ _cairo_quartz_surface_release_dest_image (void *abstract_surface,
if (!CGBitmapContextGetData (surface->cgContext)) { if (!CGBitmapContextGetData (surface->cgContext)) {
CGDataProviderRef dataProvider; CGDataProviderRef dataProvider;
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
CGImageRef img; CGImageRef img;
dataProvider = CGDataProviderCreateWithData (NULL, imageData, dataProvider = CGDataProviderCreateWithData (NULL, imageData,
@ -975,12 +1018,13 @@ _cairo_quartz_surface_release_dest_image (void *abstract_surface,
img = CGImageCreate (surface->extents.width, surface->extents.height, img = CGImageCreate (surface->extents.width, surface->extents.height,
8, 32, 8, 32,
surface->extents.width * 4, surface->extents.width * 4,
CGColorSpaceCreateDeviceRGB(), rgb,
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
dataProvider, dataProvider,
NULL, NULL,
false, false,
kCGRenderingIntentDefault); kCGRenderingIntentDefault);
CGColorSpaceRelease (rgb);
CGContextSetCompositeOperation (surface->cgContext, kPrivateCGCompositeCopy); CGContextSetCompositeOperation (surface->cgContext, kPrivateCGCompositeCopy);
@ -1079,7 +1123,6 @@ _cairo_quartz_surface_clone_similar (void *abstract_surface,
new_format = isurf->format; new_format = isurf->format;
dataProvider = CGDataProviderCreateWithData (NULL, dataProvider = CGDataProviderCreateWithData (NULL,
isurf->data, isurf->data,
isurf->height * isurf->stride, isurf->height * isurf->stride,
@ -1221,7 +1264,9 @@ _cairo_quartz_surface_fill (void *abstract_surface,
stroke.cgContext = surface->cgContext; stroke.cgContext = surface->cgContext;
stroke.ctm_inverse = NULL; stroke.ctm_inverse = NULL;
_cairo_quartz_cairo_path_to_quartz_context (path, &stroke); rv = _cairo_quartz_cairo_path_to_quartz_context (path, &stroke);
if (rv)
goto BAIL;
if (action == DO_SOLID || action == DO_PATTERN) { if (action == DO_SOLID || action == DO_PATTERN) {
if (fill_rule == CAIRO_FILL_RULE_WINDING) if (fill_rule == CAIRO_FILL_RULE_WINDING)
@ -1257,6 +1302,7 @@ _cairo_quartz_surface_fill (void *abstract_surface,
rv = CAIRO_INT_STATUS_UNSUPPORTED; rv = CAIRO_INT_STATUS_UNSUPPORTED;
} }
BAIL:
_cairo_quartz_teardown_source (surface, source); _cairo_quartz_teardown_source (surface, source);
CGContextRestoreGState (surface->cgContext); CGContextRestoreGState (surface->cgContext);
@ -1303,15 +1349,20 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
#define STATIC_DASH 32 #define STATIC_DASH 32
float sdash[STATIC_DASH]; float sdash[STATIC_DASH];
float *fdash = sdash; float *fdash = sdash;
unsigned int max_dashes = style->num_dashes;
unsigned int k; unsigned int k;
if (style->num_dashes > STATIC_DASH)
fdash = _cairo_malloc_ab (style->num_dashes, sizeof (float));
for (k = 0; k < style->num_dashes; k++) if (style->num_dashes%2)
fdash[k] = (float) style->dash[k]; max_dashes *= 2;
if (max_dashes > STATIC_DASH)
fdash = _cairo_malloc_ab (max_dashes, sizeof (float));
if (fdash == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
CGContextSetLineDash (surface->cgContext, style->dash_offset, fdash, style->num_dashes); for (k = 0; k < max_dashes; k++)
fdash[k] = (float) style->dash[k % style->num_dashes];
CGContextSetLineDash (surface->cgContext, style->dash_offset, fdash, max_dashes);
if (fdash != sdash) if (fdash != sdash)
free (fdash); free (fdash);
} }
@ -1328,7 +1379,9 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
stroke.cgContext = surface->cgContext; stroke.cgContext = surface->cgContext;
stroke.ctm_inverse = ctm_inverse; stroke.ctm_inverse = ctm_inverse;
_cairo_quartz_cairo_path_to_quartz_context (path, &stroke); rv = _cairo_quartz_cairo_path_to_quartz_context (path, &stroke);
if (rv)
goto BAIL;
if (action == DO_SOLID || action == DO_PATTERN) { if (action == DO_SOLID || action == DO_PATTERN) {
CGContextStrokePath (surface->cgContext); CGContextStrokePath (surface->cgContext);
@ -1352,6 +1405,7 @@ _cairo_quartz_surface_stroke (void *abstract_surface,
rv = CAIRO_INT_STATUS_UNSUPPORTED; rv = CAIRO_INT_STATUS_UNSUPPORTED;
} }
BAIL:
_cairo_quartz_teardown_source (surface, source); _cairo_quartz_teardown_source (surface, source);
CGContextRestoreGState (surface->cgContext); CGContextRestoreGState (surface->cgContext);
@ -1369,6 +1423,9 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
int num_glyphs, int num_glyphs,
cairo_scaled_font_t *scaled_font) cairo_scaled_font_t *scaled_font)
{ {
ATSUFontID fid;
ATSFontRef atsfref;
CGFontRef cgfref;
CGAffineTransform cairoTextTransform, textTransform, ctm; CGAffineTransform cairoTextTransform, textTransform, ctm;
// XXXtodo/perf: stack storage for glyphs/sizes // XXXtodo/perf: stack storage for glyphs/sizes
#define STATIC_BUF_SIZE 64 #define STATIC_BUF_SIZE 64
@ -1401,15 +1458,18 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
CGContextSetTextDrawingMode (surface->cgContext, kCGTextClip); CGContextSetTextDrawingMode (surface->cgContext, kCGTextClip);
} else { } else {
/* Unsupported */ /* Unsupported */
CGContextRestoreGState (surface->cgContext); rv = CAIRO_INT_STATUS_UNSUPPORTED;
return CAIRO_INT_STATUS_UNSUPPORTED; goto BAIL;
} }
CGContextSetCompositeOperation (surface->cgContext, _cairo_quartz_cairo_operator_to_quartz (op)); CGContextSetCompositeOperation (surface->cgContext, _cairo_quartz_cairo_operator_to_quartz (op));
/* this doesn't addref */ fid = _cairo_atsui_scaled_font_get_atsu_font_id (scaled_font);
CGFontRef cgfref = _cairo_atsui_scaled_font_get_cg_font_ref (scaled_font); atsfref = FMGetATSFontRefFromFont (fid);
cgfref = CGFontCreateWithPlatformFont (&atsfref);
CGContextSetFont (surface->cgContext, cgfref); CGContextSetFont (surface->cgContext, cgfref);
CGFontRelease (cgfref);
/* So this should include the size; I don't know if I need to extract the /* So this should include the size; I don't know if I need to extract the
* size from this and call CGContextSetFontSize.. will I get crappy hinting * size from this and call CGContextSetFontSize.. will I get crappy hinting
@ -1439,7 +1499,16 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
if (num_glyphs > STATIC_BUF_SIZE) { if (num_glyphs > STATIC_BUF_SIZE) {
cg_glyphs = (CGGlyph*) _cairo_malloc_ab (num_glyphs, sizeof(CGGlyph)); cg_glyphs = (CGGlyph*) _cairo_malloc_ab (num_glyphs, sizeof(CGGlyph));
if (cg_glyphs == NULL) {
rv = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL;
}
cg_advances = (CGSize*) _cairo_malloc_ab (num_glyphs, sizeof(CGSize)); cg_advances = (CGSize*) _cairo_malloc_ab (num_glyphs, sizeof(CGSize));
if (cg_advances == NULL) {
rv = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL;
}
} }
xprev = glyphs[0].x; xprev = glyphs[0].x;
@ -1470,11 +1539,6 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
cg_advances, cg_advances,
num_glyphs); num_glyphs);
if (cg_glyphs != &glyphs_static[0]) {
free (cg_glyphs);
free (cg_advances);
}
if (action == DO_IMAGE) { if (action == DO_IMAGE) {
CGContextConcatCTM (surface->cgContext, surface->sourceImageTransform); CGContextConcatCTM (surface->cgContext, surface->sourceImageTransform);
if (cairo_surface_get_type(((cairo_surface_pattern_t*)source)->surface) == CAIRO_SURFACE_TYPE_QUARTZ) { if (cairo_surface_get_type(((cairo_surface_pattern_t*)source)->surface) == CAIRO_SURFACE_TYPE_QUARTZ) {
@ -1487,6 +1551,15 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
CGContextDrawShading (surface->cgContext, surface->sourceShading); CGContextDrawShading (surface->cgContext, surface->sourceShading);
} }
BAIL:
if (cg_advances != &cg_advances_static[0]) {
free (cg_advances);
}
if (cg_glyphs != &glyphs_static[0]) {
free (cg_glyphs);
}
_cairo_quartz_teardown_source (surface, source); _cairo_quartz_teardown_source (surface, source);
CGContextRestoreGState (surface->cgContext); CGContextRestoreGState (surface->cgContext);
@ -1495,6 +1568,45 @@ _cairo_quartz_surface_show_glyphs (void *abstract_surface,
} }
#endif /* CAIRO_HAS_ATSUI_FONT */ #endif /* CAIRO_HAS_ATSUI_FONT */
static cairo_int_status_t
_cairo_quartz_surface_mask_with_surface (cairo_quartz_surface_t *surface,
cairo_operator_t op,
cairo_pattern_t *source,
cairo_surface_pattern_t *mask)
{
cairo_rectangle_int16_t extents;
cairo_quartz_surface_t *quartz_surf;
CGRect rect;
CGImageRef img;
cairo_surface_t *pat_surf = mask->surface;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
status = _cairo_surface_get_extents (pat_surf, &extents);
if (status)
return status;
status = _cairo_quartz_surface_to_quartz (NULL, pat_surf, &quartz_surf);
if (status)
return status;
img = CGBitmapContextCreateImage (quartz_surf->cgContext);
if (!img) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL;
}
rect = CGRectMake (-mask->base.matrix.x0, -mask->base.matrix.y0, extents.width, extents.height);
CGContextSaveGState (surface->cgContext);
CGContextClipToMask (surface->cgContext, rect, img);
status = _cairo_quartz_surface_paint (surface, op, source);
CGContextRestoreGState (surface->cgContext);
CGImageRelease (img);
BAIL:
cairo_surface_destroy ((cairo_surface_t*) quartz_surf);
return status;
}
static cairo_int_status_t static cairo_int_status_t
_cairo_quartz_surface_mask (void *abstract_surface, _cairo_quartz_surface_mask (void *abstract_surface,
cairo_operator_t op, cairo_operator_t op,
@ -1511,6 +1623,10 @@ _cairo_quartz_surface_mask (void *abstract_surface,
cairo_solid_pattern_t *solid_mask = (cairo_solid_pattern_t *) mask; cairo_solid_pattern_t *solid_mask = (cairo_solid_pattern_t *) mask;
CGContextSetAlpha (surface->cgContext, solid_mask->color.alpha); CGContextSetAlpha (surface->cgContext, solid_mask->color.alpha);
} else if (CGContextClipToMask &&
mask->type == CAIRO_PATTERN_TYPE_SURFACE &&
mask->extend == CAIRO_EXTEND_NONE) {
return _cairo_quartz_surface_mask_with_surface (surface, op, source, (cairo_surface_pattern_t *) mask);
} else { } else {
/* So, CGContextClipToMask is not present in 10.3.9, so we're /* So, CGContextClipToMask is not present in 10.3.9, so we're
* doomed; if we have imageData, we can do fallback, otherwise * doomed; if we have imageData, we can do fallback, otherwise
@ -1542,6 +1658,7 @@ _cairo_quartz_surface_intersect_clip_path (void *abstract_surface,
{ {
cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface;
quartz_stroke_t stroke; quartz_stroke_t stroke;
cairo_status_t status;
ND((stderr, "%p _cairo_quartz_surface_intersect_clip_path path: %p\n", surface, path)); ND((stderr, "%p _cairo_quartz_surface_intersect_clip_path path: %p\n", surface, path));
@ -1559,7 +1676,13 @@ _cairo_quartz_surface_intersect_clip_path (void *abstract_surface,
CGContextBeginPath (surface->cgContext); CGContextBeginPath (surface->cgContext);
stroke.cgContext = surface->cgContext; stroke.cgContext = surface->cgContext;
stroke.ctm_inverse = NULL; stroke.ctm_inverse = NULL;
_cairo_quartz_cairo_path_to_quartz_context (path, &stroke);
/* path must not be empty. */
CGContextMoveToPoint (surface->cgContext, 0, 0);
status = _cairo_quartz_cairo_path_to_quartz_context (path, &stroke);
if (status)
return status;
if (fill_rule == CAIRO_FILL_RULE_WINDING) if (fill_rule == CAIRO_FILL_RULE_WINDING)
CGContextClip (surface->cgContext); CGContextClip (surface->cgContext);
else else
@ -1794,6 +1917,7 @@ cairo_quartz_surface_create (cairo_format_t format,
width, height); width, height);
if (!surf) { if (!surf) {
CGContextRelease (cgc); CGContextRelease (cgc);
free (imageData);
// create_internal will have set an error // create_internal will have set an error
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
} }

View File

@ -0,0 +1,66 @@
/* cairo - a vector graphics library with display and print output
*
* Copyright © 2007 Chris Wilson
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
* The Original Code is the cairo graphics library.
*
* The Initial Developer of the Original Code is University of Southern
* California.
*
* Contributor(s):
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#ifndef CAIRO_REFRENCE_COUNT_PRIVATE_H
#define CAIRO_REFRENCE_COUNT_PRIVATE_H
#include "cairo-atomic-private.h"
CAIRO_BEGIN_DECLS
/* Encapsulate operations on the object's reference count */
typedef struct {
cairo_atomic_int_t ref_count;
} cairo_reference_count_t;
#define _cairo_reference_count_inc(RC) _cairo_atomic_int_inc (&(RC)->ref_count)
#define _cairo_reference_count_dec_and_test(RC) _cairo_atomic_int_dec_and_test (&(RC)->ref_count)
#define CAIRO_REFERENCE_COUNT_INIT(RC, VALUE) ((RC)->ref_count = (VALUE))
#define CAIRO_REFERENCE_COUNT_GET_VALUE(RC) _cairo_atomic_int_get (&(RC)->ref_count)
#define CAIRO_REFERENCE_COUNT_SET_VALUE(RC, VALUE) _cairo_atomic_int_set (&(RC)->ref_count, (VALUE))
#define CAIRO_REFERENCE_COUNT_INVALID_VALUE ((cairo_atomic_int_t) -1)
#define CAIRO_REFERENCE_COUNT_INVALID {CAIRO_REFERENCE_COUNT_INVALID_VALUE}
#define CAIRO_REFERENCE_COUNT_IS_INVALID(RC) (CAIRO_REFERENCE_COUNT_GET_VALUE (RC) == CAIRO_REFERENCE_COUNT_INVALID_VALUE)
#define CAIRO_REFERENCE_COUNT_HAS_REFERENCE(RC) (CAIRO_REFERENCE_COUNT_GET_VALUE (RC) > 0)
CAIRO_END_DECLS
#endif

View File

@ -39,6 +39,8 @@
#include <pixman.h> #include <pixman.h>
#include "cairo-compiler-private.h"
/* cairo_region_t is defined in cairoint.h */ /* cairo_region_t is defined in cairoint.h */
struct _cairo_region { struct _cairo_region {

View File

@ -67,7 +67,7 @@ _cairo_region_init_boxes (cairo_region_t *region,
if (count > ARRAY_LENGTH(stack_pboxes)) { if (count > ARRAY_LENGTH(stack_pboxes)) {
pboxes = _cairo_malloc_ab (count, sizeof(pixman_box16_t)); pboxes = _cairo_malloc_ab (count, sizeof(pixman_box16_t));
if (pboxes == NULL) if (pboxes == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
@ -78,7 +78,7 @@ _cairo_region_init_boxes (cairo_region_t *region,
} }
if (!pixman_region_init_rects (&region->rgn, pboxes, count)) if (!pixman_region_init_rects (&region->rgn, pboxes, count))
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (pboxes != stack_pboxes) if (pboxes != stack_pboxes)
free (pboxes); free (pboxes);
@ -96,7 +96,7 @@ cairo_int_status_t
_cairo_region_copy (cairo_region_t *dst, cairo_region_t *src) _cairo_region_copy (cairo_region_t *dst, cairo_region_t *src)
{ {
if (!pixman_region_copy (&dst->rgn, &src->rgn)) if (!pixman_region_copy (&dst->rgn, &src->rgn))
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -125,7 +125,7 @@ _cairo_region_get_boxes (cairo_region_t *region, int *num_boxes, cairo_box_int_t
cboxes = _cairo_malloc_ab (nboxes, sizeof(cairo_box_int_t)); cboxes = _cairo_malloc_ab (nboxes, sizeof(cairo_box_int_t));
if (cboxes == NULL) if (cboxes == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
for (i = 0; i < nboxes; i++) { for (i = 0; i < nboxes; i++) {
cboxes[i].p1.x = pboxes[i].x1; cboxes[i].p1.x = pboxes[i].x1;
@ -168,7 +168,7 @@ cairo_int_status_t
_cairo_region_subtract (cairo_region_t *dst, cairo_region_t *a, cairo_region_t *b) _cairo_region_subtract (cairo_region_t *dst, cairo_region_t *a, cairo_region_t *b)
{ {
if (!pixman_region_subtract (&dst->rgn, &a->rgn, &b->rgn)) if (!pixman_region_subtract (&dst->rgn, &a->rgn, &b->rgn))
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -177,7 +177,7 @@ cairo_int_status_t
_cairo_region_intersect (cairo_region_t *dst, cairo_region_t *a, cairo_region_t *b) _cairo_region_intersect (cairo_region_t *dst, cairo_region_t *a, cairo_region_t *b)
{ {
if (!pixman_region_intersect (&dst->rgn, &a->rgn, &b->rgn)) if (!pixman_region_intersect (&dst->rgn, &a->rgn, &b->rgn))
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -190,7 +190,7 @@ _cairo_region_union_rect (cairo_region_t *dst,
if (!pixman_region_union_rect (&dst->rgn, &src->rgn, if (!pixman_region_union_rect (&dst->rgn, &src->rgn,
rect->x, rect->y, rect->x, rect->y,
rect->width, rect->height)) rect->width, rect->height))
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }

View File

@ -42,6 +42,7 @@
#include "cairo-types-private.h" #include "cairo-types-private.h"
#include "cairo-mutex-type-private.h" #include "cairo-mutex-type-private.h"
#include "cairo-reference-count-private.h"
struct _cairo_scaled_font { struct _cairo_scaled_font {
/* For most cairo objects, the rule for multiple threads is that /* For most cairo objects, the rule for multiple threads is that
@ -79,7 +80,7 @@ struct _cairo_scaled_font {
/* useful bits for _cairo_scaled_font_nil */ /* useful bits for _cairo_scaled_font_nil */
cairo_status_t status; cairo_status_t status;
unsigned int ref_count; cairo_reference_count_t ref_count;
cairo_user_data_array_t user_data; cairo_user_data_array_t user_data;
/* hash key members */ /* hash key members */

View File

@ -188,7 +188,7 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *font_subsets,
unsigned long scaled_font_glyph_index, unsigned long scaled_font_glyph_index,
cairo_scaled_font_subsets_glyph_t *subset_glyph_ret); cairo_scaled_font_subsets_glyph_t *subset_glyph_ret);
typedef void typedef cairo_status_t
(*cairo_scaled_font_subset_callback_func_t) (cairo_scaled_font_subset_t *font_subset, (*cairo_scaled_font_subset_callback_func_t) (cairo_scaled_font_subset_t *font_subset,
void *closure); void *closure);
@ -262,6 +262,21 @@ _cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t
cairo_scaled_font_subset_callback_func_t font_subset_callback, cairo_scaled_font_subset_callback_func_t font_subset_callback,
void *closure); void *closure);
/**
* _cairo_scaled_font_subset_create_glyph_names:
* @font_subsets: a #cairo_scaled_font_subsets_t
*
* Create an array of strings containing the glyph name for each glyph
* in @font_subsets. The array as store in font_subsets->glyph_names.
*
* Return value: CAIRO_STATUS_SUCCESS if successful,
* CAIRO_INT_STATUS_UNSUPPORTED if the font backend does not support
* mapping the glyph indices to unicode characters. Possible errors
* include CAIRO_STATUS_NO_MEMORY.
**/
cairo_private cairo_int_status_t
_cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset);
typedef struct _cairo_cff_subset { typedef struct _cairo_cff_subset {
char *base_font; char *base_font;
int *widths; int *widths;

View File

@ -37,6 +37,7 @@
* Carl D. Worth <cworth@cworth.org> * Carl D. Worth <cworth@cworth.org>
* Kristian Høgsberg <krh@redhat.com> * Kristian Høgsberg <krh@redhat.com>
* Keith Packard <keithp@keithp.com> * Keith Packard <keithp@keithp.com>
* Adrian Johnson <ajohnson@redneon.com>
*/ */
#include "cairoint.h" #include "cairoint.h"
@ -95,10 +96,16 @@ typedef struct _cairo_sub_font_collection {
unsigned int subset_id; unsigned int subset_id;
cairo_status_t status;
cairo_scaled_font_subset_callback_func_t font_subset_callback; cairo_scaled_font_subset_callback_func_t font_subset_callback;
void *font_subset_callback_closure; void *font_subset_callback_closure;
} cairo_sub_font_collection_t; } cairo_sub_font_collection_t;
typedef struct _cairo_string_entry {
cairo_hash_entry_t base;
char *string;
} cairo_string_entry_t;
static void static void
_cairo_sub_font_glyph_init_key (cairo_sub_font_glyph_t *sub_font_glyph, _cairo_sub_font_glyph_init_key (cairo_sub_font_glyph_t *sub_font_glyph,
unsigned long scaled_font_glyph_index) unsigned long scaled_font_glyph_index)
@ -124,8 +131,10 @@ _cairo_sub_font_glyph_create (unsigned long scaled_font_glyph_index,
cairo_sub_font_glyph_t *sub_font_glyph; cairo_sub_font_glyph_t *sub_font_glyph;
sub_font_glyph = malloc (sizeof (cairo_sub_font_glyph_t)); sub_font_glyph = malloc (sizeof (cairo_sub_font_glyph_t));
if (sub_font_glyph == NULL) if (sub_font_glyph == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
}
_cairo_sub_font_glyph_init_key (sub_font_glyph, scaled_font_glyph_index); _cairo_sub_font_glyph_init_key (sub_font_glyph, scaled_font_glyph_index);
sub_font_glyph->subset_id = subset_id; sub_font_glyph->subset_id = subset_id;
@ -214,8 +223,10 @@ _cairo_sub_font_create (cairo_scaled_font_subsets_t *parent,
cairo_sub_font_t *sub_font; cairo_sub_font_t *sub_font;
sub_font = malloc (sizeof (cairo_sub_font_t)); sub_font = malloc (sizeof (cairo_sub_font_t));
if (sub_font == NULL) if (sub_font == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
}
sub_font->is_scaled = is_scaled; sub_font->is_scaled = is_scaled;
sub_font->is_composite = is_composite; sub_font->is_composite = is_composite;
@ -264,7 +275,7 @@ _cairo_sub_font_pluck (void *entry, void *closure)
_cairo_sub_font_destroy (sub_font); _cairo_sub_font_destroy (sub_font);
} }
static cairo_status_t static cairo_bool_t
_cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font, _cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font,
unsigned long scaled_font_glyph_index, unsigned long scaled_font_glyph_index,
cairo_scaled_font_subsets_glyph_t *subset_glyph) cairo_scaled_font_subsets_glyph_t *subset_glyph)
@ -282,10 +293,10 @@ _cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font,
subset_glyph->is_composite = sub_font->is_composite; subset_glyph->is_composite = sub_font->is_composite;
subset_glyph->x_advance = sub_font_glyph->x_advance; subset_glyph->x_advance = sub_font_glyph->x_advance;
return CAIRO_STATUS_SUCCESS; return TRUE;
} }
return CAIRO_STATUS_NULL_POINTER; return FALSE;
} }
static cairo_status_t static cairo_status_t
@ -321,10 +332,18 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index, sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index,
sub_font->current_subset, sub_font->current_subset,
sub_font->num_glyphs_in_current_subset++, sub_font->num_glyphs_in_current_subset,
scaled_glyph->metrics.x_advance); scaled_glyph->metrics.x_advance);
if (sub_font_glyph == NULL) if (sub_font_glyph == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base);
if (status) {
_cairo_sub_font_glyph_destroy (sub_font_glyph);
return status;
}
sub_font->num_glyphs_in_current_subset++;
if (sub_font->is_scaled) if (sub_font->is_scaled)
{ {
@ -336,12 +355,6 @@ _cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font,
if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_unscaled_subset_used) if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_unscaled_subset_used)
sub_font->parent->max_glyphs_per_unscaled_subset_used = sub_font->num_glyphs_in_current_subset; sub_font->parent->max_glyphs_per_unscaled_subset_used = sub_font->num_glyphs_in_current_subset;
} }
status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base);
if (status) {
_cairo_sub_font_glyph_destroy (sub_font_glyph);
return status;
}
} }
subset_glyph->font_id = sub_font->font_id; subset_glyph->font_id = sub_font->font_id;
@ -363,6 +376,9 @@ _cairo_sub_font_collect (void *entry, void *closure)
int i; int i;
unsigned int j; unsigned int j;
if (collection->status)
return;
for (i = 0; i <= sub_font->current_subset; i++) { for (i = 0; i <= sub_font->current_subset; i++) {
collection->subset_id = i; collection->subset_id = i;
@ -378,6 +394,10 @@ _cairo_sub_font_collect (void *entry, void *closure)
_cairo_hash_table_foreach (sub_font->sub_font_glyphs, _cairo_hash_table_foreach (sub_font->sub_font_glyphs,
_cairo_sub_font_glyph_collect, collection); _cairo_sub_font_glyph_collect, collection);
if (collection->status)
break;
if (collection->num_glyphs == 0)
continue;
/* Ensure the resulting array has no uninitialized holes */ /* Ensure the resulting array has no uninitialized holes */
assert (collection->num_glyphs == collection->max_glyph + 1); assert (collection->num_glyphs == collection->max_glyph + 1);
@ -388,6 +408,7 @@ _cairo_sub_font_collect (void *entry, void *closure)
subset.subset_id = i; subset.subset_id = i;
subset.glyphs = collection->glyphs; subset.glyphs = collection->glyphs;
subset.num_glyphs = collection->num_glyphs; subset.num_glyphs = collection->num_glyphs;
subset.glyph_names = NULL;
/* No need to check for out of memory here. If to_unicode is NULL, the PDF /* No need to check for out of memory here. If to_unicode is NULL, the PDF
* surface does not emit an ToUnicode stream */ * surface does not emit an ToUnicode stream */
subset.to_unicode = _cairo_malloc_ab (collection->num_glyphs, sizeof (unsigned long)); subset.to_unicode = _cairo_malloc_ab (collection->num_glyphs, sizeof (unsigned long));
@ -397,11 +418,20 @@ _cairo_sub_font_collect (void *entry, void *closure)
subset.to_unicode[j] = 0xfffd; subset.to_unicode[j] = 0xfffd;
} }
} }
(collection->font_subset_callback) (&subset, collection->status = (collection->font_subset_callback) (&subset,
collection->font_subset_callback_closure); collection->font_subset_callback_closure);
if (subset.to_unicode != NULL) if (subset.to_unicode != NULL)
free (subset.to_unicode); free (subset.to_unicode);
if (subset.glyph_names != NULL) {
for (j = 0; j < collection->num_glyphs; j++)
free (subset.glyph_names[j]);
free (subset.glyph_names);
}
if (collection->status)
break;
} }
} }
@ -411,8 +441,10 @@ _cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type)
cairo_scaled_font_subsets_t *subsets; cairo_scaled_font_subsets_t *subsets;
subsets = malloc (sizeof (cairo_scaled_font_subsets_t)); subsets = malloc (sizeof (cairo_scaled_font_subsets_t));
if (subsets == NULL) if (subsets == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
}
subsets->type = type; subsets->type = type;
subsets->max_glyphs_per_unscaled_subset_used = 0; subsets->max_glyphs_per_unscaled_subset_used = 0;
@ -487,10 +519,9 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
if (_cairo_hash_table_lookup (subsets->unscaled_sub_fonts, &key.base, if (_cairo_hash_table_lookup (subsets->unscaled_sub_fonts, &key.base,
(cairo_hash_entry_t **) &sub_font)) (cairo_hash_entry_t **) &sub_font))
{ {
status = _cairo_sub_font_lookup_glyph (sub_font, if (_cairo_sub_font_lookup_glyph (sub_font,
scaled_font_glyph_index, scaled_font_glyph_index,
subset_glyph); subset_glyph))
if (status == CAIRO_STATUS_SUCCESS)
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
} }
@ -501,10 +532,9 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
if (_cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base, if (_cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base,
(cairo_hash_entry_t **) &sub_font)) (cairo_hash_entry_t **) &sub_font))
{ {
status = _cairo_sub_font_lookup_glyph (sub_font, if (_cairo_sub_font_lookup_glyph (sub_font,
scaled_font_glyph_index, scaled_font_glyph_index,
subset_glyph); subset_glyph))
if (status == CAIRO_STATUS_SUCCESS)
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -551,13 +581,13 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
sub_font = _cairo_sub_font_create (subsets, sub_font = _cairo_sub_font_create (subsets,
unscaled_font, unscaled_font,
subsets->num_sub_fonts++, subsets->num_sub_fonts,
max_glyphs, max_glyphs,
subset_glyph->is_scaled, subset_glyph->is_scaled,
subset_glyph->is_composite); subset_glyph->is_composite);
if (sub_font == NULL) { if (sub_font == NULL) {
cairo_scaled_font_destroy (unscaled_font); cairo_scaled_font_destroy (unscaled_font);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts, status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts,
@ -566,6 +596,8 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
_cairo_sub_font_destroy (sub_font); _cairo_sub_font_destroy (sub_font);
return status; return status;
} }
subsets->num_sub_fonts++;
} }
} else { } else {
/* No path available. Add to scaled subset. */ /* No path available. Add to scaled subset. */
@ -583,13 +615,13 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
sub_font = _cairo_sub_font_create (subsets, sub_font = _cairo_sub_font_create (subsets,
cairo_scaled_font_reference (scaled_font), cairo_scaled_font_reference (scaled_font),
subsets->num_sub_fonts++, subsets->num_sub_fonts,
max_glyphs, max_glyphs,
subset_glyph->is_scaled, subset_glyph->is_scaled,
subset_glyph->is_composite); subset_glyph->is_composite);
if (sub_font == NULL) { if (sub_font == NULL) {
cairo_scaled_font_destroy (scaled_font); cairo_scaled_font_destroy (scaled_font);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
status = _cairo_hash_table_insert (subsets->scaled_sub_fonts, status = _cairo_hash_table_insert (subsets->scaled_sub_fonts,
@ -598,6 +630,8 @@ _cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets,
_cairo_sub_font_destroy (sub_font); _cairo_sub_font_destroy (sub_font);
return status; return status;
} }
subsets->num_sub_fonts++;
} }
} }
@ -624,10 +658,11 @@ _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t
collection.glyphs = _cairo_malloc_ab (collection.glyphs_size, sizeof(unsigned long)); collection.glyphs = _cairo_malloc_ab (collection.glyphs_size, sizeof(unsigned long));
if (collection.glyphs == NULL) if (collection.glyphs == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
collection.font_subset_callback = font_subset_callback; collection.font_subset_callback = font_subset_callback;
collection.font_subset_callback_closure = closure; collection.font_subset_callback_closure = closure;
collection.status = CAIRO_STATUS_SUCCESS;
if (is_scaled) if (is_scaled)
_cairo_hash_table_foreach (font_subsets->scaled_sub_fonts, _cairo_hash_table_foreach (font_subsets->scaled_sub_fonts,
@ -638,10 +673,10 @@ _cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t
free (collection.glyphs); free (collection.glyphs);
return CAIRO_STATUS_SUCCESS; return collection.status;
} }
cairo_private cairo_status_t cairo_status_t
_cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t *font_subsets, _cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t *font_subsets,
cairo_scaled_font_subset_callback_func_t font_subset_callback, cairo_scaled_font_subset_callback_func_t font_subset_callback,
void *closure) void *closure)
@ -652,7 +687,7 @@ _cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t *fon
TRUE); TRUE);
} }
cairo_private cairo_status_t cairo_status_t
_cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t *font_subsets, _cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t *font_subsets,
cairo_scaled_font_subset_callback_func_t font_subset_callback, cairo_scaled_font_subset_callback_func_t font_subset_callback,
void *closure) void *closure)
@ -662,3 +697,149 @@ _cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t *fo
closure, closure,
FALSE); FALSE);
} }
static cairo_bool_t
_cairo_string_equal (const void *key_a, const void *key_b)
{
const cairo_string_entry_t *a = key_a;
const cairo_string_entry_t *b = key_b;
if (strcmp (a->string, b->string) == 0)
return TRUE;
else
return FALSE;
}
static void
_cairo_string_init_key (cairo_string_entry_t *key, char *s)
{
unsigned long sum = 0;
unsigned int i;
for (i = 0; i < strlen(s); i++)
sum += s[i];
key->base.hash = sum;
key->string = s;
}
static cairo_string_entry_t *
create_string_entry (char *s)
{
cairo_string_entry_t *entry;
entry = malloc (sizeof (cairo_string_entry_t));
if (entry == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL;
}
_cairo_string_init_key (entry, s);
return entry;
}
cairo_int_status_t
_cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset)
{
const cairo_scaled_font_backend_t *backend;
unsigned int i;
cairo_status_t status;
cairo_hash_table_t *names;
cairo_string_entry_t key, *entry;
char buf[30];
if (subset->to_unicode == NULL) {
return CAIRO_INT_STATUS_UNSUPPORTED;
}
if (_cairo_truetype_create_glyph_to_unicode_map (subset) != CAIRO_STATUS_SUCCESS) {
backend = subset->scaled_font->backend;
if (backend->map_glyphs_to_unicode == NULL) {
return CAIRO_INT_STATUS_UNSUPPORTED;
}
backend->map_glyphs_to_unicode (subset->scaled_font, subset);
}
subset->glyph_names = calloc (subset->num_glyphs, sizeof (char *));
names = _cairo_hash_table_create (_cairo_string_equal);
if (names == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
goto FAIL1;
}
subset->glyph_names[0] = strdup (".notdef");
if (subset->glyph_names[0] == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
goto FAIL1;
}
entry = create_string_entry (subset->glyph_names[0]);
if (entry == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
goto FAIL2;
}
status = _cairo_hash_table_insert (names, &entry->base);
if (status) {
free (entry);
goto CLEANUP_HASH;
}
for (i = 0; i < subset->num_glyphs; i++) {
if (subset->to_unicode[i] <= 0xffff) {
snprintf (buf, sizeof(buf), "uni%04X", (unsigned int)(subset->to_unicode[i]));
_cairo_string_init_key (&key, buf);
if (_cairo_hash_table_lookup (names, &key.base,
(cairo_hash_entry_t **) &entry)) {
snprintf (buf, sizeof(buf), "g%d", i);
}
} else {
snprintf (buf, sizeof(buf), "g%d", i);
}
subset->glyph_names[i] = strdup (buf);
if (subset->glyph_names[i] == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
goto CLEANUP_HASH;
}
entry = create_string_entry (subset->glyph_names[i]);
if (entry == NULL) {
status = CAIRO_STATUS_NO_MEMORY;
goto CLEANUP_HASH;
}
status = _cairo_hash_table_insert (names, &entry->base);
if (status) {
free (entry);
goto CLEANUP_HASH;
}
}
return 0;
CLEANUP_HASH:
while (1) {
entry = _cairo_hash_table_random_entry (names, NULL);
if (entry == NULL)
break;
_cairo_hash_table_remove (names, (cairo_hash_entry_t *) entry);
free (entry);
}
_cairo_hash_table_destroy (names);
if (status == CAIRO_STATUS_SUCCESS)
return status;
FAIL2:
for (i = 0; i < subset->num_glyphs; i++) {
if (subset->glyph_names[i] != NULL)
free (subset->glyph_names[i]);
}
FAIL1:
free (subset->glyph_names);
subset->glyph_names = NULL;
return status;
}

View File

@ -177,10 +177,11 @@ _cairo_scaled_glyph_destroy (void *abstract_glyph)
free (scaled_glyph); free (scaled_glyph);
} }
#define ZOMBIE 0
const cairo_scaled_font_t _cairo_scaled_font_nil = { const cairo_scaled_font_t _cairo_scaled_font_nil = {
{ 0 }, /* hash_entry */ { ZOMBIE }, /* hash_entry */
CAIRO_STATUS_NO_MEMORY, /* status */ CAIRO_STATUS_NO_MEMORY, /* status */
CAIRO_REF_COUNT_INVALID, /* ref_count */ CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
{ 0, 0, 0, NULL }, /* user_data */ { 0, 0, 0, NULL }, /* user_data */
NULL, /* font_face */ NULL, /* font_face */
{ 1., 0., 0., 1., 0, 0}, /* font_matrix */ { 1., 0., 0., 1., 0, 0}, /* font_matrix */
@ -204,27 +205,31 @@ const cairo_scaled_font_t _cairo_scaled_font_nil = {
* @status: a status value indicating an error, (eg. not * @status: a status value indicating an error, (eg. not
* CAIRO_STATUS_SUCCESS) * CAIRO_STATUS_SUCCESS)
* *
* Sets scaled_font->status to @status and calls _cairo_error; * Atomically sets scaled_font->status to @status and calls _cairo_error;
* *
* All assignments of an error status to scaled_font->status should happen * All assignments of an error status to scaled_font->status should happen
* through _cairo_scaled_font_set_error() or else _cairo_error() should be * through _cairo_scaled_font_set_error(). Note that due to the nature of
* called immediately after the assignment. * the atomic operation, it is not safe to call this function on the nil
* objects.
* *
* The purpose of this function is to allow the user to set a * The purpose of this function is to allow the user to set a
* breakpoint in _cairo_error() to generate a stack trace for when the * breakpoint in _cairo_error() to generate a stack trace for when the
* user causes cairo to detect an error. * user causes cairo to detect an error.
*
* Return value: the error status.
**/ **/
void cairo_status_t
_cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font, _cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
cairo_status_t status) cairo_status_t status)
{ {
/* Don't overwrite an existing error. This preserves the first if (status == CAIRO_STATUS_SUCCESS)
* error, which is the most significant. It also avoids attempting return status;
* to write to read-only data (eg. from a nil scaled_font). */
if (scaled_font->status == CAIRO_STATUS_SUCCESS)
scaled_font->status = status;
_cairo_error (status); /* Don't overwrite an existing error. This preserves the first
* error, which is the most significant. */
_cairo_status_set_error (&scaled_font->status, status);
return _cairo_error (status);
} }
/** /**
@ -241,7 +246,7 @@ _cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
cairo_font_type_t cairo_font_type_t
cairo_scaled_font_get_type (cairo_scaled_font_t *scaled_font) cairo_scaled_font_get_type (cairo_scaled_font_t *scaled_font)
{ {
if (scaled_font->ref_count == CAIRO_REF_COUNT_INVALID) if (CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
return CAIRO_FONT_TYPE_TOY; return CAIRO_FONT_TYPE_TOY;
return scaled_font->backend->type; return scaled_font->backend->type;
@ -324,6 +329,7 @@ _cairo_scaled_font_map_lock (void)
cairo_scaled_font_map = NULL; cairo_scaled_font_map = NULL;
CLEANUP_MUTEX_LOCK: CLEANUP_MUTEX_LOCK:
CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex); CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
} }
@ -352,7 +358,7 @@ _cairo_scaled_font_map_destroy (void)
/* We should only get here through the reset_static_data path /* We should only get here through the reset_static_data path
* and there had better not be any active references at that * and there had better not be any active references at that
* point. */ * point. */
assert (scaled_font->ref_count == 0); assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
_cairo_hash_table_remove (font_map->hash_table, _cairo_hash_table_remove (font_map->hash_table,
&scaled_font->hash_entry); &scaled_font->hash_entry);
_cairo_scaled_font_fini (scaled_font); _cairo_scaled_font_fini (scaled_font);
@ -418,6 +424,7 @@ _cairo_scaled_font_init_key (cairo_scaled_font_t *scaled_font,
hash ^= cairo_font_options_hash (&scaled_font->options); hash ^= cairo_font_options_hash (&scaled_font->options);
assert (hash != ZOMBIE);
scaled_font->hash_entry.hash = hash; scaled_font->hash_entry.hash = hash;
} }
@ -481,9 +488,9 @@ _cairo_scaled_font_init (cairo_scaled_font_t *scaled_font,
_cairo_scaled_glyph_destroy, _cairo_scaled_glyph_destroy,
MAX_GLYPHS_CACHED_PER_FONT); MAX_GLYPHS_CACHED_PER_FONT);
if (scaled_font->glyphs == NULL) if (scaled_font->glyphs == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
scaled_font->ref_count = 1; CAIRO_REFERENCE_COUNT_INIT (&scaled_font->ref_count, 1);
_cairo_user_data_array_init (&scaled_font->user_data); _cairo_user_data_array_init (&scaled_font->user_data);
@ -598,6 +605,9 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
if (cairo_font_options_status ((cairo_font_options_t *) options)) if (cairo_font_options_status ((cairo_font_options_t *) options))
return (cairo_scaled_font_t *)&_cairo_scaled_font_nil; return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
if (! _cairo_matrix_is_invertible (font_matrix))
return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
font_map = _cairo_scaled_font_map_lock (); font_map = _cairo_scaled_font_map_lock ();
if (font_map == NULL) if (font_map == NULL)
return (cairo_scaled_font_t *)&_cairo_scaled_font_nil; return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
@ -613,7 +623,7 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
* been found in font_map->holdovers, (which means this caching is * been found in font_map->holdovers, (which means this caching is
* actually working). So now we remove it from the holdovers * actually working). So now we remove it from the holdovers
* array. */ * array. */
if (scaled_font->ref_count == 0) { if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count)) {
int i; int i;
for (i = 0; i < font_map->num_holdovers; i++) for (i = 0; i < font_map->num_holdovers; i++)
@ -635,13 +645,14 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
* than calling into cairo_scaled_font_reference), since we * than calling into cairo_scaled_font_reference), since we
* must modify the reference count while our lock is still * must modify the reference count while our lock is still
* held. */ * held. */
scaled_font->ref_count++; _cairo_reference_count_inc (&scaled_font->ref_count);
_cairo_scaled_font_map_unlock (); _cairo_scaled_font_map_unlock ();
return scaled_font; return scaled_font;
} }
/* the font has been put into an error status - abandon the cache */ /* the font has been put into an error status - abandon the cache */
_cairo_hash_table_remove (font_map->hash_table, &key.hash_entry); _cairo_hash_table_remove (font_map->hash_table, &key.hash_entry);
scaled_font->hash_entry.hash = ZOMBIE;
} }
/* Otherwise create it and insert it into the hash table. */ /* Otherwise create it and insert it into the hash table. */
@ -649,6 +660,7 @@ cairo_scaled_font_create (cairo_font_face_t *font_face,
ctm, options, &scaled_font); ctm, options, &scaled_font);
if (status) { if (status) {
_cairo_scaled_font_map_unlock (); _cairo_scaled_font_map_unlock ();
status = _cairo_font_face_set_error (font_face, status);
return (cairo_scaled_font_t *)&_cairo_scaled_font_nil; return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;
} }
@ -686,16 +698,13 @@ slim_hidden_def (cairo_scaled_font_create);
cairo_scaled_font_t * cairo_scaled_font_t *
cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font) cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font)
{ {
if (scaled_font == NULL || scaled_font->ref_count == CAIRO_REF_COUNT_INVALID) if (scaled_font == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
return scaled_font; return scaled_font;
_cairo_scaled_font_map_lock (); assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
{
assert (scaled_font->ref_count > 0);
scaled_font->ref_count++; _cairo_reference_count_inc (&scaled_font->ref_count);
}
_cairo_scaled_font_map_unlock ();
return scaled_font; return scaled_font;
} }
@ -715,26 +724,27 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
cairo_scaled_font_map_t *font_map; cairo_scaled_font_map_t *font_map;
cairo_scaled_font_t *lru = NULL; cairo_scaled_font_t *lru = NULL;
if (scaled_font == NULL || scaled_font->ref_count == CAIRO_REF_COUNT_INVALID) if (scaled_font == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
return; return;
font_map = _cairo_scaled_font_map_lock (); font_map = _cairo_scaled_font_map_lock ();
{ assert (font_map != NULL);
assert (font_map != NULL);
assert (scaled_font->ref_count > 0); assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
if (--(scaled_font->ref_count) == 0) if (_cairo_reference_count_dec_and_test (&scaled_font->ref_count)) {
{ if (scaled_font->hash_entry.hash != ZOMBIE) {
/* Rather than immediately destroying this object, we put it into /* Rather than immediately destroying this object, we put it into
* the font_map->holdovers array in case it will get used again * the font_map->holdovers array in case it will get used again
* soon. To make room for it, we do actually destroy the * soon (and is why we must hold the lock over the atomic op on
* least-recently-used holdover. * the reference count). To make room for it, we do actually
* destroy the least-recently-used holdover.
*/ */
if (font_map->num_holdovers == CAIRO_SCALED_FONT_MAX_HOLDOVERS) if (font_map->num_holdovers == CAIRO_SCALED_FONT_MAX_HOLDOVERS)
{ {
lru = font_map->holdovers[0]; lru = font_map->holdovers[0];
assert (lru->ref_count == 0); assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&lru->ref_count));
_cairo_hash_table_remove (font_map->hash_table, &lru->hash_entry); _cairo_hash_table_remove (font_map->hash_table, &lru->hash_entry);
@ -746,7 +756,8 @@ cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font)
font_map->holdovers[font_map->num_holdovers] = scaled_font; font_map->holdovers[font_map->num_holdovers] = scaled_font;
font_map->num_holdovers++; font_map->num_holdovers++;
} } else
lru = scaled_font;
} }
_cairo_scaled_font_map_unlock (); _cairo_scaled_font_map_unlock ();
@ -777,10 +788,11 @@ slim_hidden_def (cairo_scaled_font_destroy);
unsigned int unsigned int
cairo_scaled_font_get_reference_count (cairo_scaled_font_t *scaled_font) cairo_scaled_font_get_reference_count (cairo_scaled_font_t *scaled_font)
{ {
if (scaled_font == NULL || scaled_font->ref_count == CAIRO_REF_COUNT_INVALID) if (scaled_font == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
return 0; return 0;
return scaled_font->ref_count; return CAIRO_REFERENCE_COUNT_GET_VALUE (&scaled_font->ref_count);
} }
/** /**
@ -829,8 +841,8 @@ cairo_scaled_font_set_user_data (cairo_scaled_font_t *scaled_font,
void *user_data, void *user_data,
cairo_destroy_func_t destroy) cairo_destroy_func_t destroy)
{ {
if (scaled_font->ref_count == CAIRO_REF_COUNT_INVALID) if (CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return _cairo_user_data_array_set_data (&scaled_font->user_data, return _cairo_user_data_array_set_data (&scaled_font->user_data,
key, user_data, destroy); key, user_data, destroy);
@ -890,7 +902,7 @@ cairo_scaled_font_text_extents (cairo_scaled_font_t *scaled_font,
status = _cairo_scaled_font_text_to_glyphs (scaled_font, 0., 0., utf8, &glyphs, &num_glyphs); status = _cairo_scaled_font_text_to_glyphs (scaled_font, 0., 0., utf8, &glyphs, &num_glyphs);
if (status) { if (status) {
_cairo_scaled_font_set_error (scaled_font, status); status = _cairo_scaled_font_set_error (scaled_font, status);
return; return;
} }
cairo_scaled_font_glyph_extents (scaled_font, glyphs, num_glyphs, extents); cairo_scaled_font_glyph_extents (scaled_font, glyphs, num_glyphs, extents);
@ -927,10 +939,18 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
cairo_bool_t visible = FALSE; cairo_bool_t visible = FALSE;
cairo_scaled_glyph_t *scaled_glyph = NULL; cairo_scaled_glyph_t *scaled_glyph = NULL;
if (scaled_font->status) if (scaled_font->status) {
extents->x_bearing = 0.0;
extents->y_bearing = 0.0;
extents->width = 0.0;
extents->height = 0.0;
extents->x_advance = 0.0;
extents->y_advance = 0.0;
return; return;
}
CAIRO_MUTEX_LOCK (scaled_font->mutex); CAIRO_MUTEX_LOCK (scaled_font->mutex);
_cairo_scaled_font_freeze_cache (scaled_font);
for (i = 0; i < num_glyphs; i++) { for (i = 0; i < num_glyphs; i++) {
double left, top, right, bottom; double left, top, right, bottom;
@ -940,7 +960,7 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
CAIRO_SCALED_GLYPH_INFO_METRICS, CAIRO_SCALED_GLYPH_INFO_METRICS,
&scaled_glyph); &scaled_glyph);
if (status) { if (status) {
_cairo_scaled_font_set_error (scaled_font, status); status = _cairo_scaled_font_set_error (scaled_font, status);
goto UNLOCK; goto UNLOCK;
} }
@ -997,6 +1017,7 @@ cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font,
} }
UNLOCK: UNLOCK:
_cairo_scaled_font_thaw_cache (scaled_font);
CAIRO_MUTEX_UNLOCK (scaled_font->mutex); CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
} }
slim_hidden_def (cairo_scaled_font_glyph_extents); slim_hidden_def (cairo_scaled_font_glyph_extents);
@ -1011,9 +1032,13 @@ _cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
{ {
int i; int i;
uint32_t *ucs4 = NULL; uint32_t *ucs4 = NULL;
cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_status_t status;
cairo_scaled_glyph_t *scaled_glyph; cairo_scaled_glyph_t *scaled_glyph;
status = scaled_font->status;
if (status)
return status;
if (utf8[0] == '\0') { if (utf8[0] == '\0') {
*num_glyphs = 0; *num_glyphs = 0;
*glyphs = NULL; *glyphs = NULL;
@ -1021,6 +1046,7 @@ _cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
} }
CAIRO_MUTEX_LOCK (scaled_font->mutex); CAIRO_MUTEX_LOCK (scaled_font->mutex);
_cairo_scaled_font_freeze_cache (scaled_font);
if (scaled_font->backend->text_to_glyphs) { if (scaled_font->backend->text_to_glyphs) {
status = scaled_font->backend->text_to_glyphs (scaled_font, status = scaled_font->backend->text_to_glyphs (scaled_font,
@ -1038,7 +1064,7 @@ _cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
*glyphs = (cairo_glyph_t *) _cairo_malloc_ab ((*num_glyphs), sizeof (cairo_glyph_t)); *glyphs = (cairo_glyph_t *) _cairo_malloc_ab ((*num_glyphs), sizeof (cairo_glyph_t));
if (*glyphs == NULL) { if (*glyphs == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto DONE; goto DONE;
} }
@ -1063,6 +1089,7 @@ _cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
} }
DONE: DONE:
_cairo_scaled_font_thaw_cache (scaled_font);
CAIRO_MUTEX_UNLOCK (scaled_font->mutex); CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
if (ucs4) if (ucs4)
@ -1098,10 +1125,8 @@ _cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font,
glyphs[i].index, glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_METRICS, CAIRO_SCALED_GLYPH_INFO_METRICS,
&scaled_glyph); &scaled_glyph);
if (status) { if (status)
_cairo_scaled_font_set_error (scaled_font, status); return _cairo_scaled_font_set_error (scaled_font, status);
return status;
}
/* glyph images are snapped to pixel locations */ /* glyph images are snapped to pixel locations */
x = _cairo_lround (glyphs[i].x); x = _cairo_lround (glyphs[i].x);
@ -1145,6 +1170,7 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
{ {
cairo_status_t status; cairo_status_t status;
cairo_surface_t *mask = NULL; cairo_surface_t *mask = NULL;
cairo_surface_pattern_t mask_pattern;
int i; int i;
/* These operators aren't interpreted the same way by the backends; /* These operators aren't interpreted the same way by the backends;
@ -1167,7 +1193,7 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
width, height, width, height,
glyphs, num_glyphs); glyphs, num_glyphs);
if (status != CAIRO_INT_STATUS_UNSUPPORTED) if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status; return _cairo_scaled_font_set_error (scaled_font, status);
} }
/* Font display routine either does not exist or failed. */ /* Font display routine either does not exist or failed. */
@ -1237,27 +1263,23 @@ _cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font,
goto CLEANUP_MASK; goto CLEANUP_MASK;
} }
if (mask != NULL) { _cairo_pattern_init_for_surface (&mask_pattern, mask);
cairo_surface_pattern_t mask_pattern;
_cairo_pattern_init_for_surface (&mask_pattern, mask); status = _cairo_surface_composite (op, pattern, &mask_pattern.base,
surface,
source_x, source_y,
0, 0,
dest_x, dest_y,
width, height);
status = _cairo_surface_composite (op, pattern, &mask_pattern.base, _cairo_pattern_fini (&mask_pattern.base);
surface,
source_x, source_y,
0, 0,
dest_x, dest_y,
width, height);
_cairo_pattern_fini (&mask_pattern.base);
}
CLEANUP_MASK: CLEANUP_MASK:
_cairo_cache_thaw (scaled_font->glyphs); _cairo_cache_thaw (scaled_font->glyphs);
if (mask != NULL) if (mask != NULL)
cairo_surface_destroy (mask); cairo_surface_destroy (mask);
return status; return _cairo_scaled_font_set_error (scaled_font, status);
} }
typedef struct _cairo_scaled_glyph_path_closure { typedef struct _cairo_scaled_glyph_path_closure {
@ -1376,12 +1398,15 @@ _trace_mask_to_path (cairo_image_surface_t *mask,
double xoff, yoff; double xoff, yoff;
if (mask->format == CAIRO_FORMAT_A1) if (mask->format == CAIRO_FORMAT_A1)
a1_mask = mask; a1_mask = (cairo_image_surface_t *) cairo_surface_reference (&mask->base);
else else
a1_mask = _cairo_image_surface_clone (mask, CAIRO_FORMAT_A1); a1_mask = _cairo_image_surface_clone (mask, CAIRO_FORMAT_A1);
if (cairo_surface_status (&a1_mask->base)) status = cairo_surface_status (&a1_mask->base);
return cairo_surface_status (&a1_mask->base); if (status) {
cairo_surface_destroy (&a1_mask->base);
return status;
}
cairo_surface_get_device_offset (&mask->base, &xoff, &yoff); cairo_surface_get_device_offset (&mask->base, &xoff, &yoff);
@ -1394,16 +1419,16 @@ _trace_mask_to_path (cairo_image_surface_t *mask,
status = _add_unit_rectangle_to_path (path, status = _add_unit_rectangle_to_path (path,
x - xoff, y - yoff); x - xoff, y - yoff);
if (status) if (status)
return status; goto BAIL;
} }
} }
} }
} }
if (a1_mask != mask) BAIL:
cairo_surface_destroy (&a1_mask->base); cairo_surface_destroy (&a1_mask->base);
return CAIRO_STATUS_SUCCESS; return status;
} }
cairo_status_t cairo_status_t
@ -1417,10 +1442,12 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
cairo_scaled_glyph_path_closure_t closure; cairo_scaled_glyph_path_closure_t closure;
cairo_path_fixed_t *glyph_path; cairo_path_fixed_t *glyph_path;
if (scaled_font->status) status = scaled_font->status;
return scaled_font->status; if (status)
return status;
closure.path = path; closure.path = path;
_cairo_scaled_font_freeze_cache (scaled_font);
for (i = 0; i < num_glyphs; i++) { for (i = 0; i < num_glyphs; i++) {
cairo_scaled_glyph_t *scaled_glyph; cairo_scaled_glyph_t *scaled_glyph;
@ -1431,7 +1458,7 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
if (status == CAIRO_STATUS_SUCCESS) if (status == CAIRO_STATUS_SUCCESS)
glyph_path = scaled_glyph->path; glyph_path = scaled_glyph->path;
else if (status != CAIRO_INT_STATUS_UNSUPPORTED) else if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status; goto BAIL;
/* If the font is incapable of providing a path, then we'll /* If the font is incapable of providing a path, then we'll
* have to trace our own from a surface. */ * have to trace our own from a surface. */
@ -1441,16 +1468,18 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
CAIRO_SCALED_GLYPH_INFO_SURFACE, CAIRO_SCALED_GLYPH_INFO_SURFACE,
&scaled_glyph); &scaled_glyph);
if (status) if (status)
return status; goto BAIL;
glyph_path = _cairo_path_fixed_create (); glyph_path = _cairo_path_fixed_create ();
if (glyph_path == NULL) if (glyph_path == NULL) {
return CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL;
}
status = _trace_mask_to_path (scaled_glyph->surface, glyph_path); status = _trace_mask_to_path (scaled_glyph->surface, glyph_path);
if (status) { if (status) {
_cairo_path_fixed_destroy (glyph_path); _cairo_path_fixed_destroy (glyph_path);
return status; goto BAIL;
} }
} }
@ -1468,10 +1497,12 @@ _cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
_cairo_path_fixed_destroy (glyph_path); _cairo_path_fixed_destroy (glyph_path);
if (status) if (status)
return status; goto BAIL;
} }
BAIL:
_cairo_scaled_font_thaw_cache (scaled_font);
return CAIRO_STATUS_SUCCESS; return _cairo_scaled_font_set_error (scaled_font, status);
} }
/** /**
@ -1628,7 +1659,7 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
*/ */
scaled_glyph = malloc (sizeof (cairo_scaled_glyph_t)); scaled_glyph = malloc (sizeof (cairo_scaled_glyph_t));
if (scaled_glyph == NULL) { if (scaled_glyph == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP; goto CLEANUP;
} }
@ -1679,7 +1710,7 @@ _cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font,
if (status) { if (status) {
/* It's not an error for the backend to not support the info we want. */ /* It's not an error for the backend to not support the info we want. */
if (status != CAIRO_INT_STATUS_UNSUPPORTED) if (status != CAIRO_INT_STATUS_UNSUPPORTED)
_cairo_scaled_font_set_error (scaled_font, status); status = _cairo_scaled_font_set_error (scaled_font, status);
*scaled_glyph_ret = NULL; *scaled_glyph_ret = NULL;
} else { } else {
*scaled_glyph_ret = scaled_glyph; *scaled_glyph_ret = scaled_glyph;

View File

@ -355,8 +355,11 @@ _cairo_skip_list_insert (cairo_skip_list_t *list, void *data, int unique)
} }
data_and_elt = alloc_node_for_level (list, level); data_and_elt = alloc_node_for_level (list, level);
if (data_and_elt == NULL) if (data_and_elt == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
}
memcpy (data_and_elt, data, list->data_size); memcpy (data_and_elt, data, list->data_size);
elt = (skip_elt_t *) (data_and_elt + list->data_size); elt = (skip_elt_t *) (data_and_elt + list->data_size);

View File

@ -40,45 +40,45 @@ static cairo_status_t
_cairo_spline_grow (cairo_spline_t *spline); _cairo_spline_grow (cairo_spline_t *spline);
static cairo_status_t static cairo_status_t
_cairo_spline_add_point (cairo_spline_t *spline, cairo_point_t *point); _cairo_spline_add_point (cairo_spline_t *spline, const cairo_point_t *point);
static void static void
_lerp_half (cairo_point_t *a, cairo_point_t *b, cairo_point_t *result); _lerp_half (const cairo_point_t *a, const cairo_point_t *b, cairo_point_t *result);
static void static void
_de_casteljau (cairo_spline_t *spline, cairo_spline_t *s1, cairo_spline_t *s2); _de_casteljau (cairo_spline_knots_t *s1, cairo_spline_knots_t *s2);
static double static double
_cairo_spline_error_squared (cairo_spline_t *spline); _cairo_spline_error_squared (const cairo_spline_knots_t *spline);
static cairo_status_t static cairo_status_t
_cairo_spline_decompose_into (cairo_spline_t *spline, double tolerance_squared, cairo_spline_t *result); _cairo_spline_decompose_into (cairo_spline_knots_t *spline, double tolerance_squared, cairo_spline_t *result);
cairo_int_status_t cairo_int_status_t
_cairo_spline_init (cairo_spline_t *spline, _cairo_spline_init (cairo_spline_t *spline,
cairo_point_t *a, cairo_point_t *b, const cairo_point_t *a, const cairo_point_t *b,
cairo_point_t *c, cairo_point_t *d) const cairo_point_t *c, const cairo_point_t *d)
{ {
spline->a = *a; spline->knots.a = *a;
spline->b = *b; spline->knots.b = *b;
spline->c = *c; spline->knots.c = *c;
spline->d = *d; spline->knots.d = *d;
if (a->x != b->x || a->y != b->y) if (a->x != b->x || a->y != b->y)
_cairo_slope_init (&spline->initial_slope, &spline->a, &spline->b); _cairo_slope_init (&spline->initial_slope, &spline->knots.a, &spline->knots.b);
else if (a->x != c->x || a->y != c->y) else if (a->x != c->x || a->y != c->y)
_cairo_slope_init (&spline->initial_slope, &spline->a, &spline->c); _cairo_slope_init (&spline->initial_slope, &spline->knots.a, &spline->knots.c);
else if (a->x != d->x || a->y != d->y) else if (a->x != d->x || a->y != d->y)
_cairo_slope_init (&spline->initial_slope, &spline->a, &spline->d); _cairo_slope_init (&spline->initial_slope, &spline->knots.a, &spline->knots.d);
else else
return CAIRO_INT_STATUS_DEGENERATE; return CAIRO_INT_STATUS_DEGENERATE;
if (c->x != d->x || c->y != d->y) if (c->x != d->x || c->y != d->y)
_cairo_slope_init (&spline->final_slope, &spline->c, &spline->d); _cairo_slope_init (&spline->final_slope, &spline->knots.c, &spline->knots.d);
else if (b->x != d->x || b->y != d->y) else if (b->x != d->x || b->y != d->y)
_cairo_slope_init (&spline->final_slope, &spline->b, &spline->d); _cairo_slope_init (&spline->final_slope, &spline->knots.b, &spline->knots.d);
else else
_cairo_slope_init (&spline->final_slope, &spline->a, &spline->d); _cairo_slope_init (&spline->final_slope, &spline->knots.a, &spline->knots.d);
spline->points = spline->points_embedded; spline->points = spline->points_embedded;
spline->points_size = ARRAY_LENGTH (spline->points_embedded); spline->points_size = ARRAY_LENGTH (spline->points_embedded);
@ -113,12 +113,12 @@ _cairo_spline_grow (cairo_spline_t *spline)
if (new_points) if (new_points)
memcpy (new_points, spline->points, old_size * sizeof (cairo_point_t)); memcpy (new_points, spline->points, old_size * sizeof (cairo_point_t));
} else { } else {
new_points = realloc (spline->points, new_size * sizeof (cairo_point_t)); new_points = _cairo_realloc_ab (spline->points,
new_size, sizeof (cairo_point_t));
} }
if (new_points == NULL) { if (new_points == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
spline->points = new_points; spline->points = new_points;
spline->points_size = new_size; spline->points_size = new_size;
@ -127,7 +127,7 @@ _cairo_spline_grow (cairo_spline_t *spline)
} }
static cairo_status_t static cairo_status_t
_cairo_spline_add_point (cairo_spline_t *spline, cairo_point_t *point) _cairo_spline_add_point (cairo_spline_t *spline, const cairo_point_t *point)
{ {
cairo_status_t status; cairo_status_t status;
cairo_point_t *prev; cairo_point_t *prev;
@ -151,96 +151,92 @@ _cairo_spline_add_point (cairo_spline_t *spline, cairo_point_t *point)
} }
static void static void
_lerp_half (cairo_point_t *a, cairo_point_t *b, cairo_point_t *result) _lerp_half (const cairo_point_t *a, const cairo_point_t *b, cairo_point_t *result)
{ {
result->x = a->x + ((b->x - a->x) >> 1); result->x = a->x + ((b->x - a->x) >> 1);
result->y = a->y + ((b->y - a->y) >> 1); result->y = a->y + ((b->y - a->y) >> 1);
} }
static void static void
_de_casteljau (cairo_spline_t *spline, cairo_spline_t *s1, cairo_spline_t *s2) _de_casteljau (cairo_spline_knots_t *s1, cairo_spline_knots_t *s2)
{ {
cairo_point_t ab, bc, cd; cairo_point_t ab, bc, cd;
cairo_point_t abbc, bccd; cairo_point_t abbc, bccd;
cairo_point_t final; cairo_point_t final;
_lerp_half (&spline->a, &spline->b, &ab); _lerp_half (&s1->a, &s1->b, &ab);
_lerp_half (&spline->b, &spline->c, &bc); _lerp_half (&s1->b, &s1->c, &bc);
_lerp_half (&spline->c, &spline->d, &cd); _lerp_half (&s1->c, &s1->d, &cd);
_lerp_half (&ab, &bc, &abbc); _lerp_half (&ab, &bc, &abbc);
_lerp_half (&bc, &cd, &bccd); _lerp_half (&bc, &cd, &bccd);
_lerp_half (&abbc, &bccd, &final); _lerp_half (&abbc, &bccd, &final);
s1->a = spline->a;
s1->b = ab;
s1->c = abbc;
s1->d = final;
s2->a = final; s2->a = final;
s2->b = bccd; s2->b = bccd;
s2->c = cd; s2->c = cd;
s2->d = spline->d; s2->d = s1->d;
s1->b = ab;
s1->c = abbc;
s1->d = final;
} }
/* Return an upper bound on the error (squared) that could result from
* approximating a spline as a line segment connecting the two endpoints. */
static double static double
_PointDistanceSquaredToPoint (cairo_point_t *a, cairo_point_t *b) _cairo_spline_error_squared (const cairo_spline_knots_t *knots)
{ {
double dx = _cairo_fixed_to_double (b->x - a->x); double bdx, bdy, berr;
double dy = _cairo_fixed_to_double (b->y - a->y); double cdx, cdy, cerr;
return dx*dx + dy*dy; /* Intersection point (px):
} * px = p1 + u(p2 - p1)
* (p - px) (p2 - p1) = 0
* Thus:
* u = ((p - p1) (p2 - p1)) / p2 - p1²;
*/
bdx = _cairo_fixed_to_double (knots->b.x - knots->a.x);
bdy = _cairo_fixed_to_double (knots->b.y - knots->a.y);
static double cdx = _cairo_fixed_to_double (knots->c.x - knots->a.x);
_PointDistanceSquaredToSegment (cairo_point_t *p, cairo_point_t *p1, cairo_point_t *p2) cdy = _cairo_fixed_to_double (knots->c.y - knots->a.y);
{
double u;
double dx, dy;
double pdx, pdy;
cairo_point_t px;
/* intersection point (px): if (knots->a.x != knots->d.x || knots->a.y != knots->d.y) {
double dx, dy, u, v;
px = p1 + u(p2 - p1) dx = _cairo_fixed_to_double (knots->d.x - knots->a.x);
(p - px) . (p2 - p1) = 0 dy = _cairo_fixed_to_double (knots->d.y - knots->a.y);
v = dx * dx + dy * dy;
Thus: u = bdx * dx + bdy * dy;
if (u <= 0) {
/* bdx -= 0;
* bdy -= 0;
*/
} else if (u >= v) {
bdx -= dx;
bdy -= dy;
} else {
bdx -= u/v * dx;
bdy -= u/v * dy;
}
u = ((p - p1) . (p2 - p1)) / (||(p2 - p1)|| ^ 2); u = cdx * dx + cdy * dy;
*/ if (u <= 0) {
/* cdx -= 0;
dx = _cairo_fixed_to_double (p2->x - p1->x); * cdy -= 0;
dy = _cairo_fixed_to_double (p2->y - p1->y); */
} else if (u >= v) {
if (dx == 0 && dy == 0) cdx -= dx;
return _PointDistanceSquaredToPoint (p, p1); cdy -= dy;
} else {
pdx = _cairo_fixed_to_double (p->x - p1->x); cdx -= u/v * dx;
pdy = _cairo_fixed_to_double (p->y - p1->y); cdy -= u/v * dy;
}
u = (pdx * dx + pdy * dy) / (dx*dx + dy*dy); }
if (u <= 0)
return _PointDistanceSquaredToPoint (p, p1);
else if (u >= 1)
return _PointDistanceSquaredToPoint (p, p2);
px.x = p1->x + u * (p2->x - p1->x);
px.y = p1->y + u * (p2->y - p1->y);
return _PointDistanceSquaredToPoint (p, &px);
}
/* Return an upper bound on the error (squared) that could result from approximating
a spline as a line segment connecting the two endpoints */
static double
_cairo_spline_error_squared (cairo_spline_t *spline)
{
double berr, cerr;
berr = _PointDistanceSquaredToSegment (&spline->b, &spline->a, &spline->d);
cerr = _PointDistanceSquaredToSegment (&spline->c, &spline->a, &spline->d);
berr = bdx * bdx + bdy * bdy;
cerr = cdx * cdx + cdy * cdy;
if (berr > cerr) if (berr > cerr)
return berr; return berr;
else else
@ -248,18 +244,17 @@ _cairo_spline_error_squared (cairo_spline_t *spline)
} }
static cairo_status_t static cairo_status_t
_cairo_spline_decompose_into (cairo_spline_t *spline, double tolerance_squared, cairo_spline_t *result) _cairo_spline_decompose_into (cairo_spline_knots_t *s1, double tolerance_squared, cairo_spline_t *result)
{ {
cairo_spline_knots_t s2;
cairo_status_t status; cairo_status_t status;
cairo_spline_t s1, s2;
if (_cairo_spline_error_squared (spline) < tolerance_squared) { if (_cairo_spline_error_squared (s1) < tolerance_squared)
return _cairo_spline_add_point (result, &spline->a); return _cairo_spline_add_point (result, &s1->a);
}
_de_casteljau (spline, &s1, &s2); _de_casteljau (s1, &s2);
status = _cairo_spline_decompose_into (&s1, tolerance_squared, result); status = _cairo_spline_decompose_into (s1, tolerance_squared, result);
if (status) if (status)
return status; return status;
@ -274,15 +269,17 @@ cairo_status_t
_cairo_spline_decompose (cairo_spline_t *spline, double tolerance) _cairo_spline_decompose (cairo_spline_t *spline, double tolerance)
{ {
cairo_status_t status; cairo_status_t status;
cairo_spline_knots_t s1;
/* reset the spline, but keep the buffer */ /* reset the spline, but keep the buffer */
spline->num_points = 0; spline->num_points = 0;
status = _cairo_spline_decompose_into (spline, tolerance * tolerance, spline); s1 = spline->knots;
status = _cairo_spline_decompose_into (&s1, tolerance * tolerance, spline);
if (status) if (status)
return status; return status;
status = _cairo_spline_add_point (spline, &spline->d); status = _cairo_spline_add_point (spline, &spline->knots.d);
if (status) if (status)
return status; return status;

View File

@ -64,7 +64,7 @@ _cairo_stroke_style_init_copy (cairo_stroke_style_t *style,
} else { } else {
style->dash = _cairo_malloc_ab (style->num_dashes, sizeof (double)); style->dash = _cairo_malloc_ab (style->num_dashes, sizeof (double));
if (style->dash == NULL) if (style->dash == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
memcpy (style->dash, other->dash, memcpy (style->dash, other->dash,
style->num_dashes * sizeof (double)); style->num_dashes * sizeof (double));

View File

@ -125,7 +125,7 @@ _create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern,
extents->width, extents->width,
extents->height); extents->height);
if (mask->status) if (mask->status)
return CAIRO_STATUS_NO_MEMORY; return mask->status;
status = (*draw_func) (draw_closure, CAIRO_OPERATOR_ADD, status = (*draw_func) (draw_closure, CAIRO_OPERATOR_ADD,
NULL, mask, NULL, mask,
@ -211,7 +211,7 @@ _clip_and_composite_combine (cairo_clip_t *clip,
extents->width, extents->width,
extents->height); extents->height);
if (intermediate->status) if (intermediate->status)
return CAIRO_STATUS_NO_MEMORY; return intermediate->status;
/* Initialize the intermediate surface from the destination surface /* Initialize the intermediate surface from the destination surface
*/ */
@ -1049,8 +1049,11 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
snapshot = cairo_image_surface_create (image->format, snapshot = cairo_image_surface_create (image->format,
image->width, image->width,
image->height); image->height);
if (cairo_surface_status (snapshot)) if (cairo_surface_status (snapshot)) {
_cairo_surface_release_source_image (surface,
image, &image_extra);
return snapshot; return snapshot;
}
_cairo_pattern_init_for_surface (&pattern.surface, &image->base); _cairo_pattern_init_for_surface (&pattern.surface, &image->base);
@ -1065,14 +1068,14 @@ _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
image->height); image->height);
_cairo_pattern_fini (&pattern.base); _cairo_pattern_fini (&pattern.base);
_cairo_surface_release_source_image (surface,
image, &image_extra);
if (status) { if (status) {
cairo_surface_destroy (snapshot); cairo_surface_destroy (snapshot);
return (cairo_surface_t *) &_cairo_surface_nil; return (cairo_surface_t *) &_cairo_surface_nil;
} }
_cairo_surface_release_source_image (surface,
image, image_extra);
snapshot->device_transform = surface->device_transform; snapshot->device_transform = surface->device_transform;
snapshot->device_transform_inverse = surface->device_transform_inverse; snapshot->device_transform_inverse = surface->device_transform_inverse;
@ -1171,7 +1174,7 @@ _cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface,
if (state.image_rect.x != 0 || state.image_rect.y != 0) { if (state.image_rect.x != 0 || state.image_rect.y != 0) {
offset_rects = _cairo_malloc_ab (num_rects, sizeof (cairo_rectangle_int_t)); offset_rects = _cairo_malloc_ab (num_rects, sizeof (cairo_rectangle_int_t));
if (offset_rects == NULL) { if (offset_rects == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto DONE; goto DONE;
} }
@ -1227,7 +1230,7 @@ _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op,
if (state.image_rect.x != 0 || state.image_rect.y != 0) { if (state.image_rect.x != 0 || state.image_rect.y != 0) {
offset_traps = _cairo_malloc_ab (num_traps, sizeof (cairo_trapezoid_t)); offset_traps = _cairo_malloc_ab (num_traps, sizeof (cairo_trapezoid_t));
if (!offset_traps) { if (!offset_traps) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto DONE; goto DONE;
} }

View File

@ -41,6 +41,7 @@
#include "cairo.h" #include "cairo.h"
#include "cairo-types-private.h" #include "cairo-types-private.h"
#include "cairo-reference-count-private.h"
struct _cairo_surface { struct _cairo_surface {
const cairo_surface_backend_t *backend; const cairo_surface_backend_t *backend;
@ -52,7 +53,7 @@ struct _cairo_surface {
cairo_content_t content; cairo_content_t content;
unsigned int ref_count; cairo_reference_count_t ref_count;
cairo_status_t status; cairo_status_t status;
cairo_bool_t finished; cairo_bool_t finished;
cairo_user_data_array_t user_data; cairo_user_data_array_t user_data;

View File

@ -46,7 +46,7 @@ const cairo_surface_t name = { \
&cairo_image_surface_backend, /* backend */ \ &cairo_image_surface_backend, /* backend */ \
CAIRO_SURFACE_TYPE_IMAGE, \ CAIRO_SURFACE_TYPE_IMAGE, \
CAIRO_CONTENT_COLOR, \ CAIRO_CONTENT_COLOR, \
CAIRO_REF_COUNT_INVALID, /* ref_count */ \ CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ \
status, /* status */ \ status, /* status */ \
FALSE, /* finished */ \ FALSE, /* finished */ \
{ 0, /* size */ \ { 0, /* size */ \
@ -94,27 +94,31 @@ _cairo_surface_copy_pattern_for_destination (const cairo_pattern_t *pattern,
* @status: a status value indicating an error, (eg. not * @status: a status value indicating an error, (eg. not
* CAIRO_STATUS_SUCCESS) * CAIRO_STATUS_SUCCESS)
* *
* Sets surface->status to @status and calls _cairo_error; * Atomically sets surface->status to @status and calls _cairo_error;
* *
* All assignments of an error status to surface->status should happen * All assignments of an error status to surface->status should happen
* through _cairo_surface_set_error() or else _cairo_error() should be * through _cairo_surface_set_error(). Note that due to the nature of
* called immediately after the assignment. * the atomic operation, it is not safe to call this function on the
* nil objects.
* *
* The purpose of this function is to allow the user to set a * The purpose of this function is to allow the user to set a
* breakpoint in _cairo_error() to generate a stack trace for when the * breakpoint in _cairo_error() to generate a stack trace for when the
* user causes cairo to detect an error. * user causes cairo to detect an error.
*
* Return value: the error status.
**/ **/
void cairo_status_t
_cairo_surface_set_error (cairo_surface_t *surface, _cairo_surface_set_error (cairo_surface_t *surface,
cairo_status_t status) cairo_status_t status)
{ {
/* Don't overwrite an existing error. This preserves the first if (status == CAIRO_STATUS_SUCCESS || status >= CAIRO_INT_STATUS_UNSUPPORTED)
* error, which is the most significant. It also avoids attempting return status;
* to write to read-only data (eg. from a nil surface). */
if (surface->status == CAIRO_STATUS_SUCCESS)
surface->status = status;
_cairo_error (status); /* Don't overwrite an existing error. This preserves the first
* error, which is the most significant. */
_cairo_status_set_error (&surface->status, status);
return _cairo_error (status);
} }
/** /**
@ -167,7 +171,7 @@ slim_hidden_def(cairo_surface_get_content);
* *
* Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_STATUS_NULL_POINTER, * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_STATUS_NULL_POINTER,
* %CAIRO_STATUS_NO_MEMORY, %CAIRO_STATUS_READ_ERROR, * %CAIRO_STATUS_NO_MEMORY, %CAIRO_STATUS_READ_ERROR,
* %CAIRO_STATUS_INVALID_CONTENT, %CAIRO_STATUS_INVALUE_FORMAT, or * %CAIRO_STATUS_INVALID_CONTENT, %CAIRO_STATUS_INVALID_FORMAT, or
* %CAIRO_STATUS_INVALID_VISUAL. * %CAIRO_STATUS_INVALID_VISUAL.
**/ **/
cairo_status_t cairo_status_t
@ -188,7 +192,7 @@ _cairo_surface_init (cairo_surface_t *surface,
surface->content = content; surface->content = content;
surface->type = backend->type; surface->type = backend->type;
surface->ref_count = 1; CAIRO_REFERENCE_COUNT_INIT (&surface->ref_count, 1);
surface->status = CAIRO_STATUS_SUCCESS; surface->status = CAIRO_STATUS_SUCCESS;
surface->finished = FALSE; surface->finished = FALSE;
@ -288,7 +292,7 @@ cairo_surface_create_similar (cairo_surface_t *other,
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
if (! CAIRO_CONTENT_VALID (content)) { if (! CAIRO_CONTENT_VALID (content)) {
_cairo_error (CAIRO_STATUS_INVALID_CONTENT); _cairo_error_throw (CAIRO_STATUS_INVALID_CONTENT);
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
} }
@ -314,7 +318,7 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other,
surface = _cairo_surface_create_similar_scratch (other, content, surface = _cairo_surface_create_similar_scratch (other, content,
width, height); width, height);
if (surface->status) { if (surface->status) {
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
} }
@ -322,7 +326,7 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other,
source = _cairo_pattern_create_solid (color, content); source = _cairo_pattern_create_solid (color, content);
if (source->status) { if (source->status) {
cairo_surface_destroy (surface); cairo_surface_destroy (surface);
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
} }
} else } else
@ -338,7 +342,7 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other,
if (status) { if (status) {
cairo_surface_destroy (surface); cairo_surface_destroy (surface);
_cairo_error (status); _cairo_error_throw (status);
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
} }
@ -372,12 +376,13 @@ _cairo_surface_get_clip_mode (cairo_surface_t *surface)
cairo_surface_t * cairo_surface_t *
cairo_surface_reference (cairo_surface_t *surface) cairo_surface_reference (cairo_surface_t *surface)
{ {
if (surface == NULL || surface->ref_count == CAIRO_REF_COUNT_INVALID) if (surface == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
return surface; return surface;
assert (surface->ref_count > 0); assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count));
surface->ref_count++; _cairo_reference_count_inc (&surface->ref_count);
return surface; return surface;
} }
@ -394,13 +399,13 @@ slim_hidden_def (cairo_surface_reference);
void void
cairo_surface_destroy (cairo_surface_t *surface) cairo_surface_destroy (cairo_surface_t *surface)
{ {
if (surface == NULL || surface->ref_count == CAIRO_REF_COUNT_INVALID) if (surface == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
return; return;
assert (surface->ref_count > 0); assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count));
surface->ref_count--; if (! _cairo_reference_count_dec_and_test (&surface->ref_count))
if (surface->ref_count)
return; return;
if (! surface->finished) if (! surface->finished)
@ -422,17 +427,18 @@ slim_hidden_def(cairo_surface_destroy);
cairo_status_t cairo_status_t
_cairo_surface_reset (cairo_surface_t *surface) _cairo_surface_reset (cairo_surface_t *surface)
{ {
if (surface == NULL || surface->ref_count == CAIRO_REF_COUNT_INVALID) if (surface == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
assert (surface->ref_count == 1); assert (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->ref_count) == 1);
_cairo_user_data_array_fini (&surface->user_data); _cairo_user_data_array_fini (&surface->user_data);
if (surface->backend->reset != NULL) { if (surface->backend->reset != NULL) {
cairo_status_t status = surface->backend->reset (surface); cairo_status_t status = surface->backend->reset (surface);
if (status) if (status)
return status; return _cairo_surface_set_error (surface, status);
} }
_cairo_surface_init (surface, surface->backend, surface->content); _cairo_surface_init (surface, surface->backend, surface->content);
@ -454,10 +460,11 @@ _cairo_surface_reset (cairo_surface_t *surface)
unsigned int unsigned int
cairo_surface_get_reference_count (cairo_surface_t *surface) cairo_surface_get_reference_count (cairo_surface_t *surface)
{ {
if (surface == NULL || surface->ref_count == CAIRO_REF_COUNT_INVALID) if (surface == NULL ||
CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
return 0; return 0;
return surface->ref_count; return CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->ref_count);
} }
/** /**
@ -486,11 +493,11 @@ cairo_surface_finish (cairo_surface_t *surface)
if (surface == NULL) if (surface == NULL)
return; return;
if (surface->ref_count == CAIRO_REF_COUNT_INVALID) if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
return; return;
if (surface->finished) { if (surface->finished) {
_cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); status = _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED);
return; return;
} }
@ -502,14 +509,14 @@ cairo_surface_finish (cairo_surface_t *surface)
if (!surface->status && surface->backend->flush) { if (!surface->status && surface->backend->flush) {
status = surface->backend->flush (surface); status = surface->backend->flush (surface);
if (status) { if (status) {
_cairo_surface_set_error (surface, status); status = _cairo_surface_set_error (surface, status);
return; return;
} }
} }
status = surface->backend->finish (surface); status = surface->backend->finish (surface);
if (status) if (status)
_cairo_surface_set_error (surface, status); status = _cairo_surface_set_error (surface, status);
surface->finished = TRUE; surface->finished = TRUE;
} }
@ -557,8 +564,8 @@ cairo_surface_set_user_data (cairo_surface_t *surface,
void *user_data, void *user_data,
cairo_destroy_func_t destroy) cairo_destroy_func_t destroy)
{ {
if (surface->ref_count == CAIRO_REF_COUNT_INVALID) if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return _cairo_user_data_array_set_data (&surface->user_data, return _cairo_user_data_array_set_data (&surface->user_data,
key, user_data, destroy); key, user_data, destroy);
@ -583,6 +590,19 @@ void
_cairo_surface_set_font_options (cairo_surface_t *surface, _cairo_surface_set_font_options (cairo_surface_t *surface,
cairo_font_options_t *options) cairo_font_options_t *options)
{ {
cairo_status_t status;
assert (! surface->is_snapshot);
if (surface->status)
return;
if (surface->finished) {
status = _cairo_surface_set_error (surface,
CAIRO_STATUS_SURFACE_FINISHED);
return;
}
if (options) { if (options) {
surface->has_font_options = TRUE; surface->has_font_options = TRUE;
_cairo_font_options_init_copy (&surface->font_options, options); _cairo_font_options_init_copy (&surface->font_options, options);
@ -638,21 +658,20 @@ slim_hidden_def (cairo_surface_get_font_options);
void void
cairo_surface_flush (cairo_surface_t *surface) cairo_surface_flush (cairo_surface_t *surface)
{ {
cairo_status_t status;
if (surface->status) if (surface->status)
return; return;
if (surface->finished) { if (surface->finished) {
_cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); status = _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED);
return; return;
} }
if (surface->backend->flush) { if (surface->backend->flush) {
cairo_status_t status;
status = surface->backend->flush (surface); status = surface->backend->flush (surface);
if (status) if (status)
_cairo_surface_set_error (surface, status); status = _cairo_surface_set_error (surface, status);
} }
} }
@ -695,13 +714,15 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
int width, int width,
int height) int height)
{ {
cairo_status_t status;
assert (! surface->is_snapshot); assert (! surface->is_snapshot);
if (surface->status) if (surface->status)
return; return;
if (surface->finished) { if (surface->finished) {
_cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); status = _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED);
return; return;
} }
@ -713,8 +734,6 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
surface->current_clip_serial = -1; surface->current_clip_serial = -1;
if (surface->backend->mark_dirty_rectangle) { if (surface->backend->mark_dirty_rectangle) {
cairo_status_t status;
/* XXX: FRAGILE: We're ignoring the scaling component of /* XXX: FRAGILE: We're ignoring the scaling component of
* device_transform here. I don't know what the right thing to * device_transform here. I don't know what the right thing to
* do would actually be if there were some scaling here, but * do would actually be if there were some scaling here, but
@ -726,7 +745,7 @@ cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface,
width, height); width, height);
if (status) if (status)
_cairo_surface_set_error (surface, status); status = _cairo_surface_set_error (surface, status);
} }
} }
slim_hidden_def (cairo_surface_mark_dirty_rectangle); slim_hidden_def (cairo_surface_mark_dirty_rectangle);
@ -756,13 +775,15 @@ _cairo_surface_set_device_scale (cairo_surface_t *surface,
double sx, double sx,
double sy) double sy)
{ {
cairo_status_t status;
assert (! surface->is_snapshot); assert (! surface->is_snapshot);
if (surface->status) if (surface->status)
return; return;
if (surface->finished) { if (surface->finished) {
_cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); status = _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED);
return; return;
} }
@ -796,13 +817,15 @@ cairo_surface_set_device_offset (cairo_surface_t *surface,
double x_offset, double x_offset,
double y_offset) double y_offset)
{ {
cairo_status_t status;
assert (! surface->is_snapshot); assert (! surface->is_snapshot);
if (surface->status) if (surface->status)
return; return;
if (surface->finished) { if (surface->finished) {
_cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); status = _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED);
return; return;
} }
@ -872,6 +895,18 @@ cairo_surface_set_fallback_resolution (cairo_surface_t *surface,
double x_pixels_per_inch, double x_pixels_per_inch,
double y_pixels_per_inch) double y_pixels_per_inch)
{ {
cairo_status_t status;
assert (! surface->is_snapshot);
if (surface->status)
return;
if (surface->finished) {
status = _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED);
return;
}
surface->x_fallback_resolution = x_pixels_per_inch; surface->x_fallback_resolution = x_pixels_per_inch;
surface->y_fallback_resolution = y_pixels_per_inch; surface->y_fallback_resolution = y_pixels_per_inch;
} }
@ -907,8 +942,9 @@ _cairo_surface_acquire_source_image (cairo_surface_t *surface,
{ {
assert (!surface->finished); assert (!surface->finished);
return surface->backend->acquire_source_image (surface, return _cairo_surface_set_error (surface,
image_out, image_extra); surface->backend->acquire_source_image (surface,
image_out, image_extra));
} }
/** /**
@ -969,9 +1005,12 @@ _cairo_surface_acquire_dest_image (cairo_surface_t *surface,
{ {
assert (!surface->finished); assert (!surface->finished);
return surface->backend->acquire_dest_image (surface, return _cairo_surface_set_error (surface,
interest_rect, surface->backend->acquire_dest_image (surface,
image_out, image_rect, image_extra); interest_rect,
image_out,
image_rect,
image_extra));
} }
/** /**
@ -1034,7 +1073,7 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
void *image_extra; void *image_extra;
if (surface->finished) if (surface->finished)
return CAIRO_STATUS_SURFACE_FINISHED; return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
if (surface->backend->clone_similar) { if (surface->backend->clone_similar) {
status = surface->backend->clone_similar (surface, src, src_x, src_y, status = surface->backend->clone_similar (surface, src, src_x, src_y,
@ -1162,7 +1201,7 @@ _cairo_surface_composite (cairo_operator_t op,
return dst->status; return dst->status;
if (dst->finished) if (dst->finished)
return CAIRO_STATUS_SURFACE_FINISHED; return _cairo_surface_set_error (dst, CAIRO_STATUS_SURFACE_FINISHED);
if (dst->backend->composite) { if (dst->backend->composite) {
status = dst->backend->composite (op, status = dst->backend->composite (op,
@ -1172,15 +1211,16 @@ _cairo_surface_composite (cairo_operator_t op,
dst_x, dst_y, dst_x, dst_y,
width, height); width, height);
if (status != CAIRO_INT_STATUS_UNSUPPORTED) if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status; return _cairo_surface_set_error (dst, status);
} }
return _cairo_surface_fallback_composite (op, return _cairo_surface_set_error (dst,
_cairo_surface_fallback_composite (op,
src, mask, dst, src, mask, dst,
src_x, src_y, src_x, src_y,
mask_x, mask_y, mask_x, mask_y,
dst_x, dst_y, dst_x, dst_y,
width, height); width, height));
} }
/** /**
@ -1215,7 +1255,7 @@ _cairo_surface_fill_rectangle (cairo_surface_t *surface,
return surface->status; return surface->status;
if (surface->finished) if (surface->finished)
return CAIRO_STATUS_SURFACE_FINISHED; return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED);
rect.x = x; rect.x = x;
rect.y = y; rect.y = y;
@ -1245,46 +1285,54 @@ _cairo_surface_fill_region (cairo_surface_t *surface,
cairo_region_t *region) cairo_region_t *region)
{ {
int num_boxes; int num_boxes;
cairo_box_int_t *boxes; cairo_box_int_t *boxes = NULL;
cairo_rectangle_int_t stack_rects[CAIRO_STACK_BUFFER_SIZE / sizeof (cairo_rectangle_int_t)]; cairo_rectangle_int_t stack_rects[CAIRO_STACK_BUFFER_SIZE / sizeof (cairo_rectangle_int_t)];
cairo_rectangle_int_t *rects; cairo_rectangle_int_t *rects = stack_rects;
cairo_status_t status; cairo_status_t status;
int i; int i;
assert (! surface->is_snapshot); assert (! surface->is_snapshot);
status = _cairo_region_get_boxes (region, &num_boxes, &boxes); num_boxes = _cairo_region_num_boxes (region);
if (status)
return status;
if (num_boxes == 0) if (num_boxes == 0)
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
rects = stack_rects; /* handle the common case of a single box without allocation */
if (num_boxes > ARRAY_LENGTH (stack_rects)) { if (num_boxes > 1) {
rects = _cairo_malloc_ab (num_boxes, sizeof (cairo_rectangle_int_t)); status = _cairo_region_get_boxes (region, &num_boxes, &boxes);
if (!rects) { if (status)
_cairo_region_boxes_fini (region, boxes); return status;
return CAIRO_STATUS_NO_MEMORY;
}
}
for (i = 0; i < num_boxes; i++) { if (num_boxes > ARRAY_LENGTH (stack_rects)) {
rects[i].x = boxes[i].p1.x; rects = _cairo_malloc_ab (num_boxes,
rects[i].y = boxes[i].p1.y; sizeof (cairo_rectangle_int_t));
rects[i].width = boxes[i].p2.x - boxes[i].p1.x; if (!rects) {
rects[i].height = boxes[i].p2.y - boxes[i].p1.y; _cairo_region_boxes_fini (region, boxes);
} return _cairo_surface_set_error (surface,
CAIRO_STATUS_NO_MEMORY);
}
}
for (i = 0; i < num_boxes; i++) {
rects[i].x = boxes[i].p1.x;
rects[i].y = boxes[i].p1.y;
rects[i].width = boxes[i].p2.x - boxes[i].p1.x;
rects[i].height = boxes[i].p2.y - boxes[i].p1.y;
}
} else
_cairo_region_get_extents (region, &rects[0]);
status = _cairo_surface_fill_rectangles (surface, op, status = _cairo_surface_fill_rectangles (surface, op,
color, rects, num_boxes); color, rects, num_boxes);
_cairo_region_boxes_fini (region, boxes); if (boxes != NULL)
_cairo_region_boxes_fini (region, boxes);
if (rects != stack_rects) if (rects != stack_rects)
free (rects); free (rects);
return status; return _cairo_surface_set_error (surface, status);
} }
/** /**
@ -1318,7 +1366,7 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface,
return surface->status; return surface->status;
if (surface->finished) if (surface->finished)
return CAIRO_STATUS_SURFACE_FINISHED; return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED);
if (num_rects == 0) if (num_rects == 0)
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
@ -1327,11 +1375,12 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface,
status = surface->backend->fill_rectangles (surface, op, color, status = surface->backend->fill_rectangles (surface, op, color,
rects, num_rects); rects, num_rects);
if (status != CAIRO_INT_STATUS_UNSUPPORTED) if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status; return _cairo_surface_set_error (surface, status);
} }
return _cairo_surface_fallback_fill_rectangles (surface, op, color, return _cairo_surface_set_error (surface,
rects, num_rects); _cairo_surface_fallback_fill_rectangles (surface, op, color,
rects, num_rects));
} }
cairo_status_t cairo_status_t
@ -1346,7 +1395,7 @@ _cairo_surface_paint (cairo_surface_t *surface,
status = _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base); status = _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
if (status) if (status)
return status; return _cairo_surface_set_error (surface, status);
if (surface->backend->paint) { if (surface->backend->paint) {
status = surface->backend->paint (surface, op, &dev_source.base); status = surface->backend->paint (surface, op, &dev_source.base);
@ -1359,7 +1408,7 @@ _cairo_surface_paint (cairo_surface_t *surface,
FINISH: FINISH:
_cairo_pattern_fini (&dev_source.base); _cairo_pattern_fini (&dev_source.base);
return status; return _cairo_surface_set_error (surface, status);
} }
cairo_status_t cairo_status_t
@ -1377,6 +1426,7 @@ _cairo_surface_mask (cairo_surface_t *surface,
status = _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base); status = _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
if (status) if (status)
goto FINISH; goto FINISH;
status = _cairo_surface_copy_pattern_for_destination (mask, surface, &dev_mask.base); status = _cairo_surface_copy_pattern_for_destination (mask, surface, &dev_mask.base);
if (status) if (status)
goto CLEANUP_SOURCE; goto CLEANUP_SOURCE;
@ -1395,7 +1445,7 @@ _cairo_surface_mask (cairo_surface_t *surface,
_cairo_pattern_fini (&dev_source.base); _cairo_pattern_fini (&dev_source.base);
FINISH: FINISH:
return status; return _cairo_surface_set_error (surface, status);
} }
cairo_status_t cairo_status_t
@ -1424,12 +1474,12 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface,
status = _cairo_surface_copy_pattern_for_destination (stroke_source, surface, &dev_stroke_source.base); status = _cairo_surface_copy_pattern_for_destination (stroke_source, surface, &dev_stroke_source.base);
if (status) if (status)
return status; return _cairo_surface_set_error (surface, status);
status = _cairo_surface_copy_pattern_for_destination (fill_source, surface, &dev_fill_source.base); status = _cairo_surface_copy_pattern_for_destination (fill_source, surface, &dev_fill_source.base);
if (status) { if (status) {
_cairo_pattern_fini (&dev_stroke_source.base); _cairo_pattern_fini (&dev_stroke_source.base);
return status; return _cairo_surface_set_error (surface, status);
} }
status = surface->backend->fill_stroke (surface, fill_op, &dev_fill_source.base, status = surface->backend->fill_stroke (surface, fill_op, &dev_fill_source.base,
@ -1442,19 +1492,21 @@ _cairo_surface_fill_stroke (cairo_surface_t *surface,
_cairo_pattern_fini (&dev_fill_source.base); _cairo_pattern_fini (&dev_fill_source.base);
if (status != CAIRO_INT_STATUS_UNSUPPORTED) if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status; return _cairo_surface_set_error (surface, status);
} }
status = _cairo_surface_fill (surface, fill_op, fill_source, path, status = _cairo_surface_fill (surface, fill_op, fill_source, path,
fill_rule, fill_tolerance, fill_antialias); fill_rule, fill_tolerance, fill_antialias);
if (status) if (status)
return status; return _cairo_surface_set_error (surface, status);
status = _cairo_surface_stroke (surface, stroke_op, stroke_source, path, status = _cairo_surface_stroke (surface, stroke_op, stroke_source, path,
stroke_style, stroke_ctm, stroke_ctm_inverse, stroke_style, stroke_ctm, stroke_ctm_inverse,
stroke_tolerance, stroke_antialias); stroke_tolerance, stroke_antialias);
if (status)
return _cairo_surface_set_error (surface, status);
return status; return CAIRO_STATUS_SUCCESS;
} }
cairo_status_t cairo_status_t
@ -1479,7 +1531,7 @@ _cairo_surface_stroke (cairo_surface_t *surface,
status = _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base); status = _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
if (status) if (status)
return status; return _cairo_surface_set_error (surface, status);
if (surface->backend->stroke) { if (surface->backend->stroke) {
status = surface->backend->stroke (surface, op, &dev_source.base, status = surface->backend->stroke (surface, op, &dev_source.base,
@ -1501,7 +1553,7 @@ _cairo_surface_stroke (cairo_surface_t *surface,
_cairo_path_fixed_fini (&real_dev_path); _cairo_path_fixed_fini (&real_dev_path);
_cairo_pattern_fini (&dev_source.base); _cairo_pattern_fini (&dev_source.base);
return status; return _cairo_surface_set_error (surface, status);
} }
cairo_status_t cairo_status_t
@ -1520,7 +1572,7 @@ _cairo_surface_fill (cairo_surface_t *surface,
status = _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base); status = _cairo_surface_copy_pattern_for_destination (source, surface, &dev_source.base);
if (status) if (status)
return status; return _cairo_surface_set_error (surface, status);
if (surface->backend->fill) { if (surface->backend->fill) {
status = surface->backend->fill (surface, op, &dev_source.base, status = surface->backend->fill (surface, op, &dev_source.base,
@ -1538,7 +1590,7 @@ _cairo_surface_fill (cairo_surface_t *surface,
FINISH: FINISH:
_cairo_pattern_fini (&dev_source.base); _cairo_pattern_fini (&dev_source.base);
return status; return _cairo_surface_set_error (surface, status);
} }
cairo_status_t cairo_status_t
@ -1568,7 +1620,7 @@ _cairo_surface_composite_trapezoids (cairo_operator_t op,
return dst->status; return dst->status;
if (dst->finished) if (dst->finished)
return CAIRO_STATUS_SURFACE_FINISHED; return _cairo_surface_set_error (dst, CAIRO_STATUS_SURFACE_FINISHED);
if (dst->backend->composite_trapezoids) { if (dst->backend->composite_trapezoids) {
status = dst->backend->composite_trapezoids (op, status = dst->backend->composite_trapezoids (op,
@ -1579,15 +1631,16 @@ _cairo_surface_composite_trapezoids (cairo_operator_t op,
width, height, width, height,
traps, num_traps); traps, num_traps);
if (status != CAIRO_INT_STATUS_UNSUPPORTED) if (status != CAIRO_INT_STATUS_UNSUPPORTED)
return status; return _cairo_surface_set_error (dst, status);
} }
return _cairo_surface_fallback_composite_trapezoids (op, pattern, dst, return _cairo_surface_set_error (dst,
_cairo_surface_fallback_composite_trapezoids (op, pattern, dst,
antialias, antialias,
src_x, src_y, src_x, src_y,
dst_x, dst_y, dst_x, dst_y,
width, height, width, height,
traps, num_traps); traps, num_traps));
} }
/** /**
@ -1610,13 +1663,14 @@ cairo_surface_copy_page (cairo_surface_t *surface)
return surface->status; return surface->status;
if (surface->finished) if (surface->finished)
return CAIRO_STATUS_SURFACE_FINISHED; return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED);
/* It's fine if some backends don't implement copy_page */ /* It's fine if some backends don't implement copy_page */
if (surface->backend->copy_page == NULL) if (surface->backend->copy_page == NULL)
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
return surface->backend->copy_page (surface); return _cairo_surface_set_error (surface,
surface->backend->copy_page (surface));
} }
slim_hidden_def (cairo_surface_copy_page); slim_hidden_def (cairo_surface_copy_page);
@ -1639,13 +1693,14 @@ cairo_surface_show_page (cairo_surface_t *surface)
return surface->status; return surface->status;
if (surface->finished) if (surface->finished)
return CAIRO_STATUS_SURFACE_FINISHED; return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED);
/* It's fine if some backends don't implement show_page */ /* It's fine if some backends don't implement show_page */
if (surface->backend->show_page == NULL) if (surface->backend->show_page == NULL)
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
return surface->backend->show_page (surface); return _cairo_surface_set_error (surface,
surface->backend->show_page (surface));
} }
slim_hidden_def (cairo_surface_show_page); slim_hidden_def (cairo_surface_show_page);
@ -1705,7 +1760,7 @@ _cairo_surface_reset_clip (cairo_surface_t *surface)
return surface->status; return surface->status;
if (surface->finished) if (surface->finished)
return CAIRO_STATUS_SURFACE_FINISHED; return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED);
surface->current_clip_serial = 0; surface->current_clip_serial = 0;
@ -1716,13 +1771,13 @@ _cairo_surface_reset_clip (cairo_surface_t *surface)
0, 0,
CAIRO_ANTIALIAS_DEFAULT); CAIRO_ANTIALIAS_DEFAULT);
if (status) if (status)
return status; return _cairo_surface_set_error (surface, status);
} }
if (surface->backend->set_clip_region != NULL) { if (surface->backend->set_clip_region != NULL) {
status = surface->backend->set_clip_region (surface, NULL); status = surface->backend->set_clip_region (surface, NULL);
if (status) if (status)
return status; return _cairo_surface_set_error (surface, status);
} }
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
@ -1749,7 +1804,7 @@ _cairo_surface_set_clip_region (cairo_surface_t *surface,
return surface->status; return surface->status;
if (surface->finished) if (surface->finished)
return CAIRO_STATUS_SURFACE_FINISHED; return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED);
assert (surface->backend->set_clip_region != NULL); assert (surface->backend->set_clip_region != NULL);
@ -1757,7 +1812,7 @@ _cairo_surface_set_clip_region (cairo_surface_t *surface,
status = surface->backend->set_clip_region (surface, region); status = surface->backend->set_clip_region (surface, region);
return status; return _cairo_surface_set_error (surface, status);
} }
cairo_int_status_t cairo_int_status_t
@ -1774,7 +1829,7 @@ _cairo_surface_intersect_clip_path (cairo_surface_t *surface,
return surface->status; return surface->status;
if (surface->finished) if (surface->finished)
return CAIRO_STATUS_SURFACE_FINISHED; return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED);
assert (surface->backend->intersect_clip_path != NULL); assert (surface->backend->intersect_clip_path != NULL);
@ -1784,7 +1839,7 @@ _cairo_surface_intersect_clip_path (cairo_surface_t *surface,
tolerance, tolerance,
antialias); antialias);
return status; return _cairo_surface_set_error (surface, status);
} }
static cairo_status_t static cairo_status_t
@ -1827,7 +1882,7 @@ _cairo_surface_set_clip_path (cairo_surface_t *surface,
return surface->status; return surface->status;
if (surface->finished) if (surface->finished)
return CAIRO_STATUS_SURFACE_FINISHED; return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED);
assert (surface->backend->intersect_clip_path != NULL); assert (surface->backend->intersect_clip_path != NULL);
@ -1837,30 +1892,59 @@ _cairo_surface_set_clip_path (cairo_surface_t *surface,
0, 0,
CAIRO_ANTIALIAS_DEFAULT); CAIRO_ANTIALIAS_DEFAULT);
if (status) if (status)
return status; return _cairo_surface_set_error (surface, status);
status = _cairo_surface_set_clip_path_recursive (surface, clip_path); status = _cairo_surface_set_clip_path_recursive (surface, clip_path);
if (status) if (status)
return status; return _cairo_surface_set_error (surface, status);
surface->current_clip_serial = serial; surface->current_clip_serial = serial;
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
/**
* _cairo_surface_set_empty_clip_path:
* @surface: the #cairo_surface_t to set the clip on
* @serial: the clip serial number associated with the clip path
*
* Create an empty clip path, one that represents the entire surface clipped
* out, and assigns the given clipping serial to the surface.
**/
static cairo_status_t
_cairo_surface_set_empty_clip_path (cairo_surface_t *surface,
unsigned int serial)
{
cairo_path_fixed_t path;
cairo_status_t status;
_cairo_path_fixed_init (&path);
status = surface->backend->intersect_clip_path (surface,
&path,
CAIRO_FILL_RULE_WINDING,
0,
CAIRO_ANTIALIAS_DEFAULT);
if (status == CAIRO_STATUS_SUCCESS)
surface->current_clip_serial = serial;
_cairo_path_fixed_fini (&path);
return _cairo_surface_set_error (surface, status);
}
cairo_status_t cairo_status_t
_cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip) _cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip)
{ {
unsigned int serial = 0; unsigned int serial = 0;
if (!surface)
return CAIRO_STATUS_NULL_POINTER;
if (surface->status) if (surface->status)
return surface->status; return surface->status;
if (surface->finished) if (surface->finished)
return CAIRO_STATUS_SURFACE_FINISHED; return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED);
if (clip) { if (clip) {
serial = clip->serial; serial = clip->serial;
@ -1874,15 +1958,26 @@ _cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip)
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
if (clip) { if (clip) {
if (clip->path) if (clip->all_clipped) {
return _cairo_surface_set_clip_path (surface, if (surface->backend->intersect_clip_path != NULL)
clip->path, return _cairo_surface_set_empty_clip_path (surface,
clip->serial); clip->serial);
if (clip->has_region) if (surface->backend->set_clip_region != NULL)
return _cairo_surface_set_clip_region (surface, return _cairo_surface_set_clip_region (surface,
&clip->region, &clip->region,
clip->serial); clip->serial);
} else {
if (clip->path)
return _cairo_surface_set_clip_path (surface,
clip->path,
clip->serial);
if (clip->has_region)
return _cairo_surface_set_clip_region (surface,
&clip->region,
clip->serial);
}
} }
return _cairo_surface_reset_clip (surface); return _cairo_surface_reset_clip (surface);
@ -1920,9 +2015,10 @@ _cairo_surface_get_extents (cairo_surface_t *surface,
return surface->status; return surface->status;
if (surface->finished) if (surface->finished)
return CAIRO_STATUS_SURFACE_FINISHED; return _cairo_surface_set_error (surface,CAIRO_STATUS_SURFACE_FINISHED);
return surface->backend->get_extents (surface, rectangle); return _cairo_surface_set_error (surface,
surface->backend->get_extents (surface, rectangle));
} }
/* Note: the backends may modify the contents of the glyph array as long as /* Note: the backends may modify the contents of the glyph array as long as
@ -1955,7 +2051,7 @@ _cairo_surface_show_glyphs (cairo_surface_t *surface,
surface, surface,
&dev_source.base); &dev_source.base);
if (status) if (status)
return status; return _cairo_surface_set_error (surface, status);
cairo_scaled_font_get_font_matrix (scaled_font, &font_matrix); cairo_scaled_font_get_font_matrix (scaled_font, &font_matrix);
@ -1979,7 +2075,7 @@ _cairo_surface_show_glyphs (cairo_surface_t *surface,
status = cairo_scaled_font_status (dev_scaled_font); status = cairo_scaled_font_status (dev_scaled_font);
if (status) { if (status) {
_cairo_pattern_fini (&dev_source.base); _cairo_pattern_fini (&dev_source.base);
return status; return _cairo_surface_set_error (surface, status);
} }
CAIRO_MUTEX_LOCK (dev_scaled_font->mutex); CAIRO_MUTEX_LOCK (dev_scaled_font->mutex);
@ -2003,7 +2099,7 @@ _cairo_surface_show_glyphs (cairo_surface_t *surface,
_cairo_pattern_fini (&dev_source.base); _cairo_pattern_fini (&dev_source.base);
return status; return _cairo_surface_set_error (surface, status);
} }
/* XXX: Previously, we had a function named _cairo_surface_show_glyphs /* XXX: Previously, we had a function named _cairo_surface_show_glyphs
@ -2033,7 +2129,7 @@ _cairo_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
return dst->status; return dst->status;
if (dst->finished) if (dst->finished)
return CAIRO_STATUS_SURFACE_FINISHED; return _cairo_surface_set_error (dst, CAIRO_STATUS_SURFACE_FINISHED);
if (dst->backend->old_show_glyphs) { if (dst->backend->old_show_glyphs) {
status = dst->backend->old_show_glyphs (scaled_font, status = dst->backend->old_show_glyphs (scaled_font,
@ -2045,7 +2141,7 @@ _cairo_surface_old_show_glyphs (cairo_scaled_font_t *scaled_font,
} else } else
status = CAIRO_INT_STATUS_UNSUPPORTED; status = CAIRO_INT_STATUS_UNSUPPORTED;
return status; return _cairo_surface_set_error (dst, status);
} }
static cairo_status_t static cairo_status_t
@ -2092,7 +2188,7 @@ _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t *dst,
if (_cairo_region_subtract (&clear_region, &clear_region, &drawn_region) if (_cairo_region_subtract (&clear_region, &clear_region, &drawn_region)
!= CAIRO_STATUS_SUCCESS) != CAIRO_STATUS_SUCCESS)
{ {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_REGIONS; goto CLEANUP_REGIONS;
} }
@ -2106,7 +2202,7 @@ CLEANUP_REGIONS:
if (has_clear_region) if (has_clear_region)
_cairo_region_fini (&clear_region); _cairo_region_fini (&clear_region);
return status; return _cairo_surface_set_error (dst, status);
} }
/** /**

File diff suppressed because it is too large Load Diff

View File

@ -257,21 +257,17 @@ _cairo_traps_grow (cairo_traps_t *traps)
cairo_trapezoid_t *new_traps; cairo_trapezoid_t *new_traps;
int new_size = 2 * MAX (traps->traps_size, 16); int new_size = 2 * MAX (traps->traps_size, 16);
if (traps->status)
return traps->status;
if (traps->traps == traps->traps_embedded) { if (traps->traps == traps->traps_embedded) {
new_traps = _cairo_malloc_ab (new_size, sizeof (cairo_trapezoid_t)); new_traps = _cairo_malloc_ab (new_size, sizeof (cairo_trapezoid_t));
if (new_traps) if (new_traps)
memcpy (new_traps, traps->traps, sizeof (traps->traps_embedded)); memcpy (new_traps, traps->traps, sizeof (traps->traps_embedded));
} else { } else {
new_traps = realloc (traps->traps, new_size * sizeof (cairo_trapezoid_t)); new_traps = _cairo_realloc_ab (traps->traps,
new_size, sizeof (cairo_trapezoid_t));
} }
if (new_traps == NULL) { if (new_traps == NULL)
traps->status = CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return traps->status;
}
traps->traps = new_traps; traps->traps = new_traps;
traps->traps_size = new_size; traps->traps_size = new_size;
@ -614,7 +610,7 @@ _cairo_traps_extract_region (cairo_traps_t *traps,
boxes = _cairo_malloc_ab (traps->num_traps, sizeof(cairo_box_int_t)); boxes = _cairo_malloc_ab (traps->num_traps, sizeof(cairo_box_int_t));
if (boxes == NULL) if (boxes == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
box_count = 0; box_count = 0;

View File

@ -46,10 +46,22 @@ struct subset_glyph {
unsigned long location; unsigned long location;
}; };
typedef struct _cairo_truetype_font { typedef struct _cairo_truetype_font cairo_truetype_font_t;
typedef struct table table_t;
struct table {
unsigned long tag;
cairo_status_t (*write) (cairo_truetype_font_t *font, unsigned long tag);
int pos; /* position in the font directory */
};
struct _cairo_truetype_font {
cairo_scaled_font_subset_t *scaled_font_subset; cairo_scaled_font_subset_t *scaled_font_subset;
table_t truetype_tables[10];
int num_tables;
struct { struct {
char *base_font; char *base_font;
unsigned int num_glyphs; unsigned int num_glyphs;
@ -70,7 +82,7 @@ typedef struct _cairo_truetype_font {
int *parent_to_subset; int *parent_to_subset;
cairo_status_t status; cairo_status_t status;
} cairo_truetype_font_t; };
static int static int
cairo_truetype_font_use_glyph (cairo_truetype_font_t *font, int glyph); cairo_truetype_font_use_glyph (cairo_truetype_font_t *font, int glyph);
@ -78,6 +90,18 @@ cairo_truetype_font_use_glyph (cairo_truetype_font_t *font, int glyph);
#define SFNT_VERSION 0x00010000 #define SFNT_VERSION 0x00010000
#define SFNT_STRING_MAX_LENGTH 65535 #define SFNT_STRING_MAX_LENGTH 65535
static cairo_status_t
_cairo_truetype_font_set_error (cairo_truetype_font_t *font,
cairo_status_t status)
{
if (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED)
return status;
_cairo_status_set_error (&font->status, status);
return _cairo_error (status);
}
static cairo_status_t static cairo_status_t
_cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset, _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
cairo_truetype_font_t **font_return) cairo_truetype_font_t **font_return)
@ -107,42 +131,51 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
*/ */
size = sizeof (tt_head_t); size = sizeof (tt_head_t);
if (backend->load_truetype_table (scaled_font_subset->scaled_font, status = backend->load_truetype_table (scaled_font_subset->scaled_font,
TT_TAG_head, 0, (unsigned char *) &head, TT_TAG_head, 0,
&size) != CAIRO_STATUS_SUCCESS) (unsigned char *) &head,
return CAIRO_INT_STATUS_UNSUPPORTED; &size);
if (status)
return status;
size = sizeof (tt_maxp_t); size = sizeof (tt_maxp_t);
if (backend->load_truetype_table (scaled_font_subset->scaled_font, status = backend->load_truetype_table (scaled_font_subset->scaled_font,
TT_TAG_maxp, 0, (unsigned char *) &maxp, TT_TAG_maxp, 0,
&size) != CAIRO_STATUS_SUCCESS) (unsigned char *) &maxp,
return CAIRO_INT_STATUS_UNSUPPORTED; &size);
if (status)
return status;
size = sizeof (tt_hhea_t); size = sizeof (tt_hhea_t);
if (backend->load_truetype_table (scaled_font_subset->scaled_font, status = backend->load_truetype_table (scaled_font_subset->scaled_font,
TT_TAG_hhea, 0, (unsigned char *) &hhea, TT_TAG_hhea, 0,
&size) != CAIRO_STATUS_SUCCESS) (unsigned char *) &hhea,
return CAIRO_INT_STATUS_UNSUPPORTED; &size);
if (status)
return status;
size = 0; size = 0;
if (backend->load_truetype_table (scaled_font_subset->scaled_font, status = backend->load_truetype_table (scaled_font_subset->scaled_font,
TT_TAG_name, 0, NULL, TT_TAG_name, 0,
&size) != CAIRO_STATUS_SUCCESS) NULL,
return CAIRO_INT_STATUS_UNSUPPORTED; &size);
if (status)
return status;
name = malloc(size); name = malloc(size);
if (name == NULL) if (name == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = backend->load_truetype_table (scaled_font_subset->scaled_font, status = backend->load_truetype_table (scaled_font_subset->scaled_font,
TT_TAG_name, 0, (unsigned char *) name, TT_TAG_name, 0,
(unsigned char *) name,
&size); &size);
if (status) if (status)
goto fail0; goto fail0;
font = malloc (sizeof (cairo_truetype_font_t)); font = malloc (sizeof (cairo_truetype_font_t));
if (font == NULL) { if (font == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail0; goto fail0;
} }
@ -159,13 +192,13 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
font->glyphs = calloc (font->num_glyphs_in_face + 1, sizeof (subset_glyph_t)); font->glyphs = calloc (font->num_glyphs_in_face + 1, sizeof (subset_glyph_t));
if (font->glyphs == NULL) { if (font->glyphs == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail1; goto fail1;
} }
font->parent_to_subset = calloc (font->num_glyphs_in_face, sizeof (int)); font->parent_to_subset = calloc (font->num_glyphs_in_face, sizeof (int));
if (font->parent_to_subset == NULL) { if (font->parent_to_subset == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2; goto fail2;
} }
@ -209,7 +242,7 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
if (font->base.base_font == NULL) { if (font->base.base_font == NULL) {
font->base.base_font = malloc (30); font->base.base_font = malloc (30);
if (font->base.base_font == NULL) { if (font->base.base_font == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3; goto fail3;
} }
@ -227,7 +260,7 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
font->base.widths = calloc (font->num_glyphs_in_face, sizeof (int)); font->base.widths = calloc (font->num_glyphs_in_face, sizeof (int));
if (font->base.widths == NULL) { if (font->base.widths == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail4; goto fail4;
} }
@ -258,7 +291,7 @@ _cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
if (name) if (name)
free (name); free (name);
return status; return _cairo_error (status);
} }
static void static void
@ -280,9 +313,12 @@ cairo_truetype_font_allocate_write_buffer (cairo_truetype_font_t *font,
{ {
cairo_status_t status; cairo_status_t status;
if (font->status)
return font->status;
status = _cairo_array_allocate (&font->output, length, (void **) buffer); status = _cairo_array_allocate (&font->output, length, (void **) buffer);
if (status) if (status)
return status; return _cairo_truetype_font_set_error (font, status);
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -294,9 +330,12 @@ cairo_truetype_font_write (cairo_truetype_font_t *font,
{ {
cairo_status_t status; cairo_status_t status;
if (font->status)
return font->status;
status = _cairo_array_append_multiple (&font->output, data, length); status = _cairo_array_append_multiple (&font->output, data, length);
if (status) if (status)
return status; return _cairo_truetype_font_set_error (font, status);
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -307,6 +346,9 @@ cairo_truetype_font_write_be16 (cairo_truetype_font_t *font,
{ {
uint16_t be16_value; uint16_t be16_value;
if (font->status)
return;
be16_value = cpu_to_be16 (value); be16_value = cpu_to_be16 (value);
cairo_truetype_font_write (font, &be16_value, sizeof be16_value); cairo_truetype_font_write (font, &be16_value, sizeof be16_value);
} }
@ -317,6 +359,9 @@ cairo_truetype_font_write_be32 (cairo_truetype_font_t *font,
{ {
uint32_t be32_value; uint32_t be32_value;
if (font->status)
return;
be32_value = cpu_to_be32 (value); be32_value = cpu_to_be32 (value);
cairo_truetype_font_write (font, &be32_value, sizeof be32_value); cairo_truetype_font_write (font, &be32_value, sizeof be32_value);
} }
@ -345,12 +390,15 @@ cairo_truetype_font_check_boundary (cairo_truetype_font_t *font,
{ {
cairo_status_t status; cairo_status_t status;
if (font->status)
return font->status;
if (boundary - font->last_offset > SFNT_STRING_MAX_LENGTH) if (boundary - font->last_offset > SFNT_STRING_MAX_LENGTH)
{ {
status = _cairo_array_append (&font->string_offsets, status = _cairo_array_append (&font->string_offsets,
&font->last_boundary); &font->last_boundary);
if (status) if (status)
return status; return _cairo_truetype_font_set_error (font, status);
font->last_offset = font->last_boundary; font->last_offset = font->last_boundary;
} }
@ -416,21 +464,23 @@ cairo_truetype_font_write_generic_table (cairo_truetype_font_t *font,
unsigned char *buffer; unsigned char *buffer;
unsigned long size; unsigned long size;
if (font->status)
return font->status;
size = 0; size = 0;
if (font->backend->load_truetype_table( font->scaled_font_subset->scaled_font, status = font->backend->load_truetype_table(font->scaled_font_subset->scaled_font,
tag, 0, NULL, &size) != CAIRO_STATUS_SUCCESS) { tag, 0, NULL, &size);
font->status = CAIRO_INT_STATUS_UNSUPPORTED; if (status)
return font->status; return _cairo_truetype_font_set_error (font, status);
}
status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer); status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer);
if (status) if (status)
return status; return _cairo_truetype_font_set_error (font, status);
status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
tag, 0, buffer, &size); tag, 0, buffer, &size);
if (status) if (status)
return status; return _cairo_truetype_font_set_error (font, status);
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -446,6 +496,9 @@ cairo_truetype_font_remap_composite_glyph (cairo_truetype_font_t *font,
unsigned short flags; unsigned short flags;
unsigned short index; unsigned short index;
if (font->status)
return;
glyph_data = (tt_glyph_data_t *) buffer; glyph_data = (tt_glyph_data_t *) buffer;
if ((int16_t)be16_to_cpu (glyph_data->num_contours) >= 0) if ((int16_t)be16_to_cpu (glyph_data->num_contours) >= 0)
return; return;
@ -483,30 +536,31 @@ cairo_truetype_font_write_glyf_table (cairo_truetype_font_t *font,
uint16_t *short_offsets; uint16_t *short_offsets;
uint32_t *long_offsets; uint32_t *long_offsets;
} u; } u;
cairo_status_t status;
size = sizeof (tt_head_t);
font->status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_head, 0,
(unsigned char*) &header, &size);
if (font->status) if (font->status)
return font->status; return font->status;
size = sizeof (tt_head_t);
status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_head, 0,
(unsigned char*) &header, &size);
if (status)
return _cairo_truetype_font_set_error (font, status);
if (be16_to_cpu (header.index_to_loc_format) == 0) if (be16_to_cpu (header.index_to_loc_format) == 0)
size = sizeof (int16_t) * (font->num_glyphs_in_face + 1); size = sizeof (int16_t) * (font->num_glyphs_in_face + 1);
else else
size = sizeof (int32_t) * (font->num_glyphs_in_face + 1); size = sizeof (int32_t) * (font->num_glyphs_in_face + 1);
u.bytes = malloc (size); u.bytes = malloc (size);
if (u.bytes == NULL) { if (u.bytes == NULL)
font->status = CAIRO_STATUS_NO_MEMORY; return _cairo_truetype_font_set_error (font, CAIRO_STATUS_NO_MEMORY);
return font->status;
}
if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_loca, 0, u.bytes, &size) != CAIRO_STATUS_SUCCESS) { TT_TAG_loca, 0, u.bytes, &size);
font->status = CAIRO_INT_STATUS_UNSUPPORTED; if (status)
return font->status; return _cairo_truetype_font_set_error (font, status);
}
start_offset = _cairo_array_num_elements (&font->output); start_offset = _cairo_array_num_elements (&font->output);
for (i = 0; i < font->base.num_glyphs; i++) { for (i = 0; i < font->base.num_glyphs; i++) {
@ -524,21 +578,21 @@ cairo_truetype_font_write_glyf_table (cairo_truetype_font_t *font,
next = cairo_truetype_font_align_output (font); next = cairo_truetype_font_align_output (font);
font->status = cairo_truetype_font_check_boundary (font, next); status = cairo_truetype_font_check_boundary (font, next);
if (font->status) if (status)
break; goto FAIL;
font->glyphs[i].location = next - start_offset; font->glyphs[i].location = next - start_offset;
font->status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer); status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer);
if (font->status) if (status)
break; goto FAIL;
if (size != 0) { if (size != 0) {
font->status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_glyf, begin, buffer, &size); TT_TAG_glyf, begin, buffer, &size);
if (font->status) if (status)
break; goto FAIL;
cairo_truetype_font_remap_composite_glyph (font, buffer); cairo_truetype_font_remap_composite_glyph (font, buffer);
} }
@ -547,9 +601,11 @@ cairo_truetype_font_write_glyf_table (cairo_truetype_font_t *font,
font->glyphs[i].location = font->glyphs[i].location =
cairo_truetype_font_align_output (font) - start_offset; cairo_truetype_font_align_output (font) - start_offset;
status = font->status;
FAIL:
free (u.bytes); free (u.bytes);
return font->status; return _cairo_truetype_font_set_error (font, status);
} }
static cairo_status_t static cairo_status_t
@ -558,27 +614,31 @@ cairo_truetype_font_write_head_table (cairo_truetype_font_t *font,
{ {
unsigned char *buffer; unsigned char *buffer;
unsigned long size; unsigned long size;
cairo_status_t status;
if (font->status)
return font->status;
size = 0; size = 0;
font->status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
tag, 0, NULL, &size); tag, 0, NULL, &size);
if (font->status) if (status)
return font->status; return _cairo_truetype_font_set_error (font, status);
font->checksum_index = _cairo_array_num_elements (&font->output) + 8; font->checksum_index = _cairo_array_num_elements (&font->output) + 8;
font->status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer); status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer);
if (font->status) if (status)
return font->status; return _cairo_truetype_font_set_error (font, status);
font->status = font->backend->load_truetype_table( font->scaled_font_subset->scaled_font, status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
tag, 0, buffer, &size); tag, 0, buffer, &size);
if (font->status) if (status)
return font->status; return _cairo_truetype_font_set_error (font, status);
/* set checkSumAdjustment to 0 for table checksum calcualtion */ /* set checkSumAdjustment to 0 for table checksum calcualtion */
*(uint32_t *)(buffer + 8) = 0; *(uint32_t *)(buffer + 8) = 0;
return font->status; return CAIRO_STATUS_SUCCESS;
} }
static cairo_status_t static cairo_status_t
@ -586,20 +646,24 @@ cairo_truetype_font_write_hhea_table (cairo_truetype_font_t *font, unsigned long
{ {
tt_hhea_t *hhea; tt_hhea_t *hhea;
unsigned long size; unsigned long size;
cairo_status_t status;
if (font->status)
return font->status;
size = sizeof (tt_hhea_t); size = sizeof (tt_hhea_t);
font->status = cairo_truetype_font_allocate_write_buffer (font, size, (unsigned char **) &hhea); status = cairo_truetype_font_allocate_write_buffer (font, size, (unsigned char **) &hhea);
if (font->status) if (status)
return font->status; return _cairo_truetype_font_set_error (font, status);
font->status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
tag, 0, (unsigned char *) hhea, &size); tag, 0, (unsigned char *) hhea, &size);
if (font->status) if (status)
return font->status; return _cairo_truetype_font_set_error (font, status);
hhea->num_hmetrics = cpu_to_be16 ((uint16_t)(font->base.num_glyphs)); hhea->num_hmetrics = cpu_to_be16 ((uint16_t)(font->base.num_glyphs));
return font->status; return CAIRO_STATUS_SUCCESS;
} }
static cairo_status_t static cairo_status_t
@ -613,54 +677,58 @@ cairo_truetype_font_write_hmtx_table (cairo_truetype_font_t *font,
unsigned int i; unsigned int i;
tt_hhea_t hhea; tt_hhea_t hhea;
int num_hmetrics; int num_hmetrics;
cairo_status_t status;
size = sizeof (tt_hhea_t);
font->status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_hhea, 0,
(unsigned char*) &hhea, &size);
if (font->status) if (font->status)
return font->status; return font->status;
size = sizeof (tt_hhea_t);
status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_hhea, 0,
(unsigned char*) &hhea, &size);
if (status)
return _cairo_truetype_font_set_error (font, status);
num_hmetrics = be16_to_cpu(hhea.num_hmetrics); num_hmetrics = be16_to_cpu(hhea.num_hmetrics);
for (i = 0; i < font->base.num_glyphs; i++) { for (i = 0; i < font->base.num_glyphs; i++) {
long_entry_size = 2 * sizeof (int16_t); long_entry_size = 2 * sizeof (int16_t);
short_entry_size = sizeof (int16_t); short_entry_size = sizeof (int16_t);
font->status = cairo_truetype_font_allocate_write_buffer (font, long_entry_size, status = cairo_truetype_font_allocate_write_buffer (font,
(unsigned char **) &p); long_entry_size,
if (font->status) (unsigned char **) &p);
return font->status; if (status)
return _cairo_truetype_font_set_error (font, status);
if (font->glyphs[i].parent_index < num_hmetrics) { if (font->glyphs[i].parent_index < num_hmetrics) {
if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_hmtx, TT_TAG_hmtx,
font->glyphs[i].parent_index * long_entry_size, font->glyphs[i].parent_index * long_entry_size,
(unsigned char *) p, &long_entry_size) != CAIRO_STATUS_SUCCESS) { (unsigned char *) p, &long_entry_size);
font->status = CAIRO_INT_STATUS_UNSUPPORTED; if (status)
return font->status; return _cairo_truetype_font_set_error (font, status);
}
} }
else else
{ {
if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_hmtx, TT_TAG_hmtx,
(num_hmetrics - 1) * long_entry_size, (num_hmetrics - 1) * long_entry_size,
(unsigned char *) p, &short_entry_size) != CAIRO_STATUS_SUCCESS) { (unsigned char *) p, &short_entry_size);
font->status = CAIRO_INT_STATUS_UNSUPPORTED; if (status)
return font->status; return _cairo_truetype_font_set_error (font, status);
}
font->status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_hmtx, TT_TAG_hmtx,
num_hmetrics * long_entry_size + num_hmetrics * long_entry_size +
(font->glyphs[i].parent_index - num_hmetrics) * short_entry_size, (font->glyphs[i].parent_index - num_hmetrics) * short_entry_size,
(unsigned char *) (p + 1), &short_entry_size); (unsigned char *) (p + 1), &short_entry_size);
if (font->status) if (status)
return font->status; return _cairo_truetype_font_set_error (font, status);
} }
font->base.widths[i] = be16_to_cpu (p[0]); font->base.widths[i] = be16_to_cpu (p[0]);
} }
return font->status; return CAIRO_STATUS_SUCCESS;
} }
static cairo_status_t static cairo_status_t
@ -670,14 +738,18 @@ cairo_truetype_font_write_loca_table (cairo_truetype_font_t *font,
unsigned int i; unsigned int i;
tt_head_t header; tt_head_t header;
unsigned long size; unsigned long size;
cairo_status_t status;
size = sizeof(tt_head_t);
font->status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_head, 0,
(unsigned char*) &header, &size);
if (font->status) if (font->status)
return font->status; return font->status;
size = sizeof(tt_head_t);
status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_head, 0,
(unsigned char*) &header, &size);
if (status)
return _cairo_truetype_font_set_error (font, status);
if (be16_to_cpu (header.index_to_loc_format) == 0) if (be16_to_cpu (header.index_to_loc_format) == 0)
{ {
for (i = 0; i < font->base.num_glyphs + 1; i++) for (i = 0; i < font->base.num_glyphs + 1; i++)
@ -696,51 +768,26 @@ cairo_truetype_font_write_maxp_table (cairo_truetype_font_t *font,
{ {
tt_maxp_t *maxp; tt_maxp_t *maxp;
unsigned long size; unsigned long size;
cairo_status_t status;
if (font->status)
return font->status;
size = sizeof (tt_maxp_t); size = sizeof (tt_maxp_t);
font->status = cairo_truetype_font_allocate_write_buffer (font, size, (unsigned char **) &maxp); status = cairo_truetype_font_allocate_write_buffer (font, size, (unsigned char **) &maxp);
if (font->status) if (status)
return font->status; return _cairo_truetype_font_set_error (font, status);
font->status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
tag, 0, (unsigned char *) maxp, &size); tag, 0, (unsigned char *) maxp, &size);
if (font->status) if (status)
return font->status; return _cairo_truetype_font_set_error (font, status);
maxp->num_glyphs = cpu_to_be16 (font->base.num_glyphs); maxp->num_glyphs = cpu_to_be16 (font->base.num_glyphs);
return font->status; return CAIRO_STATUS_SUCCESS;
} }
typedef struct table table_t;
struct table {
unsigned long tag;
cairo_status_t (*write) (cairo_truetype_font_t *font, unsigned long tag);
int pos; /* position in the font directory */
};
static const table_t truetype_tables[] = {
/* As we write out the glyf table we remap composite glyphs.
* Remapping composite glyphs will reference the sub glyphs the
* composite glyph is made up of. That needs to be done first so
* we have all the glyphs in the subset before going further.
*
* The third column in this table is the order in which the
* directory entries will appear in the table directory.
* The table directory must be sorted in tag order. */
{ TT_TAG_glyf, cairo_truetype_font_write_glyf_table, 3 },
{ TT_TAG_cmap, cairo_truetype_font_write_cmap_table, 0 },
{ TT_TAG_cvt, cairo_truetype_font_write_generic_table, 1 },
{ TT_TAG_fpgm, cairo_truetype_font_write_generic_table, 2 },
{ TT_TAG_head, cairo_truetype_font_write_head_table, 4 },
{ TT_TAG_hhea, cairo_truetype_font_write_hhea_table, 5 },
{ TT_TAG_hmtx, cairo_truetype_font_write_hmtx_table, 6 },
{ TT_TAG_loca, cairo_truetype_font_write_loca_table, 7 },
{ TT_TAG_maxp, cairo_truetype_font_write_maxp_table, 8 },
{ TT_TAG_name, cairo_truetype_font_write_generic_table, 9 },
{ TT_TAG_prep, cairo_truetype_font_write_generic_table, 10 },
};
static cairo_status_t static cairo_status_t
cairo_truetype_font_write_offset_table (cairo_truetype_font_t *font) cairo_truetype_font_write_offset_table (cairo_truetype_font_t *font)
{ {
@ -748,20 +795,21 @@ cairo_truetype_font_write_offset_table (cairo_truetype_font_t *font)
unsigned char *table_buffer; unsigned char *table_buffer;
size_t table_buffer_length; size_t table_buffer_length;
unsigned short search_range, entry_selector, range_shift; unsigned short search_range, entry_selector, range_shift;
int num_tables;
num_tables = ARRAY_LENGTH (truetype_tables); if (font->status)
return font->status;
search_range = 1; search_range = 1;
entry_selector = 0; entry_selector = 0;
while (search_range * 2 <= num_tables) { while (search_range * 2 <= font->num_tables) {
search_range *= 2; search_range *= 2;
entry_selector++; entry_selector++;
} }
search_range *= 16; search_range *= 16;
range_shift = num_tables * 16 - search_range; range_shift = font->num_tables * 16 - search_range;
cairo_truetype_font_write_be32 (font, SFNT_VERSION); cairo_truetype_font_write_be32 (font, SFNT_VERSION);
cairo_truetype_font_write_be16 (font, num_tables); cairo_truetype_font_write_be16 (font, font->num_tables);
cairo_truetype_font_write_be16 (font, search_range); cairo_truetype_font_write_be16 (font, search_range);
cairo_truetype_font_write_be16 (font, entry_selector); cairo_truetype_font_write_be16 (font, entry_selector);
cairo_truetype_font_write_be16 (font, range_shift); cairo_truetype_font_write_be16 (font, range_shift);
@ -769,13 +817,13 @@ cairo_truetype_font_write_offset_table (cairo_truetype_font_t *font)
/* Allocate space for the table directory. Each directory entry /* Allocate space for the table directory. Each directory entry
* will be filled in by cairo_truetype_font_update_entry() after * will be filled in by cairo_truetype_font_update_entry() after
* the table is written. */ * the table is written. */
table_buffer_length = ARRAY_LENGTH (truetype_tables) * 16; table_buffer_length = font->num_tables * 16;
status = cairo_truetype_font_allocate_write_buffer (font, table_buffer_length, status = cairo_truetype_font_allocate_write_buffer (font, table_buffer_length,
&table_buffer); &table_buffer);
if (status) if (status)
return status; return _cairo_truetype_font_set_error (font, status);
return font->status; return CAIRO_STATUS_SUCCESS;
} }
static uint32_t static uint32_t
@ -824,28 +872,31 @@ cairo_truetype_font_generate (cairo_truetype_font_t *font,
cairo_status_t status; cairo_status_t status;
unsigned long start, end, next; unsigned long start, end, next;
uint32_t checksum, *checksum_location; uint32_t checksum, *checksum_location;
unsigned int i; int i;
if (cairo_truetype_font_write_offset_table (font)) if (font->status)
goto fail; return font->status;
status = cairo_truetype_font_write_offset_table (font);
if (status)
goto FAIL;
start = cairo_truetype_font_align_output (font); start = cairo_truetype_font_align_output (font);
end = start; end = start;
end = 0; end = 0;
for (i = 0; i < ARRAY_LENGTH (truetype_tables); i++) { for (i = 0; i < font->num_tables; i++) {
if (truetype_tables[i].write (font, truetype_tables[i].tag)) status = font->truetype_tables[i].write (font, font->truetype_tables[i].tag);
goto fail; if (status)
goto FAIL;
end = _cairo_array_num_elements (&font->output); end = _cairo_array_num_elements (&font->output);
next = cairo_truetype_font_align_output (font); next = cairo_truetype_font_align_output (font);
cairo_truetype_font_update_entry (font, truetype_tables[i].pos, truetype_tables[i].tag, cairo_truetype_font_update_entry (font, font->truetype_tables[i].pos,
start, end); font->truetype_tables[i].tag, start, end);
status = cairo_truetype_font_check_boundary (font, next); status = cairo_truetype_font_check_boundary (font, next);
if (status) { if (status)
font->status = status; goto FAIL;
goto fail;
}
start = next; start = next;
} }
@ -863,8 +914,8 @@ cairo_truetype_font_generate (cairo_truetype_font_t *font,
else else
*string_offsets = NULL; *string_offsets = NULL;
fail: FAIL:
return font->status; return _cairo_truetype_font_set_error (font, status);
} }
static int static int
@ -879,6 +930,91 @@ cairo_truetype_font_use_glyph (cairo_truetype_font_t *font, int glyph)
return font->parent_to_subset[glyph]; return font->parent_to_subset[glyph];
} }
static void
cairo_truetype_font_add_truetype_table (cairo_truetype_font_t *font,
unsigned long tag,
cairo_status_t (*write) (cairo_truetype_font_t *font, unsigned long tag),
int pos)
{
font->truetype_tables[font->num_tables].tag = tag;
font->truetype_tables[font->num_tables].write = write;
font->truetype_tables[font->num_tables].pos = pos;
font->num_tables++;
}
/* cairo_truetype_font_create_truetype_table_list() builds the list of
* truetype tables to be embedded in the subsetted font. Each call to
* cairo_truetype_font_add_truetype_table() adds a table, the callback
* for generating the table, and the position in the table directory
* to the truetype_tables array.
*
* As we write out the glyf table we remap composite glyphs.
* Remapping composite glyphs will reference the sub glyphs the
* composite glyph is made up of. The "glyf" table callback needs to
* be called first so we have all the glyphs in the subset before
* going further.
*
* The order in which tables are added to the truetype_table array
* using cairo_truetype_font_add_truetype_table() specifies the order
* in which the callback functions will be called.
*
* The tables in the table directory must be listed in alphabetical
* order. The "cvt", "fpgm", and "prep" are optional tables. They
* will only be embedded in the subset if they exist in the source
* font. The pos parameter of cairo_truetype_font_add_truetype_table()
* specifies the position of the table in the table directory.
*/
static void
cairo_truetype_font_create_truetype_table_list (cairo_truetype_font_t *font)
{
cairo_bool_t has_cvt = FALSE;
cairo_bool_t has_fpgm = FALSE;
cairo_bool_t has_prep = FALSE;
unsigned long size;
int pos;
size = 0;
if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_cvt, 0, NULL,
&size) == CAIRO_STATUS_SUCCESS)
has_cvt = TRUE;
size = 0;
if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_fpgm, 0, NULL,
&size) == CAIRO_STATUS_SUCCESS)
has_fpgm = TRUE;
size = 0;
if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font,
TT_TAG_prep, 0, NULL,
&size) == CAIRO_STATUS_SUCCESS)
has_prep = TRUE;
font->num_tables = 0;
pos = 1;
if (has_cvt)
pos++;
if (has_fpgm)
pos++;
cairo_truetype_font_add_truetype_table (font, TT_TAG_glyf, cairo_truetype_font_write_glyf_table, pos);
pos = 0;
cairo_truetype_font_add_truetype_table (font, TT_TAG_cmap, cairo_truetype_font_write_cmap_table, pos++);
if (has_cvt)
cairo_truetype_font_add_truetype_table (font, TT_TAG_cvt, cairo_truetype_font_write_generic_table, pos++);
if (has_fpgm)
cairo_truetype_font_add_truetype_table (font, TT_TAG_fpgm, cairo_truetype_font_write_generic_table, pos++);
pos++;
cairo_truetype_font_add_truetype_table (font, TT_TAG_head, cairo_truetype_font_write_head_table, pos++);
cairo_truetype_font_add_truetype_table (font, TT_TAG_hhea, cairo_truetype_font_write_hhea_table, pos++);
cairo_truetype_font_add_truetype_table (font, TT_TAG_hmtx, cairo_truetype_font_write_hmtx_table, pos++);
cairo_truetype_font_add_truetype_table (font, TT_TAG_loca, cairo_truetype_font_write_loca_table, pos++);
cairo_truetype_font_add_truetype_table (font, TT_TAG_maxp, cairo_truetype_font_write_maxp_table, pos++);
if (has_prep)
cairo_truetype_font_add_truetype_table (font, TT_TAG_prep, cairo_truetype_font_write_generic_table, pos);
}
cairo_status_t cairo_status_t
_cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset, _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset,
cairo_scaled_font_subset_t *font_subset) cairo_scaled_font_subset_t *font_subset)
@ -901,14 +1037,15 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset,
cairo_truetype_font_use_glyph (font, parent_glyph); cairo_truetype_font_use_glyph (font, parent_glyph);
} }
cairo_truetype_font_create_truetype_table_list (font);
status = cairo_truetype_font_generate (font, &data, &length, status = cairo_truetype_font_generate (font, &data, &length,
&string_offsets, &num_strings); &string_offsets, &num_strings);
if (status) if (status)
goto fail1; goto fail1;
truetype_subset->base_font = strdup (font->base.base_font); truetype_subset->base_font = strdup (font->base.base_font);
if (truetype_subset->base_font == NULL) { if (truetype_subset->base_font == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail1; goto fail1;
} }
@ -918,7 +1055,7 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset,
truetype_subset->widths = calloc (sizeof (double), truetype_subset->widths = calloc (sizeof (double),
font->scaled_font_subset->num_glyphs); font->scaled_font_subset->num_glyphs);
if (truetype_subset->widths == NULL) { if (truetype_subset->widths == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2; goto fail2;
} }
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) for (i = 0; i < font->scaled_font_subset->num_glyphs; i++)
@ -934,7 +1071,7 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset,
if (length) { if (length) {
truetype_subset->data = malloc (length); truetype_subset->data = malloc (length);
if (truetype_subset->data == NULL) { if (truetype_subset->data == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3; goto fail3;
} }
@ -947,7 +1084,7 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset,
offsets_length = num_strings * sizeof (unsigned long); offsets_length = num_strings * sizeof (unsigned long);
truetype_subset->string_offsets = malloc (offsets_length); truetype_subset->string_offsets = malloc (offsets_length);
if (truetype_subset->string_offsets == NULL) { if (truetype_subset->string_offsets == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail4; goto fail4;
} }
@ -971,6 +1108,9 @@ _cairo_truetype_subset_init (cairo_truetype_subset_t *truetype_subset,
fail1: fail1:
cairo_truetype_font_destroy (font); cairo_truetype_font_destroy (font);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
status = _cairo_error (status);
return status; return status;
} }
@ -987,7 +1127,7 @@ static cairo_int_status_t
_cairo_truetype_map_glyphs_to_unicode (cairo_scaled_font_subset_t *font_subset, _cairo_truetype_map_glyphs_to_unicode (cairo_scaled_font_subset_t *font_subset,
unsigned long table_offset) unsigned long table_offset)
{ {
cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; cairo_status_t status;
const cairo_scaled_font_backend_t *backend; const cairo_scaled_font_backend_t *backend;
tt_segment_map_t *map; tt_segment_map_t *map;
char buf[4]; char buf[4];
@ -1002,12 +1142,12 @@ _cairo_truetype_map_glyphs_to_unicode (cairo_scaled_font_subset_t *font_subset,
backend = font_subset->scaled_font->backend; backend = font_subset->scaled_font->backend;
size = 4; size = 4;
if (backend->load_truetype_table (font_subset->scaled_font, status = backend->load_truetype_table (font_subset->scaled_font,
TT_TAG_cmap, table_offset, TT_TAG_cmap, table_offset,
(unsigned char *) &buf, (unsigned char *) &buf,
&size) != CAIRO_STATUS_SUCCESS) { &size);
return CAIRO_INT_STATUS_UNSUPPORTED; if (status)
} return status;
/* All table formats have the same first two words */ /* All table formats have the same first two words */
map = (tt_segment_map_t *) buf; map = (tt_segment_map_t *) buf;
@ -1017,13 +1157,14 @@ _cairo_truetype_map_glyphs_to_unicode (cairo_scaled_font_subset_t *font_subset,
size = be16_to_cpu (map->length); size = be16_to_cpu (map->length);
map = malloc (size); map = malloc (size);
if (map == NULL) if (map == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (backend->load_truetype_table (font_subset->scaled_font,
TT_TAG_cmap, table_offset, status = backend->load_truetype_table (font_subset->scaled_font,
(unsigned char *) map, TT_TAG_cmap, table_offset,
&size) != CAIRO_STATUS_SUCCESS) { (unsigned char *) map,
&size);
if (status)
goto fail; goto fail;
}
num_segments = be16_to_cpu (map->segCountX2)/2; num_segments = be16_to_cpu (map->segCountX2)/2;
end_code = map->endCount; end_code = map->endCount;
@ -1091,23 +1232,26 @@ _cairo_truetype_create_glyph_to_unicode_map (cairo_scaled_font_subset_t *font_su
return CAIRO_INT_STATUS_UNSUPPORTED; return CAIRO_INT_STATUS_UNSUPPORTED;
size = 4; size = 4;
if (backend->load_truetype_table (font_subset->scaled_font, status = backend->load_truetype_table (font_subset->scaled_font,
TT_TAG_cmap, 0, (unsigned char *) &buf, TT_TAG_cmap, 0,
&size) != CAIRO_STATUS_SUCCESS) (unsigned char *) &buf,
return CAIRO_INT_STATUS_UNSUPPORTED; &size);
if (status)
return status;
cmap = (tt_cmap_t *) buf; cmap = (tt_cmap_t *) buf;
num_tables = be16_to_cpu (cmap->num_tables); num_tables = be16_to_cpu (cmap->num_tables);
size = 4 + num_tables*sizeof(tt_cmap_index_t); size = 4 + num_tables*sizeof(tt_cmap_index_t);
cmap = malloc (size); cmap = malloc (size);
if (cmap == NULL) if (cmap == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (backend->load_truetype_table (font_subset->scaled_font,
TT_TAG_cmap, 0, (unsigned char *) cmap, status = backend->load_truetype_table (font_subset->scaled_font,
&size) != CAIRO_STATUS_SUCCESS) { TT_TAG_cmap, 0,
status = CAIRO_INT_STATUS_UNSUPPORTED; (unsigned char *) cmap,
&size);
if (status)
goto cleanup; goto cleanup;
}
/* Find a table with Unicode mapping */ /* Find a table with Unicode mapping */
for (i = 0; i < num_tables; i++) { for (i = 0; i < num_tables; i++) {

View File

@ -41,7 +41,7 @@
typedef enum { typedef enum {
CAIRO_CHARSTRING_TYPE1, CAIRO_CHARSTRING_TYPE1,
CAIRO_CHARSTRING_TYPE2, CAIRO_CHARSTRING_TYPE2
} cairo_charstring_type_t; } cairo_charstring_type_t;
typedef struct _cairo_type1_font { typedef struct _cairo_type1_font {
@ -81,13 +81,13 @@ cairo_type1_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
font = calloc (1, sizeof (cairo_type1_font_t)); font = calloc (1, sizeof (cairo_type1_font_t));
if (font == NULL) if (font == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font->widths = calloc (scaled_font_subset->num_glyphs, font->widths = calloc (scaled_font_subset->num_glyphs,
sizeof (int)); sizeof (int));
if (font->widths == NULL) { if (font->widths == NULL) {
free (font); free (font);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
font->scaled_font_subset = scaled_font_subset; font->scaled_font_subset = scaled_font_subset;
@ -119,7 +119,7 @@ fail:
free (font->widths); free (font->widths);
free (font); free (font);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
/* Charstring commands. If the high byte is 0 the command is encoded /* Charstring commands. If the high byte is 0 the command is encoded
@ -465,7 +465,13 @@ cairo_type1_font_write_charstrings (cairo_type1_font_t *font,
goto fail; goto fail;
charstring_encrypt (&data); charstring_encrypt (&data);
length = _cairo_array_num_elements (&data); length = _cairo_array_num_elements (&data);
_cairo_output_stream_printf (encrypted_output, "/g%d %d RD ", i, length); if (font->scaled_font_subset->glyph_names != NULL) {
_cairo_output_stream_printf (encrypted_output, "/%s %d RD ",
font->scaled_font_subset->glyph_names[i],
length);
} else {
_cairo_output_stream_printf (encrypted_output, "/g%d %d RD ", i, length);
}
_cairo_output_stream_write (encrypted_output, _cairo_output_stream_write (encrypted_output,
_cairo_array_index (&data, 0), _cairo_array_index (&data, 0),
length); length);
@ -527,8 +533,14 @@ cairo_type1_font_write_header (cairo_type1_font_t *font,
"} readonly def\n" "} readonly def\n"
"/Encoding 256 array\n" "/Encoding 256 array\n"
"0 1 255 {1 index exch /.notdef put} for\n"); "0 1 255 {1 index exch /.notdef put} for\n");
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) for (i = 1; i < font->scaled_font_subset->num_glyphs; i++) {
_cairo_output_stream_printf (font->output, "dup %d /g%d put\n", i, i); if (font->scaled_font_subset->glyph_names != NULL) {
_cairo_output_stream_printf (font->output, "dup %d /%s put\n",
i, font->scaled_font_subset->glyph_names[i]);
} else {
_cairo_output_stream_printf (font->output, "dup %d /g%d put\n", i, i);
}
}
_cairo_output_stream_printf (font->output, _cairo_output_stream_printf (font->output,
"readonly def\n" "readonly def\n"
"currentdict end\n" "currentdict end\n"
@ -589,7 +601,7 @@ cairo_type1_font_write_private_dict (cairo_type1_font_t *font,
NULL, NULL,
font); font);
if (encrypted_output == NULL) { if (encrypted_output == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail; goto fail;
} }
@ -729,13 +741,13 @@ _cairo_type1_fallback_init_internal (cairo_type1_subset_t *type1_subset,
type1_subset->base_font = strdup (name); type1_subset->base_font = strdup (name);
if (type1_subset->base_font == NULL) { if (type1_subset->base_font == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail1; goto fail1;
} }
type1_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs); type1_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs);
if (type1_subset->widths == NULL) { if (type1_subset->widths == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2; goto fail2;
} }
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) for (i = 0; i < font->scaled_font_subset->num_glyphs; i++)
@ -752,7 +764,7 @@ _cairo_type1_fallback_init_internal (cairo_type1_subset_t *type1_subset,
font->trailer_size; font->trailer_size;
type1_subset->data = malloc (length); type1_subset->data = malloc (length);
if (type1_subset->data == NULL) { if (type1_subset->data == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3; goto fail3;
} }
memcpy (type1_subset->data, memcpy (type1_subset->data,
@ -781,7 +793,7 @@ _cairo_type1_fallback_init_internal (cairo_type1_subset_t *type1_subset,
/* status is already set, ignore further errors */ /* status is already set, ignore further errors */
cairo_type1_font_destroy (font); cairo_type1_font_destroy (font);
return status; return _cairo_error (status);
} }
cairo_status_t cairo_status_t
@ -829,7 +841,7 @@ _cairo_type2_charstrings_init (cairo_type2_charstrings_t *type2_subset,
type2_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs); type2_subset->widths = calloc (sizeof (int), font->scaled_font_subset->num_glyphs);
if (type2_subset->widths == NULL) { if (type2_subset->widths == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail1; goto fail1;
} }
@ -865,15 +877,14 @@ _cairo_type2_charstrings_init (cairo_type2_charstrings_t *type2_subset,
type2_subset->ascent = (int) font->y_max; type2_subset->ascent = (int) font->y_max;
type2_subset->descent = (int) font->y_min; type2_subset->descent = (int) font->y_min;
cairo_type1_font_destroy (font); return cairo_type1_font_destroy (font);
return CAIRO_STATUS_SUCCESS;
fail2: fail2:
_cairo_array_fini (&charstring); _cairo_array_fini (&charstring);
_cairo_type2_charstrings_fini (type2_subset); _cairo_type2_charstrings_fini (type2_subset);
fail1: fail1:
cairo_type1_font_destroy (font); cairo_type1_font_destroy (font);
return status; return _cairo_error (status);
} }
void void

View File

@ -99,8 +99,6 @@ typedef struct _cairo_type1_font_subset {
unsigned short eexec_key; unsigned short eexec_key;
cairo_bool_t hex_encode; cairo_bool_t hex_encode;
int hex_column; int hex_column;
cairo_status_t status;
} cairo_type1_font_subset_t; } cairo_type1_font_subset_t;
@ -119,15 +117,25 @@ _cairo_type1_font_subset_create (cairo_unscaled_font_t *unscaled_font,
ft_unscaled_font = (cairo_ft_unscaled_font_t *) unscaled_font; ft_unscaled_font = (cairo_ft_unscaled_font_t *) unscaled_font;
face = _cairo_ft_unscaled_font_lock_face (ft_unscaled_font); face = _cairo_ft_unscaled_font_lock_face (ft_unscaled_font);
if (face == NULL)
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (FT_Get_PS_Font_Info(face, &font_info) != 0) { if (FT_Get_PS_Font_Info(face, &font_info) != 0) {
status = CAIRO_INT_STATUS_UNSUPPORTED; status = CAIRO_INT_STATUS_UNSUPPORTED;
goto fail1; goto fail1;
} }
/* OpenType/CFF fonts also have a PS_FontInfoRec */
#if HAVE_FT_LOAD_SFNT_TABLE
if (FT_IS_SFNT (face)) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto fail1;
}
#endif
font = calloc (sizeof (cairo_type1_font_subset_t), 1); font = calloc (sizeof (cairo_type1_font_subset_t), 1);
if (font == NULL) { if (font == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail1; goto fail1;
} }
@ -141,7 +149,7 @@ _cairo_type1_font_subset_create (cairo_unscaled_font_t *unscaled_font,
font->base.descent = face->descender; font->base.descent = face->descender;
font->base.base_font = strdup (face->family_name); font->base.base_font = strdup (face->family_name);
if (font->base.base_font == NULL) { if (font->base.base_font == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2; goto fail2;
} }
@ -154,7 +162,7 @@ _cairo_type1_font_subset_create (cairo_unscaled_font_t *unscaled_font,
font->glyphs = calloc (face->num_glyphs, sizeof font->glyphs[0]); font->glyphs = calloc (face->num_glyphs, sizeof font->glyphs[0]);
if (font->glyphs == NULL) { if (font->glyphs == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3; goto fail3;
} }
@ -208,6 +216,9 @@ find_token (const char *buffer, const char *end, const char *token)
int i, length; int i, length;
/* FIXME: find substring really must be find_token */ /* FIXME: find substring really must be find_token */
if (buffer == NULL)
return NULL;
length = strlen (token); length = strlen (token);
for (i = 0; buffer + i < end - length + 1; i++) for (i = 0; buffer + i < end - length + 1; i++)
if (memcmp (buffer + i, token, length) == 0) if (memcmp (buffer + i, token, length) == 0)
@ -247,7 +258,7 @@ cairo_type1_font_subset_find_segments (cairo_type1_font_subset_t *font)
} else { } else {
eexec_token = find_token ((char *) p, font->type1_end, "eexec"); eexec_token = find_token ((char *) p, font->type1_end, "eexec");
if (eexec_token == NULL) if (eexec_token == NULL)
return font->status = CAIRO_INT_STATUS_UNSUPPORTED; return CAIRO_INT_STATUS_UNSUPPORTED;
font->header_segment_size = eexec_token - (char *) p + strlen ("eexec\n"); font->header_segment_size = eexec_token - (char *) p + strlen ("eexec\n");
font->header_segment = (char *) p; font->header_segment = (char *) p;
@ -270,7 +281,7 @@ cairo_type1_font_subset_write_header (cairo_type1_font_subset_t *font,
start = find_token (font->header_segment, segment_end, "/FontName"); start = find_token (font->header_segment, segment_end, "/FontName");
if (start == NULL) if (start == NULL)
return font->status = CAIRO_INT_STATUS_UNSUPPORTED; return CAIRO_INT_STATUS_UNSUPPORTED;
_cairo_output_stream_write (font->output, font->header_segment, _cairo_output_stream_write (font->output, font->header_segment,
start - font->header_segment); start - font->header_segment);
@ -279,12 +290,12 @@ cairo_type1_font_subset_write_header (cairo_type1_font_subset_t *font,
end = find_token (start, segment_end, "def"); end = find_token (start, segment_end, "def");
if (end == NULL) if (end == NULL)
return font->status = CAIRO_INT_STATUS_UNSUPPORTED; return CAIRO_INT_STATUS_UNSUPPORTED;
end += 3; end += 3;
start = find_token (end, segment_end, "/Encoding"); start = find_token (end, segment_end, "/Encoding");
if (start == NULL) if (start == NULL)
return font->status = CAIRO_INT_STATUS_UNSUPPORTED; return CAIRO_INT_STATUS_UNSUPPORTED;
_cairo_output_stream_write (font->output, end, start - end); _cairo_output_stream_write (font->output, end, start - end);
_cairo_output_stream_printf (font->output, _cairo_output_stream_printf (font->output,
@ -302,12 +313,12 @@ cairo_type1_font_subset_write_header (cairo_type1_font_subset_t *font,
end = find_token (start, segment_end, "def"); end = find_token (start, segment_end, "def");
if (end == NULL) if (end == NULL)
return font->status = CAIRO_INT_STATUS_UNSUPPORTED; return CAIRO_INT_STATUS_UNSUPPORTED;
end += 3; end += 3;
_cairo_output_stream_write (font->output, end, segment_end - end); _cairo_output_stream_write (font->output, end, segment_end - end);
return font->status; return font->output->status;
} }
static int static int
@ -321,7 +332,7 @@ hex_to_int (int ch)
return ch - 'a' + 10; return ch - 'a' + 10;
} }
static void static cairo_status_t
cairo_type1_font_subset_write_encrypted (cairo_type1_font_subset_t *font, cairo_type1_font_subset_write_encrypted (cairo_type1_font_subset_t *font,
const char *data, unsigned int length) const char *data, unsigned int length)
{ {
@ -354,6 +365,8 @@ cairo_type1_font_subset_write_encrypted (cairo_type1_font_subset_t *font,
_cairo_output_stream_write (font->output, digits, 1); _cairo_output_stream_write (font->output, digits, 1);
} }
} }
return font->output->status;
} }
static cairo_status_t static cairo_status_t
@ -369,9 +382,9 @@ cairo_type1_font_subset_decrypt_eexec_segment (cairo_type1_font_subset_t *font)
font->cleartext = malloc (font->eexec_segment_size); font->cleartext = malloc (font->eexec_segment_size);
if (font->cleartext == NULL) if (font->cleartext == NULL)
return font->status = CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
out = font->cleartext;
out = font->cleartext;
while (in < end) { while (in < end) {
if (font->eexec_segment_is_ascii) { if (font->eexec_segment_is_ascii) {
c = *in++; c = *in++;
@ -386,10 +399,9 @@ cairo_type1_font_subset_decrypt_eexec_segment (cairo_type1_font_subset_t *font)
*out++ = p; *out++ = p;
} }
font->cleartext_end = out; font->cleartext_end = out;
return font->status; return CAIRO_STATUS_SUCCESS;
} }
static const char * static const char *
@ -440,7 +452,7 @@ cairo_type1_font_subset_get_glyph_names_and_widths (cairo_type1_font_subset_t *f
FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM); FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM);
if (error != 0) { if (error != 0) {
printf ("could not load glyph %d\n", i); printf ("could not load glyph %d\n", i);
return font->status = CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
font->glyphs[i].width = font->face->glyph->metrics.horiAdvance; font->glyphs[i].width = font->face->glyph->metrics.horiAdvance;
@ -448,12 +460,12 @@ cairo_type1_font_subset_get_glyph_names_and_widths (cairo_type1_font_subset_t *f
error = FT_Get_Glyph_Name(font->face, i, buffer, sizeof buffer); error = FT_Get_Glyph_Name(font->face, i, buffer, sizeof buffer);
if (error != 0) { if (error != 0) {
printf ("could not get glyph name for glyph %d\n", i); printf ("could not get glyph name for glyph %d\n", i);
return font->status = CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
font->glyphs[i].name = strdup (buffer); font->glyphs[i].name = strdup (buffer);
if (font->glyphs[i].name == NULL) if (font->glyphs[i].name == NULL)
return font->status = CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
@ -678,35 +690,38 @@ static const int16_t ps_standard_encoding_offset[256] = {
#define ps_standard_encoding(index) ((index) ? ps_standard_encoding_symbol+ps_standard_encoding_offset[(index)] : NULL) #define ps_standard_encoding(index) ((index) ? ps_standard_encoding_symbol+ps_standard_encoding_offset[(index)] : NULL)
static void static cairo_status_t
use_standard_encoding_glyph (cairo_type1_font_subset_t *font, int index) use_standard_encoding_glyph (cairo_type1_font_subset_t *font, int index)
{ {
const char *glyph_name; const char *glyph_name;
if (index < 0 || index > 255) if (index < 0 || index > 255)
return; return CAIRO_STATUS_SUCCESS;
glyph_name = ps_standard_encoding(index); glyph_name = ps_standard_encoding(index);
if (glyph_name == NULL) if (glyph_name == NULL)
return; return CAIRO_STATUS_SUCCESS;
index = cairo_type1_font_subset_lookup_glyph (font, index = cairo_type1_font_subset_lookup_glyph (font,
glyph_name, glyph_name,
strlen(glyph_name)); strlen(glyph_name));
if (index < 0) if (index < 0)
return; return CAIRO_INT_STATUS_UNSUPPORTED;
cairo_type1_font_subset_use_glyph (font, index); cairo_type1_font_subset_use_glyph (font, index);
return CAIRO_STATUS_SUCCESS;
} }
#define TYPE1_CHARSTRING_COMMAND_ESCAPE (12) #define TYPE1_CHARSTRING_COMMAND_ESCAPE (12)
#define TYPE1_CHARSTRING_COMMAND_SEAC (32 + 6) #define TYPE1_CHARSTRING_COMMAND_SEAC (32 + 6)
static void static cairo_status_t
cairo_type1_font_subset_look_for_seac(cairo_type1_font_subset_t *font, cairo_type1_font_subset_look_for_seac(cairo_type1_font_subset_t *font,
const char *name, int name_length, const char *name, int name_length,
const char *encrypted_charstring, int encrypted_charstring_length) const char *encrypted_charstring, int encrypted_charstring_length)
{ {
cairo_status_t status;
unsigned char *charstring; unsigned char *charstring;
const unsigned char *end; const unsigned char *end;
const unsigned char *p; const unsigned char *p;
@ -715,7 +730,7 @@ cairo_type1_font_subset_look_for_seac(cairo_type1_font_subset_t *font,
charstring = malloc (encrypted_charstring_length); charstring = malloc (encrypted_charstring_length);
if (charstring == NULL) if (charstring == NULL)
return; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
cairo_type1_font_subset_decrypt_charstring ((const unsigned char *) cairo_type1_font_subset_decrypt_charstring ((const unsigned char *)
encrypted_charstring, encrypted_charstring,
@ -741,8 +756,14 @@ cairo_type1_font_subset_look_for_seac(cairo_type1_font_subset_t *font,
* glyph is composed from. All we need to do is to * glyph is composed from. All we need to do is to
* make sure those glyphs are present in the subset * make sure those glyphs are present in the subset
* under their standard names. */ * under their standard names. */
use_standard_encoding_glyph (font, stack[3]); status = use_standard_encoding_glyph (font, stack[3]);
use_standard_encoding_glyph (font, stack[4]); if (status)
return status;
status = use_standard_encoding_glyph (font, stack[4]);
if (status)
return status;
sp = 0; sp = 0;
break; break;
@ -759,35 +780,50 @@ cairo_type1_font_subset_look_for_seac(cairo_type1_font_subset_t *font,
} }
free (charstring); free (charstring);
return CAIRO_STATUS_SUCCESS;
} }
static void static cairo_status_t
write_used_glyphs (cairo_type1_font_subset_t *font, write_used_glyphs (cairo_type1_font_subset_t *font,
const char *name, int name_length, const char *name, int name_length,
const char *charstring, int charstring_length) const char *charstring, int charstring_length)
{ {
cairo_status_t status;
char buffer[256]; char buffer[256];
int length; int length;
length = snprintf (buffer, sizeof buffer, length = snprintf (buffer, sizeof buffer,
"/%.*s %d %s ", "/%.*s %d %s ",
name_length, name, charstring_length, font->rd); name_length, name, charstring_length, font->rd);
cairo_type1_font_subset_write_encrypted (font, buffer, length); status = cairo_type1_font_subset_write_encrypted (font, buffer, length);
cairo_type1_font_subset_write_encrypted (font, if (status)
charstring, charstring_length); return status;
status = cairo_type1_font_subset_write_encrypted (font,
charstring,
charstring_length);
if (status)
return status;
length = snprintf (buffer, sizeof buffer, "%s\n", font->nd); length = snprintf (buffer, sizeof buffer, "%s\n", font->nd);
cairo_type1_font_subset_write_encrypted (font, buffer, length); status = cairo_type1_font_subset_write_encrypted (font, buffer, length);
if (status)
return status;
return CAIRO_STATUS_SUCCESS;
} }
typedef void (*glyph_func_t) (cairo_type1_font_subset_t *font, typedef cairo_status_t (*glyph_func_t) (cairo_type1_font_subset_t *font,
const char *name, int name_length, const char *name, int name_length,
const char *charstring, int charstring_length); const char *charstring, int charstring_length);
static const char * static cairo_status_t
cairo_type1_font_subset_for_each_glyph (cairo_type1_font_subset_t *font, cairo_type1_font_subset_for_each_glyph (cairo_type1_font_subset_t *font,
const char *dict_start, const char *dict_start,
const char *dict_end, const char *dict_end,
glyph_func_t func) glyph_func_t func,
const char **dict_out)
{ {
int charstring_length, name_length, glyph_index; int charstring_length, name_length, glyph_index;
const char *p, *charstring, *name; const char *p, *charstring, *name;
@ -815,10 +851,8 @@ cairo_type1_font_subset_for_each_glyph (cairo_type1_font_subset_t *font,
name_length = p - name; name_length = p - name;
charstring_length = strtol (p, &end, 10); charstring_length = strtol (p, &end, 10);
if (p == end) { if (p == end)
font->status = CAIRO_INT_STATUS_UNSUPPORTED; return CAIRO_INT_STATUS_UNSUPPORTED;
return NULL;
}
/* Skip past -| or RD to binary data. There is exactly one space /* Skip past -| or RD to binary data. There is exactly one space
* between the -| or RD token and the encrypted data, thus '+ 1'. */ * between the -| or RD token and the encrypted data, thus '+ 1'. */
@ -831,25 +865,31 @@ cairo_type1_font_subset_for_each_glyph (cairo_type1_font_subset_t *font,
/* In case any of the skip_token() calls above reached EOF, p will /* In case any of the skip_token() calls above reached EOF, p will
* be equal to dict_end. */ * be equal to dict_end. */
if (p == dict_end) { if (p == dict_end)
font->status = CAIRO_INT_STATUS_UNSUPPORTED; return CAIRO_INT_STATUS_UNSUPPORTED;
return NULL;
}
glyph_index = cairo_type1_font_subset_lookup_glyph (font, glyph_index = cairo_type1_font_subset_lookup_glyph (font,
name, name_length); name, name_length);
if (font->glyphs[glyph_index].subset_index >= 0) if (font->glyphs[glyph_index].subset_index >= 0) {
func (font, name, name_length, charstring, charstring_length); cairo_status_t status = func (font,
name, name_length,
charstring, charstring_length);
if (status)
return status;
}
} }
return p; *dict_out = p;
return CAIRO_STATUS_SUCCESS;
} }
static const char * static cairo_status_t
cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font, cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font,
const char *name) const char *name)
{ {
cairo_status_t status;
const char *p, *charstrings, *dict_start; const char *p, *charstrings, *dict_start;
const char *closefile_token; const char *closefile_token;
char buffer[32], *glyph_count_end; char buffer[32], *glyph_count_end;
@ -872,88 +912,98 @@ cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font,
* conceivably have "/CharStrings" in it, so we might need to skip * conceivably have "/CharStrings" in it, so we might need to skip
* this more cleverly. */ * this more cleverly. */
charstrings = find_token (font->cleartext, font->cleartext_end, "/CharStrings"); charstrings = find_token (font->cleartext, font->cleartext_end, "/CharStrings");
if (charstrings == NULL) { if (charstrings == NULL)
font->status = CAIRO_INT_STATUS_UNSUPPORTED; return CAIRO_INT_STATUS_UNSUPPORTED;
return NULL;
}
/* Scan past /CharStrings and the integer following it. */ /* Scan past /CharStrings and the integer following it. */
p = charstrings + strlen ("/CharStrings"); p = charstrings + strlen ("/CharStrings");
num_charstrings = strtol (p, &glyph_count_end, 10); num_charstrings = strtol (p, &glyph_count_end, 10);
if (p == glyph_count_end) { if (p == glyph_count_end)
font->status = CAIRO_INT_STATUS_UNSUPPORTED; return CAIRO_INT_STATUS_UNSUPPORTED;
return NULL;
}
/* Look for a '/' which marks the beginning of the first glyph /* Look for a '/' which marks the beginning of the first glyph
* definition. */ * definition. */
for (p = glyph_count_end; p < font->cleartext_end; p++) for (p = glyph_count_end; p < font->cleartext_end; p++)
if (*p == '/') if (*p == '/')
break; break;
if (p == font->cleartext_end) { if (p == font->cleartext_end)
font->status = CAIRO_INT_STATUS_UNSUPPORTED; return CAIRO_INT_STATUS_UNSUPPORTED;
return NULL;
}
dict_start = p; dict_start = p;
if (cairo_type1_font_subset_get_glyph_names_and_widths (font)) status = cairo_type1_font_subset_get_glyph_names_and_widths (font);
return NULL; if (status)
return status;
/* Now that we have the private dictionary broken down in /* Now that we have the private dictionary broken down in
* sections, do the first pass through the glyph definitions to * sections, do the first pass through the glyph definitions to
* figure out which subrs and othersubrs are use and which extra * figure out which subrs and othersubrs are use and which extra
* glyphs may be required by the seac operator. */ * glyphs may be required by the seac operator. */
p = cairo_type1_font_subset_for_each_glyph (font, status = cairo_type1_font_subset_for_each_glyph (font,
dict_start, dict_start,
font->cleartext_end, font->cleartext_end,
cairo_type1_font_subset_look_for_seac); cairo_type1_font_subset_look_for_seac,
&p);
if (status)
return status;
closefile_token = find_token (p, font->cleartext_end, "closefile"); closefile_token = find_token (p, font->cleartext_end, "closefile");
if (closefile_token == NULL) { if (closefile_token == NULL)
font->status = CAIRO_INT_STATUS_UNSUPPORTED; return CAIRO_INT_STATUS_UNSUPPORTED;
return NULL;
}
if (cairo_type1_font_subset_get_glyph_names_and_widths (font)) status = cairo_type1_font_subset_get_glyph_names_and_widths (font);
return NULL; if (status)
return status;
/* We're ready to start outputting. First write the header, /* We're ready to start outputting. First write the header,
* i.e. the public part of the font dict.*/ * i.e. the public part of the font dict.*/
if (cairo_type1_font_subset_write_header (font, name)) status = cairo_type1_font_subset_write_header (font, name);
return NULL; if (status)
return status;
font->base.header_size = _cairo_output_stream_get_position (font->output); font->base.header_size = _cairo_output_stream_get_position (font->output);
/* Start outputting the private dict. First output everything up /* Start outputting the private dict. First output everything up
* to the /CharStrings token. */ * to the /CharStrings token. */
cairo_type1_font_subset_write_encrypted (font, font->cleartext, status = cairo_type1_font_subset_write_encrypted (font, font->cleartext,
charstrings - font->cleartext); charstrings - font->cleartext);
if (status)
return status;
/* Write out new charstring count */ /* Write out new charstring count */
length = snprintf (buffer, sizeof buffer, length = snprintf (buffer, sizeof buffer,
"/CharStrings %d", font->num_glyphs); "/CharStrings %d", font->num_glyphs);
cairo_type1_font_subset_write_encrypted (font, buffer, length); status = cairo_type1_font_subset_write_encrypted (font, buffer, length);
if (status)
return status;
/* Write out text between the charstring count and the first /* Write out text between the charstring count and the first
* charstring definition */ * charstring definition */
cairo_type1_font_subset_write_encrypted (font, glyph_count_end, status = cairo_type1_font_subset_write_encrypted (font, glyph_count_end,
dict_start - glyph_count_end); dict_start - glyph_count_end);
if (status)
return status;
/* Write out the charstring definitions for each of the glyphs in /* Write out the charstring definitions for each of the glyphs in
* the subset. */ * the subset. */
p = cairo_type1_font_subset_for_each_glyph (font, status = cairo_type1_font_subset_for_each_glyph (font,
dict_start, dict_start,
font->cleartext_end, font->cleartext_end,
write_used_glyphs); write_used_glyphs,
&p);
if (status)
return status;
/* Output what's left between the end of the glyph definitions and /* Output what's left between the end of the glyph definitions and
* the end of the private dict to the output. */ * the end of the private dict to the output. */
cairo_type1_font_subset_write_encrypted (font, p, status = cairo_type1_font_subset_write_encrypted (font, p,
closefile_token - p + strlen ("closefile") + 1); closefile_token - p + strlen ("closefile") + 1);
if (status)
return status;
_cairo_output_stream_write (font->output, "\n", 1); _cairo_output_stream_write (font->output, "\n", 1);
return p; return CAIRO_STATUS_SUCCESS;
} }
static cairo_status_t static cairo_status_t
@ -973,12 +1023,12 @@ cairo_type1_font_subset_write_trailer(cairo_type1_font_subset_t *font)
cleartomark_token = find_token (font->type1_data, font->type1_end, "cleartomark"); cleartomark_token = find_token (font->type1_data, font->type1_end, "cleartomark");
if (cleartomark_token == NULL) if (cleartomark_token == NULL)
return font->status = CAIRO_INT_STATUS_UNSUPPORTED; return CAIRO_INT_STATUS_UNSUPPORTED;
_cairo_output_stream_write (font->output, cleartomark_token, _cairo_output_stream_write (font->output, cleartomark_token,
font->type1_end - cleartomark_token); font->type1_end - cleartomark_token);
return font->status; return CAIRO_STATUS_SUCCESS;
} }
static cairo_status_t static cairo_status_t
@ -986,21 +1036,22 @@ type1_font_write (void *closure, const unsigned char *data, unsigned int length)
{ {
cairo_type1_font_subset_t *font = closure; cairo_type1_font_subset_t *font = closure;
font->status = return _cairo_array_append_multiple (&font->contents, data, length);
_cairo_array_append_multiple (&font->contents, data, length);
return font->status;
} }
static cairo_status_t static cairo_status_t
cairo_type1_font_subset_write (cairo_type1_font_subset_t *font, cairo_type1_font_subset_write (cairo_type1_font_subset_t *font,
const char *name) const char *name)
{ {
if (cairo_type1_font_subset_find_segments (font)) cairo_status_t status;
return font->status;
if (cairo_type1_font_subset_decrypt_eexec_segment (font)) status = cairo_type1_font_subset_find_segments (font);
return font->status; if (status)
return status;
status = cairo_type1_font_subset_decrypt_eexec_segment (font);
if (status)
return status;
/* Determine which glyph definition delimiters to use. */ /* Determine which glyph definition delimiters to use. */
if (find_token (font->cleartext, font->cleartext_end, "/-|") != NULL) { if (find_token (font->cleartext, font->cleartext_end, "/-|") != NULL) {
@ -1011,24 +1062,28 @@ cairo_type1_font_subset_write (cairo_type1_font_subset_t *font,
font->nd = "ND"; font->nd = "ND";
} else { } else {
/* Don't know *what* kind of font this is... */ /* Don't know *what* kind of font this is... */
return font->status = CAIRO_INT_STATUS_UNSUPPORTED; return CAIRO_INT_STATUS_UNSUPPORTED;
} }
font->eexec_key = CAIRO_TYPE1_PRIVATE_DICT_KEY; font->eexec_key = CAIRO_TYPE1_PRIVATE_DICT_KEY;
font->hex_column = 0; font->hex_column = 0;
cairo_type1_font_subset_write_private_dict (font, name); status = cairo_type1_font_subset_write_private_dict (font, name);
if (status)
return status;
font->base.data_size = _cairo_output_stream_get_position (font->output) - font->base.data_size = _cairo_output_stream_get_position (font->output) -
font->base.header_size; font->base.header_size;
cairo_type1_font_subset_write_trailer (font); status = cairo_type1_font_subset_write_trailer (font);
if (status)
return status;
font->base.trailer_size = font->base.trailer_size =
_cairo_output_stream_get_position (font->output) - _cairo_output_stream_get_position (font->output) -
font->base.header_size - font->base.data_size; font->base.header_size - font->base.data_size;
return font->status; return CAIRO_STATUS_SUCCESS;
} }
static cairo_status_t static cairo_status_t
@ -1039,45 +1094,52 @@ cairo_type1_font_subset_generate (void *abstract_font,
cairo_type1_font_subset_t *font = abstract_font; cairo_type1_font_subset_t *font = abstract_font;
cairo_ft_unscaled_font_t *ft_unscaled_font; cairo_ft_unscaled_font_t *ft_unscaled_font;
unsigned long ret; unsigned long ret;
cairo_status_t status;
ft_unscaled_font = (cairo_ft_unscaled_font_t *) font->base.unscaled_font; ft_unscaled_font = (cairo_ft_unscaled_font_t *) font->base.unscaled_font;
font->face = _cairo_ft_unscaled_font_lock_face (ft_unscaled_font); font->face = _cairo_ft_unscaled_font_lock_face (ft_unscaled_font);
if (font->face == NULL)
/* If anything fails below, it's out of memory. */ return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font->status = CAIRO_STATUS_NO_MEMORY;
font->type1_length = font->face->stream->size; font->type1_length = font->face->stream->size;
font->type1_data = malloc (font->type1_length); font->type1_data = malloc (font->type1_length);
if (font->type1_data == NULL) if (font->type1_data == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail; goto fail;
}
if (font->face->stream->read) { if (font->face->stream->read) {
ret = font->face->stream->read (font->face->stream, 0, ret = font->face->stream->read (font->face->stream, 0,
(unsigned char *) font->type1_data, (unsigned char *) font->type1_data,
font->type1_length); font->type1_length);
if (ret != font->type1_length) if (ret != font->type1_length) {
status = _cairo_error (CAIRO_STATUS_READ_ERROR);
goto fail; goto fail;
}
} else { } else {
memcpy (font->type1_data, memcpy (font->type1_data,
font->face->stream->base, font->type1_length); font->face->stream->base, font->type1_length);
} }
if (_cairo_array_grow_by (&font->contents, 4096) != CAIRO_STATUS_SUCCESS) status = _cairo_array_grow_by (&font->contents, 4096);
if (status)
goto fail; goto fail;
font->output = _cairo_output_stream_create (type1_font_write, NULL, font); font->output = _cairo_output_stream_create (type1_font_write, NULL, font);
if (font->output == NULL) status = _cairo_output_stream_get_status (font->output);
if (status)
goto fail; goto fail;
font->status = CAIRO_STATUS_SUCCESS; status = cairo_type1_font_subset_write (font, name);
cairo_type1_font_subset_write (font, name); if (status)
goto fail;
font->base.data = _cairo_array_index (&font->contents, 0); font->base.data = _cairo_array_index (&font->contents, 0);
fail: fail:
_cairo_ft_unscaled_font_unlock_face (ft_unscaled_font); _cairo_ft_unscaled_font_unlock_face (ft_unscaled_font);
return font->status; return status;
} }
static void static void
@ -1111,7 +1173,7 @@ _cairo_type1_subset_init (cairo_type1_subset_t *type1_subset,
cairo_scaled_font_subset_t *scaled_font_subset, cairo_scaled_font_subset_t *scaled_font_subset,
cairo_bool_t hex_encode) cairo_bool_t hex_encode)
{ {
cairo_type1_font_subset_t *font; cairo_type1_font_subset_t *font = NULL; /* hide compiler warning */
cairo_status_t status; cairo_status_t status;
unsigned long parent_glyph, length; unsigned long parent_glyph, length;
unsigned int i; unsigned int i;
@ -1203,6 +1265,8 @@ _cairo_type1_scaled_font_is_type1 (cairo_scaled_font_t *scaled_font)
PS_FontInfoRec font_info; PS_FontInfoRec font_info;
cairo_bool_t is_type1 = FALSE; cairo_bool_t is_type1 = FALSE;
if (!_cairo_scaled_font_is_ft (scaled_font))
return FALSE;
unscaled = (cairo_ft_unscaled_font_t *) _cairo_ft_scaled_font_get_unscaled_font (scaled_font); unscaled = (cairo_ft_unscaled_font_t *) _cairo_ft_scaled_font_get_unscaled_font (scaled_font);
face = _cairo_ft_unscaled_font_lock_face (unscaled); face = _cairo_ft_unscaled_font_lock_face (unscaled);
if (!face) if (!face)

View File

@ -54,7 +54,6 @@ typedef struct _cairo_paginated_surface_backend cairo_paginated_surface_backend_
typedef struct _cairo_scaled_font_backend cairo_scaled_font_backend_t; typedef struct _cairo_scaled_font_backend cairo_scaled_font_backend_t;
typedef struct _cairo_font_face_backend cairo_font_face_backend_t; typedef struct _cairo_font_face_backend cairo_font_face_backend_t;
typedef struct _cairo_xlib_screen_info cairo_xlib_screen_info_t; typedef struct _cairo_xlib_screen_info cairo_xlib_screen_info_t;
typedef enum _cairo_paginated_mode cairo_paginated_mode_t;
typedef cairo_array_t cairo_user_data_array_t; typedef cairo_array_t cairo_user_data_array_t;
/** /**
@ -122,10 +121,10 @@ struct _cairo_cache {
int freeze_count; int freeze_count;
}; };
enum _cairo_paginated_mode { typedef enum _cairo_paginated_mode {
CAIRO_PAGINATED_MODE_ANALYZE, /* analyze page regions */ CAIRO_PAGINATED_MODE_ANALYZE, /* analyze page regions */
CAIRO_PAGINATED_MODE_RENDER /* render page contents */ CAIRO_PAGINATED_MODE_RENDER /* render page contents */
}; } cairo_paginated_mode_t;
/* Sure wish C had a real enum type so that this would be distinct /* Sure wish C had a real enum type so that this would be distinct
from cairo_status_t. Oh well, without that, I'll use this bogus 1000 from cairo_status_t. Oh well, without that, I'll use this bogus 1000
@ -137,7 +136,7 @@ typedef enum _cairo_int_status {
CAIRO_INT_STATUS_CACHE_EMPTY, CAIRO_INT_STATUS_CACHE_EMPTY,
CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY, CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY,
CAIRO_INT_STATUS_IMAGE_FALLBACK, CAIRO_INT_STATUS_IMAGE_FALLBACK,
CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN, CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN
} cairo_int_status_t; } cairo_int_status_t;
typedef enum _cairo_internal_surface_type { typedef enum _cairo_internal_surface_type {

View File

@ -231,18 +231,18 @@ _cairo_utf8_to_ucs4 (const unsigned char *str,
{ {
uint32_t wc = _utf8_get_char_extended (in, str + len - in); uint32_t wc = _utf8_get_char_extended (in, str + len - in);
if (wc & 0x80000000 || !UNICODE_VALID (wc)) if (wc & 0x80000000 || !UNICODE_VALID (wc))
return CAIRO_STATUS_INVALID_STRING; return _cairo_error (CAIRO_STATUS_INVALID_STRING);
n_chars++; n_chars++;
if (n_chars == INT_MAX) if (n_chars == INT_MAX)
return CAIRO_STATUS_INVALID_STRING; return _cairo_error (CAIRO_STATUS_INVALID_STRING);
in = UTF8_NEXT_CHAR (in); in = UTF8_NEXT_CHAR (in);
} }
str32 = _cairo_malloc_ab (n_chars + 1, sizeof (uint32_t)); str32 = _cairo_malloc_ab (n_chars + 1, sizeof (uint32_t));
if (!str32) if (!str32)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
in = str; in = str;
for (i=0; i < n_chars; i++) { for (i=0; i < n_chars; i++) {
@ -294,7 +294,7 @@ _cairo_utf8_to_utf16 (const unsigned char *str,
while ((len < 0 || str + len - in > 0) && *in) { while ((len < 0 || str + len - in > 0) && *in) {
uint32_t wc = _utf8_get_char_extended (in, str + len - in); uint32_t wc = _utf8_get_char_extended (in, str + len - in);
if (wc & 0x80000000 || !UNICODE_VALID (wc)) if (wc & 0x80000000 || !UNICODE_VALID (wc))
return CAIRO_STATUS_INVALID_STRING; return _cairo_error (CAIRO_STATUS_INVALID_STRING);
if (wc < 0x10000) if (wc < 0x10000)
n16 += 1; n16 += 1;
@ -302,14 +302,14 @@ _cairo_utf8_to_utf16 (const unsigned char *str,
n16 += 2; n16 += 2;
if (n16 == INT_MAX - 1 || n16 == INT_MAX) if (n16 == INT_MAX - 1 || n16 == INT_MAX)
return CAIRO_STATUS_INVALID_STRING; return _cairo_error (CAIRO_STATUS_INVALID_STRING);
in = UTF8_NEXT_CHAR (in); in = UTF8_NEXT_CHAR (in);
} }
str16 = _cairo_malloc_ab (n16 + 1, sizeof (uint16_t)); str16 = _cairo_malloc_ab (n16 + 1, sizeof (uint16_t));
if (!str16) if (!str16)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
in = str; in = str;
for (i = 0; i < n16;) { for (i = 0; i < n16;) {

View File

@ -74,6 +74,8 @@
#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.) #error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.)
#endif #endif
#include "cairo-compiler-private.h"
/* /*
* 64-bit datatypes. Two separate implementations, one using * 64-bit datatypes. Two separate implementations, one using
* built-in 64-bit signed/unsigned types another implemented * built-in 64-bit signed/unsigned types another implemented

View File

@ -234,13 +234,14 @@ _get_system_quality (void)
* all be 0, and face_hfont is the result of calling CreateFontIndirectW on * all be 0, and face_hfont is the result of calling CreateFontIndirectW on
* logfont. * logfont.
*/ */
static cairo_scaled_font_t * static cairo_status_t
_win32_scaled_font_create (LOGFONTW *logfont, _win32_scaled_font_create (LOGFONTW *logfont,
HFONT face_hfont, HFONT face_hfont,
cairo_font_face_t *font_face, cairo_font_face_t *font_face,
const cairo_matrix_t *font_matrix, const cairo_matrix_t *font_matrix,
const cairo_matrix_t *ctm, const cairo_matrix_t *ctm,
const cairo_font_options_t *options) const cairo_font_options_t *options,
cairo_scaled_font_t **font_out)
{ {
cairo_win32_scaled_font_t *f; cairo_win32_scaled_font_t *f;
cairo_matrix_t scale; cairo_matrix_t scale;
@ -248,7 +249,7 @@ _win32_scaled_font_create (LOGFONTW *logfont,
f = malloc (sizeof(cairo_win32_scaled_font_t)); f = malloc (sizeof(cairo_win32_scaled_font_t));
if (f == NULL) if (f == NULL)
return NULL; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
f->logfont = *logfont; f->logfont = *logfont;
@ -308,17 +309,17 @@ _win32_scaled_font_create (LOGFONTW *logfont,
goto FAIL; goto FAIL;
status = _cairo_win32_scaled_font_set_metrics (f); status = _cairo_win32_scaled_font_set_metrics (f);
if (status) { if (status) {
_cairo_scaled_font_fini (&f->base); _cairo_scaled_font_fini (&f->base);
goto FAIL; goto FAIL;
} }
return &f->base; *font_out = &f->base;
return CAIRO_STATUS_SUCCESS;
FAIL: FAIL:
free (f); free (f);
return NULL; return status;
} }
static cairo_status_t static cairo_status_t
@ -413,8 +414,10 @@ _win32_scaled_font_get_unscaled_hfont (cairo_win32_scaled_font_t *scaled_font,
} }
otm = malloc (otm_size); otm = malloc (otm_size);
if (!otm) if (!otm) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NULL; return NULL;
}
if (!GetOutlineTextMetrics (hdc, otm_size, otm)) { if (!GetOutlineTextMetrics (hdc, otm_size, otm)) {
_cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:GetOutlineTextMetrics"); _cairo_win32_print_gdi_error ("_win32_scaled_font_get_unscaled_hfont:GetOutlineTextMetrics");
@ -452,7 +455,7 @@ _cairo_win32_scaled_font_select_unscaled_font (cairo_scaled_font_t *scaled_font,
hfont = _win32_scaled_font_get_unscaled_hfont ((cairo_win32_scaled_font_t *)scaled_font, hdc); hfont = _win32_scaled_font_get_unscaled_hfont ((cairo_win32_scaled_font_t *)scaled_font, hdc);
if (!hfont) if (!hfont)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
old_hfont = SelectObject (hdc, hfont); old_hfont = SelectObject (hdc, hfont);
if (!old_hfont) if (!old_hfont)
@ -484,7 +487,6 @@ _cairo_win32_scaled_font_create_toy (cairo_toy_font_face_t *toy_face,
cairo_scaled_font_t **scaled_font_out) cairo_scaled_font_t **scaled_font_out)
{ {
LOGFONTW logfont; LOGFONTW logfont;
cairo_scaled_font_t *scaled_font;
uint16_t *face_name; uint16_t *face_name;
int face_name_len; int face_name_len;
cairo_status_t status; cairo_status_t status;
@ -496,7 +498,7 @@ _cairo_win32_scaled_font_create_toy (cairo_toy_font_face_t *toy_face,
if (face_name_len > LF_FACESIZE - 1) { if (face_name_len > LF_FACESIZE - 1) {
free (face_name); free (face_name);
return CAIRO_STATUS_INVALID_STRING; return _cairo_error (CAIRO_STATUS_INVALID_STRING);
} }
memcpy (logfont.lfFaceName, face_name, sizeof (uint16_t) * (face_name_len + 1)); memcpy (logfont.lfFaceName, face_name, sizeof (uint16_t) * (face_name_len + 1));
@ -541,16 +543,11 @@ _cairo_win32_scaled_font_create_toy (cairo_toy_font_face_t *toy_face,
logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
if (!logfont.lfFaceName) if (!logfont.lfFaceName)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
scaled_font = _win32_scaled_font_create (&logfont, NULL, &toy_face->base, return _win32_scaled_font_create (&logfont, NULL, &toy_face->base,
font_matrix, ctm, options); font_matrix, ctm, options,
if (!scaled_font) scaled_font_out);
return CAIRO_STATUS_NO_MEMORY;
*scaled_font_out = scaled_font;
return CAIRO_STATUS_SUCCESS;
} }
static void static void
@ -607,13 +604,13 @@ _cairo_win32_scaled_font_text_to_glyphs (void *abstract_font,
buffer_size = MAX (n16 * 1.2, 16); /* Initially guess number of chars plus a few */ buffer_size = MAX (n16 * 1.2, 16); /* Initially guess number of chars plus a few */
if (buffer_size > INT_MAX) { if (buffer_size > INT_MAX) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FAIL1; goto FAIL1;
} }
hdc = _get_global_font_dc (); hdc = _get_global_font_dc ();
if (!hdc) { if (!hdc) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FAIL1; goto FAIL1;
} }
@ -634,7 +631,7 @@ _cairo_win32_scaled_font_text_to_glyphs (void *abstract_font,
glyph_indices = _cairo_malloc_ab (buffer_size, sizeof (WCHAR)); glyph_indices = _cairo_malloc_ab (buffer_size, sizeof (WCHAR));
dx = _cairo_malloc_ab (buffer_size, sizeof (int)); dx = _cairo_malloc_ab (buffer_size, sizeof (int));
if (!glyph_indices || !dx) { if (!glyph_indices || !dx) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FAIL2; goto FAIL2;
} }
@ -657,7 +654,7 @@ _cairo_win32_scaled_font_text_to_glyphs (void *abstract_font,
buffer_size *= 1.5; buffer_size *= 1.5;
if (buffer_size > INT_MAX) { if (buffer_size > INT_MAX) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FAIL2; goto FAIL2;
} }
} }
@ -665,7 +662,7 @@ _cairo_win32_scaled_font_text_to_glyphs (void *abstract_font,
*num_glyphs = gcp_results.nGlyphs; *num_glyphs = gcp_results.nGlyphs;
*glyphs = _cairo_malloc_ab (gcp_results.nGlyphs, sizeof (cairo_glyph_t)); *glyphs = _cairo_malloc_ab (gcp_results.nGlyphs, sizeof (cairo_glyph_t));
if (!*glyphs) { if (!*glyphs) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FAIL2; goto FAIL2;
} }
@ -706,7 +703,7 @@ _cairo_win32_scaled_font_set_metrics (cairo_win32_scaled_font_t *scaled_font)
hdc = _get_global_font_dc (); hdc = _get_global_font_dc ();
if (!hdc) if (!hdc)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (scaled_font->preserve_axes || scaled_font->base.options.hint_metrics == CAIRO_HINT_METRICS_OFF) { if (scaled_font->preserve_axes || scaled_font->base.options.hint_metrics == CAIRO_HINT_METRICS_OFF) {
/* For 90-degree rotations (including 0), we get the metrics /* For 90-degree rotations (including 0), we get the metrics
@ -747,7 +744,7 @@ _cairo_win32_scaled_font_set_metrics (cairo_win32_scaled_font_t *scaled_font)
scaled_font->is_truetype = (metrics.tmPitchAndFamily & TMPF_TRUETYPE) != 0; scaled_font->is_truetype = (metrics.tmPitchAndFamily & TMPF_TRUETYPE) != 0;
scaled_font->glyph_indexing = scaled_font->is_truetype || scaled_font->glyph_indexing = scaled_font->is_truetype ||
(GetFontData (hdc, OPENTYPE_CFF_TAG, 0, NULL, 0) != GDI_ERROR); (GetFontData (hdc, OPENTYPE_CFF_TAG, 0, NULL, 0) != GDI_ERROR);
// XXX in what situations does this OPENTYPE_CFF thing not have the // XXX in what situations does this OPENTYPE_CFF thing not have the
// TMPF_TRUETYPE flag? GetFontData says it only works on Truetype fonts... // TMPF_TRUETYPE flag? GetFontData says it only works on Truetype fonts...
@ -768,31 +765,31 @@ _cairo_win32_scaled_font_init_glyph_metrics (cairo_win32_scaled_font_t *scaled_f
hdc = _get_global_font_dc (); hdc = _get_global_font_dc ();
if (!hdc) if (!hdc)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (!scaled_font->is_truetype) { if (!scaled_font->is_truetype) {
/* GetGlyphOutline will not work. Assume that the glyph does not extend outside the font box. */ /* GetGlyphOutline will not work. Assume that the glyph does not extend outside the font box. */
cairo_font_extents_t font_extents; cairo_font_extents_t font_extents;
INT width = 0; INT width = 0;
UINT charIndex = _cairo_scaled_glyph_index (scaled_glyph); UINT charIndex = _cairo_scaled_glyph_index (scaled_glyph);
cairo_scaled_font_extents (&scaled_font->base, &font_extents); cairo_scaled_font_extents (&scaled_font->base, &font_extents);
status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc); status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
if (!status) { if (!status) {
if (!GetCharWidth32(hdc, charIndex, charIndex, &width)) { if (!GetCharWidth32(hdc, charIndex, charIndex, &width)) {
status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_init_glyph_metrics:GetCharWidth32"); status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_init_glyph_metrics:GetCharWidth32");
width = 0; width = 0;
} }
} }
cairo_win32_scaled_font_done_font (&scaled_font->base); cairo_win32_scaled_font_done_font (&scaled_font->base);
extents.x_bearing = 0; extents.x_bearing = 0;
extents.y_bearing = -font_extents.ascent / scaled_font->y_scale; extents.y_bearing = -font_extents.ascent / scaled_font->y_scale;
extents.width = width / scaled_font->x_scale; extents.width = width / scaled_font->x_scale;
extents.height = (font_extents.ascent + font_extents.descent) / scaled_font->y_scale; extents.height = (font_extents.ascent + font_extents.descent) / scaled_font->y_scale;
extents.x_advance = extents.width; extents.x_advance = extents.width;
extents.y_advance = 0; extents.y_advance = 0;
} else if (scaled_font->preserve_axes && scaled_font->base.options.hint_style != CAIRO_HINT_METRICS_OFF) { } else if (scaled_font->preserve_axes && scaled_font->base.options.hint_style != CAIRO_HINT_METRICS_OFF) {
/* If we aren't rotating / skewing the axes, then we get the metrics /* If we aren't rotating / skewing the axes, then we get the metrics
* from the GDI in device space and convert to font space. * from the GDI in device space and convert to font space.
@ -886,7 +883,7 @@ _cairo_win32_scaled_font_glyph_bbox (void *abstract_font,
UINT glyph_index_option; UINT glyph_index_option;
if (!hdc) if (!hdc)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc); status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc);
if (status) if (status)
@ -1034,6 +1031,7 @@ _add_glyph (cairo_glyph_state_t *state,
static void static void
_finish_glyphs (cairo_glyph_state_t *state) _finish_glyphs (cairo_glyph_state_t *state)
{ {
/* ignore errors as we only call _finish_glyphs on the error path */
_flush_glyphs (state); _flush_glyphs (state);
_cairo_array_fini (&state->glyphs); _cairo_array_fini (&state->glyphs);
@ -1228,7 +1226,7 @@ _cairo_win32_scaled_font_show_glyphs (void *abstract_font,
tmp_surface = (cairo_win32_surface_t *)cairo_win32_surface_create_with_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) if (tmp_surface->base.status)
return CAIRO_STATUS_NO_MEMORY; return tmp_surface->base.status;
r.left = 0; r.left = 0;
r.top = 0; r.top = 0;
@ -1236,9 +1234,14 @@ _cairo_win32_scaled_font_show_glyphs (void *abstract_font,
r.bottom = height; r.bottom = height;
FillRect (tmp_surface->dc, &r, GetStockObject (WHITE_BRUSH)); FillRect (tmp_surface->dc, &r, GetStockObject (WHITE_BRUSH));
_draw_glyphs_on_surface (tmp_surface, scaled_font, RGB (0, 0, 0), status = _draw_glyphs_on_surface (tmp_surface,
dest_x, dest_y, scaled_font, RGB (0, 0, 0),
glyphs, num_glyphs); dest_x, dest_y,
glyphs, num_glyphs);
if (status) {
cairo_surface_destroy (&tmp_surface->base);
return status;
}
if (scaled_font->quality == CLEARTYPE_QUALITY) { if (scaled_font->quality == CLEARTYPE_QUALITY) {
/* For ClearType, we need a 4-channel mask. If we are compositing on /* For ClearType, we need a 4-channel mask. If we are compositing on
@ -1261,7 +1264,7 @@ _cairo_win32_scaled_font_show_glyphs (void *abstract_font,
mask_surface = _compute_a8_mask (tmp_surface); mask_surface = _compute_a8_mask (tmp_surface);
cairo_surface_destroy (&tmp_surface->base); cairo_surface_destroy (&tmp_surface->base);
if (!mask_surface) if (!mask_surface)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
/* For op == OVER, no-cleartype, a possible optimization here is to /* For op == OVER, no-cleartype, a possible optimization here is to
@ -1299,7 +1302,7 @@ _cairo_win32_scaled_font_load_truetype_table (void *abstract_font,
cairo_win32_scaled_font_t *scaled_font = abstract_font; cairo_win32_scaled_font_t *scaled_font = abstract_font;
hdc = _get_global_font_dc (); hdc = _get_global_font_dc ();
if (!hdc) if (!hdc)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
tag = (tag&0x000000ff)<<24 | (tag&0x0000ff00)<<8 | (tag&0x00ff0000)>>8 | (tag&0xff000000)>>24; tag = (tag&0x000000ff)<<24 | (tag&0x0000ff00)<<8 | (tag&0x00ff0000)>>8 | (tag&0xff000000)>>24;
status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc); status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc);
@ -1335,8 +1338,8 @@ _cairo_win32_transform_FIXED_to_fixed (cairo_matrix_t *matrix,
double x = Fx.value + Fx.fract / 65536.0; double x = Fx.value + Fx.fract / 65536.0;
double y = Fy.value + Fy.fract / 65536.0; double y = Fy.value + Fy.fract / 65536.0;
cairo_matrix_transform_point (matrix, &x, &y); cairo_matrix_transform_point (matrix, &x, &y);
*fx = _cairo_fixed_from_double (x); *fx = _cairo_fixed_from_double (x);
*fy = _cairo_fixed_from_double (y); *fy = _cairo_fixed_from_double (y);
} }
static cairo_status_t static cairo_status_t
@ -1356,11 +1359,11 @@ _cairo_win32_scaled_font_init_glyph_path (cairo_win32_scaled_font_t *scaled_font
hdc = _get_global_font_dc (); hdc = _get_global_font_dc ();
if (!hdc) if (!hdc)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
path = _cairo_path_fixed_create (); path = _cairo_path_fixed_create ();
if (!path) if (!path)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (scaled_font->base.options.hint_style == CAIRO_HINT_STYLE_NONE) { if (scaled_font->base.options.hint_style == CAIRO_HINT_STYLE_NONE) {
status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc); status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc);
@ -1390,7 +1393,7 @@ _cairo_win32_scaled_font_init_glyph_path (cairo_win32_scaled_font_t *scaled_font
ptr = buffer = malloc (bytesGlyph); ptr = buffer = malloc (bytesGlyph);
if (!buffer) { if (!buffer) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto CLEANUP_FONT; goto CLEANUP_FONT;
} }
@ -1398,8 +1401,7 @@ _cairo_win32_scaled_font_init_glyph_path (cairo_win32_scaled_font_t *scaled_font
GGO_NATIVE | glyph_index_option, GGO_NATIVE | glyph_index_option,
&metrics, bytesGlyph, buffer, &matrix) == GDI_ERROR) { &metrics, bytesGlyph, buffer, &matrix) == GDI_ERROR) {
status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_glyph_path"); status = _cairo_win32_print_gdi_error ("_cairo_win32_scaled_font_glyph_path");
free (buffer); goto CLEANUP_BUFFER;
goto CLEANUP_FONT;
} }
while (ptr < buffer + bytesGlyph) { while (ptr < buffer + bytesGlyph) {
@ -1412,7 +1414,9 @@ _cairo_win32_scaled_font_init_glyph_path (cairo_win32_scaled_font_t *scaled_font
header->pfxStart.x, header->pfxStart.x,
header->pfxStart.y, header->pfxStart.y,
&x, &y); &x, &y);
_cairo_path_fixed_move_to (path, x, y); status = _cairo_path_fixed_move_to (path, x, y);
if (status)
goto CLEANUP_BUFFER;
while (ptr < endPoly) { while (ptr < endPoly) {
TTPOLYCURVE *curve = (TTPOLYCURVE *)ptr; TTPOLYCURVE *curve = (TTPOLYCURVE *)ptr;
@ -1425,13 +1429,16 @@ _cairo_win32_scaled_font_init_glyph_path (cairo_win32_scaled_font_t *scaled_font
points[i].x, points[i].x,
points[i].y, points[i].y,
&x, &y); &x, &y);
_cairo_path_fixed_line_to (path, x, y); status = _cairo_path_fixed_line_to (path, x, y);
if (status)
goto CLEANUP_BUFFER;
} }
break; break;
case TT_PRIM_QSPLINE: case TT_PRIM_QSPLINE:
for (i = 0; i < curve->cpfx - 1; i++) { for (i = 0; i < curve->cpfx - 1; i++) {
cairo_fixed_t p1x, p1y, p2x, p2y, cx, cy, c1x, c1y, c2x, c2y; cairo_fixed_t p1x, p1y, p2x, p2y, cx, cy, c1x, c1y, c2x, c2y;
_cairo_path_fixed_get_current_point (path, &p1x, &p1y); if (! _cairo_path_fixed_get_current_point (path, &p1x, &p1y))
goto CLEANUP_BUFFER;
_cairo_win32_transform_FIXED_to_fixed (&transform, _cairo_win32_transform_FIXED_to_fixed (&transform,
points[i].x, points[i].x,
points[i].y, points[i].y,
@ -1458,7 +1465,9 @@ _cairo_win32_scaled_font_init_glyph_path (cairo_win32_scaled_font_t *scaled_font
c2x = 2 * cx / 3 + p2x / 3; c2x = 2 * cx / 3 + p2x / 3;
c2y = 2 * cy / 3 + p2y / 3; c2y = 2 * cy / 3 + p2y / 3;
_cairo_path_fixed_curve_to (path, c1x, c1y, c2x, c2y, p2x, p2y); status = _cairo_path_fixed_curve_to (path, c1x, c1y, c2x, c2y, p2x, p2y);
if (status)
goto CLEANUP_BUFFER;
} }
break; break;
case TT_PRIM_CSPLINE: case TT_PRIM_CSPLINE:
@ -1476,20 +1485,26 @@ _cairo_win32_scaled_font_init_glyph_path (cairo_win32_scaled_font_t *scaled_font
points[i + 2].x, points[i + 2].x,
points[i + 2].y, points[i + 2].y,
&x2, &y2); &x2, &y2);
_cairo_path_fixed_curve_to (path, x, y, x1, y1, x2, y2); status = _cairo_path_fixed_curve_to (path, x, y, x1, y1, x2, y2);
if (status)
goto CLEANUP_BUFFER;
} }
break; break;
} }
ptr += sizeof(TTPOLYCURVE) + sizeof (POINTFX) * (curve->cpfx - 1); ptr += sizeof(TTPOLYCURVE) + sizeof (POINTFX) * (curve->cpfx - 1);
} }
_cairo_path_fixed_close_path (path); status = _cairo_path_fixed_close_path (path);
if (status)
goto CLEANUP_BUFFER;
} }
free(buffer);
_cairo_scaled_glyph_set_path (scaled_glyph, _cairo_scaled_glyph_set_path (scaled_glyph,
&scaled_font->base, &scaled_font->base,
path); path);
CLEANUP_BUFFER:
free (buffer);
CLEANUP_FONT: CLEANUP_FONT:
cairo_win32_scaled_font_done_font (&scaled_font->base); cairo_win32_scaled_font_done_font (&scaled_font->base);
@ -1561,14 +1576,11 @@ _cairo_win32_font_face_scaled_font_create (void *abstract_face,
} }
} }
*font = _win32_scaled_font_create (&font_face->logfont, return _win32_scaled_font_create (&font_face->logfont,
hfont, hfont,
&font_face->base, &font_face->base,
font_matrix, ctm, options); font_matrix, ctm, options,
if (*font) font);
return CAIRO_STATUS_SUCCESS;
else
return CAIRO_STATUS_NO_MEMORY;
} }
static const cairo_font_face_backend_t _cairo_win32_font_face_backend = { static const cairo_font_face_backend_t _cairo_win32_font_face_backend = {
@ -1603,7 +1615,7 @@ cairo_win32_font_face_create_for_logfontw_hfont (LOGFONTW *logfont, HFONT font)
font_face = malloc (sizeof (cairo_win32_font_face_t)); font_face = malloc (sizeof (cairo_win32_font_face_t));
if (!font_face) { if (!font_face) {
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_font_face_t *)&_cairo_font_face_nil; return (cairo_font_face_t *)&_cairo_font_face_nil;
} }
@ -1705,7 +1717,7 @@ cairo_win32_scaled_font_select_font (cairo_scaled_font_t *scaled_font,
hfont = _win32_scaled_font_get_scaled_hfont ((cairo_win32_scaled_font_t *)scaled_font); hfont = _win32_scaled_font_get_scaled_hfont ((cairo_win32_scaled_font_t *)scaled_font);
if (!hfont) if (!hfont)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
old_hfont = SelectObject (hdc, hfont); old_hfont = SelectObject (hdc, hfont);
if (!old_hfont) if (!old_hfont)

View File

@ -1,7 +1,7 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* Cairo - a vector graphics library with display and print output /* Cairo - a vector graphics library with display and print output
* *
* Copyright © 2005 Red Hat, Inc. * Copyright © 2007 Adrian Johnson
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public * modify it either under the terms of the GNU Lesser General Public
@ -28,7 +28,7 @@
* *
* The Original Code is the cairo graphics library. * The Original Code is the cairo graphics library.
* *
* The Initial Developer of the Original Code is Red Hat, Inc. * The Initial Developer of the Original Code is Adrian Johnson.
* *
* Contributor(s): * Contributor(s):
* Adrian Johnson <ajohnson@redneon.com> * Adrian Johnson <ajohnson@redneon.com>
@ -50,6 +50,7 @@
#include "cairo-clip-private.h" #include "cairo-clip-private.h"
#include "cairo-win32-private.h" #include "cairo-win32-private.h"
#include "cairo-meta-surface-private.h"
#include <windows.h> #include <windows.h>
@ -94,11 +95,65 @@ _cairo_win32_printing_surface_init_ps_mode (cairo_win32_surface_t *surface)
surface->flags |= CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT; surface->flags |= CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT;
} }
static cairo_int_status_t
analyze_surface_pattern_transparency (cairo_surface_pattern_t *pattern)
{
cairo_image_surface_t *image;
void *image_extra;
cairo_int_status_t status;
int x, y;
status = _cairo_surface_acquire_source_image (pattern->surface,
&image,
&image_extra);
if (status)
return status;
if (image->base.status)
return image->base.status;
if (image->format == CAIRO_FORMAT_RGB24) {
status = CAIRO_STATUS_SUCCESS;
goto RELEASE_SOURCE;
}
if (image->format != CAIRO_FORMAT_ARGB32) {
/* If the surface does not support the image format, assume
* that it does have alpha. The image will be converted to
* rgb24 when the surface blends the image into the page
* color to remove the transparency. */
status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
goto RELEASE_SOURCE;
}
for (y = 0; y < image->height; y++) {
int a;
uint32_t *pixel = (uint32_t *) (image->data + y * image->stride);
for (x = 0; x < image->width; x++, pixel++) {
a = (*pixel & 0xff000000) >> 24;
if (a != 255) {
status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
goto RELEASE_SOURCE;
}
}
}
status = CAIRO_STATUS_SUCCESS;
RELEASE_SOURCE:
_cairo_surface_release_source_image (pattern->surface, image, image_extra);
return status;
}
static cairo_bool_t static cairo_bool_t
surface_pattern_supported (const cairo_surface_pattern_t *pattern) surface_pattern_supported (const cairo_surface_pattern_t *pattern)
{ {
cairo_extend_t extend; cairo_extend_t extend;
if (_cairo_surface_is_meta (pattern->surface))
return TRUE;
if (cairo_surface_get_type (pattern->surface) != CAIRO_SURFACE_TYPE_WIN32 && if (cairo_surface_get_type (pattern->surface) != CAIRO_SURFACE_TYPE_WIN32 &&
pattern->surface->backend->acquire_source_image == NULL) pattern->surface->backend->acquire_source_image == NULL)
{ {
@ -147,11 +202,10 @@ _cairo_win32_printing_surface_analyze_operation (cairo_win32_surface_t *surface,
op == CAIRO_OPERATOR_CLEAR) op == CAIRO_OPERATOR_CLEAR)
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
/* If IGNORE_OPERATORS was set, then we pretend everything is /* If the operation is anything other than CLEAR, SOURCE, or
* OVER/SOURCE. Otherwise, we go to fallback. * OVER, we have to go to fallback.
*/ */
if (!(surface->flags & CAIRO_WIN32_SURFACE_IGNORE_OPERATORS) && if (op != CAIRO_OPERATOR_OVER)
op != CAIRO_OPERATOR_OVER)
return CAIRO_INT_STATUS_UNSUPPORTED; return CAIRO_INT_STATUS_UNSUPPORTED;
/* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If /* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If
@ -164,11 +218,14 @@ _cairo_win32_printing_surface_analyze_operation (cairo_win32_surface_t *surface,
* background to convert the pattern to opaque. * background to convert the pattern to opaque.
*/ */
if (_cairo_operator_always_opaque (op)) if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
return CAIRO_STATUS_SUCCESS; cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
if (_cairo_operator_always_translucent (op)) if ( _cairo_surface_is_meta (surface_pattern->surface))
return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY; return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN;
else
return analyze_surface_pattern_transparency (surface_pattern);
}
if (_cairo_pattern_is_opaque (pattern)) if (_cairo_pattern_is_opaque (pattern))
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
@ -187,30 +244,56 @@ _cairo_win32_printing_surface_operation_supported (cairo_win32_surface_t *surfac
return FALSE; return FALSE;
} }
static void
_cairo_win32_printing_surface_init_clear_color (cairo_win32_surface_t *surface,
cairo_solid_pattern_t *color)
{
if (surface->content == CAIRO_CONTENT_COLOR_ALPHA)
_cairo_pattern_init_solid (color, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR);
else
_cairo_pattern_init_solid (color, CAIRO_COLOR_BLACK, CAIRO_CONTENT_COLOR);
}
static COLORREF
_cairo_win32_printing_surface_flatten_transparency (cairo_win32_surface_t *surface,
const cairo_color_t *color)
{
COLORREF c;
BYTE red, green, blue;
red = color->red_short >> 8;
green = color->green_short >> 8;
blue = color->blue_short >> 8;
if (!CAIRO_COLOR_IS_OPAQUE(color)) {
if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) {
/* Blend into white */
uint8_t one_minus_alpha = 255 - (color->alpha_short >> 8);
red = (color->red_short >> 8) + one_minus_alpha;
green = (color->green_short >> 8) + one_minus_alpha;
blue = (color->blue_short >> 8) + one_minus_alpha;
} else {
/* Blend into black */
red = (color->red_short >> 8);
green = (color->green_short >> 8);
blue = (color->blue_short >> 8);
}
}
c = RGB (red, green, blue);
return c;
}
static cairo_status_t static cairo_status_t
_cairo_win32_printing_surface_select_solid_brush (cairo_win32_surface_t *surface, _cairo_win32_printing_surface_select_solid_brush (cairo_win32_surface_t *surface,
cairo_pattern_t *source) cairo_pattern_t *source)
{ {
cairo_solid_pattern_t *pattern = (cairo_solid_pattern_t *) source; cairo_solid_pattern_t *pattern = (cairo_solid_pattern_t *) source;
cairo_color_t c = pattern->color;
COLORREF color; COLORREF color;
BYTE red, green, blue;
red = c.red_short >> 8;
green = c.green_short >> 8;
blue = c.blue_short >> 8;
if (!CAIRO_COLOR_IS_OPAQUE(&c)) {
/* Blend into white */
uint8_t one_minus_alpha = 255 - (c.alpha_short >> 8);
red = (c.red_short >> 8) + one_minus_alpha;
green = (c.green_short >> 8) + one_minus_alpha;
blue = (c.blue_short >> 8) + one_minus_alpha;
}
color = RGB (red, green, blue);
color = _cairo_win32_printing_surface_flatten_transparency (surface,
&pattern->color);
surface->brush = CreateSolidBrush (color); surface->brush = CreateSolidBrush (color);
if (!surface->brush) if (!surface->brush)
return _cairo_win32_print_gdi_error ("_cairo_win32_surface_select_solid_brush(CreateSolidBrush)"); return _cairo_win32_print_gdi_error ("_cairo_win32_surface_select_solid_brush(CreateSolidBrush)");
@ -229,6 +312,22 @@ _cairo_win32_printing_surface_done_solid_brush (cairo_win32_surface_t *surface)
} }
} }
static cairo_status_t
_cairo_win32_printing_surface_get_ctm_clip_box (cairo_win32_surface_t *surface,
RECT *clip)
{
XFORM xform;
_cairo_matrix_to_win32_xform (&surface->ctm, &xform);
if (!SetWorldTransform (surface->dc, &xform))
return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_get_clip_box:SetWorldTransform");
GetClipBox (surface->dc, clip);
if (!ModifyWorldTransform (surface->dc, &xform, MWT_IDENTITY))
return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_get_clip_box:ModifyWorldTransform");
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t static cairo_status_t
_cairo_win32_printing_surface_paint_solid_pattern (cairo_win32_surface_t *surface, _cairo_win32_printing_surface_paint_solid_pattern (cairo_win32_surface_t *surface,
cairo_pattern_t *pattern) cairo_pattern_t *pattern)
@ -248,8 +347,135 @@ _cairo_win32_printing_surface_paint_solid_pattern (cairo_win32_surface_t *surfac
} }
static cairo_status_t static cairo_status_t
_cairo_win32_printing_surface_paint_surface_pattern (cairo_win32_surface_t *surface, _cairo_win32_printing_surface_paint_meta_pattern (cairo_win32_surface_t *surface,
cairo_surface_pattern_t *pattern) cairo_surface_pattern_t *pattern)
{
cairo_content_t old_content;
cairo_matrix_t old_ctm;
cairo_bool_t old_has_ctm;
cairo_rectangle_int_t meta_extents;
cairo_status_t status;
cairo_extend_t extend;
cairo_matrix_t p2d;
XFORM xform;
int x_tile, y_tile, left, right, top, bottom;
RECT clip;
cairo_surface_t *meta_surface = pattern->surface;
extend = cairo_pattern_get_extend (&pattern->base);
p2d = pattern->base.matrix;
status = cairo_matrix_invert (&p2d);
/* _cairo_pattern_set_matrix guarantees invertibility */
assert (status == CAIRO_STATUS_SUCCESS);
old_ctm = surface->ctm;
old_has_ctm = surface->has_ctm;
cairo_matrix_multiply (&p2d, &p2d, &surface->ctm);
surface->ctm = p2d;
SaveDC (surface->dc);
_cairo_matrix_to_win32_xform (&p2d, &xform);
status = _cairo_surface_get_extents (meta_surface, &meta_extents);
if (status)
return status;
status = _cairo_win32_printing_surface_get_ctm_clip_box (surface, &clip);
if (status)
return status;
if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT) {
left = (int) floor((double)clip.left/meta_extents.width);
right = (int) ceil((double)clip.right/meta_extents.width);
top = (int) floor((double)clip.top/meta_extents.height);
bottom = (int) ceil((double)clip.bottom/meta_extents.height);
} else {
left = 0;
right = 1;
top = 0;
bottom = 1;
}
old_content = surface->content;
if (cairo_surface_get_content (meta_surface) == CAIRO_CONTENT_COLOR) {
cairo_pattern_t *source;
cairo_solid_pattern_t black;
surface->content = CAIRO_CONTENT_COLOR;
_cairo_pattern_init_solid (&black, CAIRO_COLOR_BLACK, CAIRO_CONTENT_COLOR);
source = (cairo_pattern_t*) &black;
_cairo_win32_printing_surface_paint_solid_pattern (surface, source);
}
for (y_tile = top; y_tile < bottom; y_tile++) {
for (x_tile = left; x_tile < right; x_tile++) {
cairo_matrix_t m;
double x, y;
SaveDC (surface->dc);
m = p2d;
cairo_matrix_translate (&m,
x_tile*meta_extents.width,
y_tile*meta_extents.height);
if (extend == CAIRO_EXTEND_REFLECT) {
if (x_tile % 2) {
cairo_matrix_translate (&m, meta_extents.width, 0);
cairo_matrix_scale (&m, -1, 1);
}
if (y_tile % 2) {
cairo_matrix_translate (&m, 0, meta_extents.height);
cairo_matrix_scale (&m, 1, -1);
}
}
surface->ctm = m;
surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
/* Set clip path around bbox of the pattern. */
BeginPath (surface->dc);
x = 0;
y = 0;
cairo_matrix_transform_point (&surface->ctm, &x, &y);
MoveToEx (surface->dc, (int) x, (int) y, NULL);
x = meta_extents.width;
y = 0;
cairo_matrix_transform_point (&surface->ctm, &x, &y);
LineTo (surface->dc, (int) x, (int) y);
x = meta_extents.width;
y = meta_extents.height;
cairo_matrix_transform_point (&surface->ctm, &x, &y);
LineTo (surface->dc, (int) x, (int) y);
x = 0;
y = meta_extents.height;
cairo_matrix_transform_point (&surface->ctm, &x, &y);
LineTo (surface->dc, (int) x, (int) y);
CloseFigure (surface->dc);
EndPath (surface->dc);
SelectClipPath (surface->dc, RGN_AND);
status = _cairo_meta_surface_replay (meta_surface, &surface->base);
if (status)
return status;
RestoreDC (surface->dc, -1);
}
}
surface->content = old_content;
surface->ctm = old_ctm;
surface->has_ctm = old_has_ctm;
RestoreDC (surface->dc, -1);
return status;
}
static cairo_status_t
_cairo_win32_printing_surface_paint_image_pattern (cairo_win32_surface_t *surface,
cairo_surface_pattern_t *pattern)
{ {
cairo_status_t status; cairo_status_t status;
cairo_extend_t extend; cairo_extend_t extend;
@ -266,13 +492,19 @@ _cairo_win32_printing_surface_paint_surface_pattern (cairo_win32_surface_t *su
XFORM xform; XFORM xform;
int x_tile, y_tile, left, right, top, bottom; int x_tile, y_tile, left, right, top, bottom;
RECT clip; RECT clip;
const cairo_color_t *background_color;
/* If we can't use StretchDIBits with this surface, we can't do anything /* If we can't use StretchDIBits with this surface, we can't do anything
* special here. * here.
*/ */
if (!(surface->flags & CAIRO_WIN32_SURFACE_CAN_STRETCHDIB)) if (!(surface->flags & CAIRO_WIN32_SURFACE_CAN_STRETCHDIB))
return CAIRO_INT_STATUS_UNSUPPORTED; return CAIRO_INT_STATUS_UNSUPPORTED;
if (surface->content == CAIRO_CONTENT_COLOR_ALPHA)
background_color = CAIRO_COLOR_WHITE;
else
background_color = CAIRO_COLOR_BLACK;
extend = cairo_pattern_get_extend (&pattern->base); extend = cairo_pattern_get_extend (&pattern->base);
status = _cairo_pattern_acquire_surface ((cairo_pattern_t *)pattern, status = _cairo_pattern_acquire_surface ((cairo_pattern_t *)pattern,
(cairo_surface_t *)surface, (cairo_surface_t *)surface,
@ -290,8 +522,7 @@ _cairo_win32_printing_surface_paint_surface_pattern (cairo_win32_surface_t *su
goto FINISH2; goto FINISH2;
} }
if (image->width == 0 || image->height == 0) if (image->width == 0 || image->height == 0) {
{
status = CAIRO_STATUS_SUCCESS; status = CAIRO_STATUS_SUCCESS;
goto FINISH2; goto FINISH2;
} }
@ -309,7 +540,7 @@ _cairo_win32_printing_surface_paint_surface_pattern (cairo_win32_surface_t *su
status = _cairo_surface_fill_rectangle (opaque_surface, status = _cairo_surface_fill_rectangle (opaque_surface,
CAIRO_OPERATOR_SOURCE, CAIRO_OPERATOR_SOURCE,
CAIRO_COLOR_WHITE, background_color,
0, 0, 0, 0,
image->width, image->height); image->width, image->height);
if (status) { if (status) {
@ -351,10 +582,12 @@ _cairo_win32_printing_surface_paint_surface_pattern (cairo_win32_surface_t *su
bi.bmiHeader.biClrImportant = 0; bi.bmiHeader.biClrImportant = 0;
m = pattern->base.matrix; m = pattern->base.matrix;
cairo_matrix_invert (&m); status = cairo_matrix_invert (&m);
/* _cairo_pattern_set_matrix guarantees invertibility */
assert (status == CAIRO_STATUS_SUCCESS);
cairo_matrix_multiply (&m, &m, &surface->ctm);
SaveDC (surface->dc); SaveDC (surface->dc);
SetGraphicsMode (surface->dc, GM_ADVANCED);
_cairo_matrix_to_win32_xform (&m, &xform); _cairo_matrix_to_win32_xform (&m, &xform);
if (!SetWorldTransform (surface->dc, &xform)) if (!SetWorldTransform (surface->dc, &xform))
@ -390,7 +623,7 @@ _cairo_win32_printing_surface_paint_surface_pattern (cairo_win32_surface_t *su
&bi, &bi,
DIB_RGB_COLORS, DIB_RGB_COLORS,
SRCCOPY)) SRCCOPY))
return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_paint_surface_pattern(StretchDIBits)"); return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_paint(StretchDIBits)");
} }
} }
SetStretchBltMode(surface->dc, oldmode); SetStretchBltMode(surface->dc, oldmode);
@ -407,13 +640,29 @@ FINISH:
return status; return status;
} }
static cairo_status_t
_cairo_win32_printing_surface_paint_surface_pattern (cairo_win32_surface_t *surface,
cairo_surface_pattern_t *pattern)
{
if (_cairo_surface_is_meta (pattern->surface)) {
return _cairo_win32_printing_surface_paint_meta_pattern (surface,
pattern);
} else {
return _cairo_win32_printing_surface_paint_image_pattern (surface,
pattern);
}
}
static void static void
vertex_set_color (TRIVERTEX *vert, cairo_color_t *color) vertex_set_color (TRIVERTEX *vert, cairo_color_t *color)
{ {
vert->Alpha = 0xffff; /* MSDN says that the range here is 0x0000 .. 0xff00;
vert->Red = color->red_short; * that may well be a typo, but just chop the low bits
vert->Green = color->green_short; * here. */
vert->Blue = color->blue_short; vert->Alpha = 0xff00;
vert->Red = color->red_short & 0xff00;
vert->Green = color->green_short & 0xff00;
vert->Blue = color->blue_short & 0xff00;
} }
static cairo_int_status_t static cairo_int_status_t
@ -430,12 +679,17 @@ _cairo_win32_printing_surface_paint_linear_pattern (cairo_win32_surface_t *surfa
cairo_extend_t extend; cairo_extend_t extend;
int range_start, range_stop, num_ranges, num_rects, stop; int range_start, range_stop, num_ranges, num_rects, stop;
int total_verts, total_rects; int total_verts, total_rects;
cairo_status_t status;
extend = cairo_pattern_get_extend (&pattern->base.base); extend = cairo_pattern_get_extend (&pattern->base.base);
SaveDC (surface->dc); SaveDC (surface->dc);
mat = pattern->base.base.matrix; mat = pattern->base.base.matrix;
cairo_matrix_invert (&mat); status = cairo_matrix_invert (&mat);
/* _cairo_pattern_set_matrix guarantees invertibility */
assert (status == CAIRO_STATUS_SUCCESS);
cairo_matrix_multiply (&mat, &surface->ctm, &mat);
p1x = _cairo_fixed_to_double (pattern->p1.x); p1x = _cairo_fixed_to_double (pattern->p1.x);
p1y = _cairo_fixed_to_double (pattern->p1.y); p1y = _cairo_fixed_to_double (pattern->p1.y);
@ -456,16 +710,11 @@ _cairo_win32_printing_surface_paint_linear_pattern (cairo_win32_surface_t *surfa
_cairo_matrix_to_win32_xform (&mat, &xform); _cairo_matrix_to_win32_xform (&mat, &xform);
SetGraphicsMode (surface->dc, GM_ADVANCED);
if (!SetWorldTransform (surface->dc, &xform)) if (!SetWorldTransform (surface->dc, &xform))
return _cairo_win32_print_gdi_error ("_win32_printing_surface_paint_linear_pattern:SetWorldTransform2"); return _cairo_win32_print_gdi_error ("_win32_printing_surface_paint_linear_pattern:SetWorldTransform2");
GetWorldTransform(surface->dc, &xform);
p1x = 0.0;
p1y = 0.0;
p2x = d;
p2y = 0;
GetClipBox (surface->dc, &clip); GetClipBox (surface->dc, &clip);
if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT) { if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT) {
range_start = (int) floor(clip.left/d); range_start = (int) floor(clip.left/d);
range_stop = (int) ceil(clip.right/d); range_stop = (int) ceil(clip.right/d);
@ -596,9 +845,6 @@ _cairo_win32_printing_surface_paint_pattern (cairo_win32_surface_t *surface,
typedef struct _win32_print_path_info { typedef struct _win32_print_path_info {
cairo_win32_surface_t *surface; cairo_win32_surface_t *surface;
cairo_line_cap_t line_cap;
cairo_point_t last_move_to_point;
cairo_bool_t has_sub_path;
} win32_path_info_t; } win32_path_info_t;
static cairo_status_t static cairo_status_t
@ -606,13 +852,19 @@ _cairo_win32_printing_surface_path_move_to (void *closure, cairo_point_t *point)
{ {
win32_path_info_t *path_info = closure; win32_path_info_t *path_info = closure;
path_info->last_move_to_point = *point; if (path_info->surface->has_ctm) {
path_info->has_sub_path = FALSE; double x, y;
MoveToEx (path_info->surface->dc, x = _cairo_fixed_to_double (point->x);
_cairo_fixed_integer_part (point->x), y = _cairo_fixed_to_double (point->y);
_cairo_fixed_integer_part (point->y), cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y);
NULL); MoveToEx (path_info->surface->dc, (int) x, (int) y, NULL);
} else {
MoveToEx (path_info->surface->dc,
_cairo_fixed_integer_part (point->x),
_cairo_fixed_integer_part (point->y),
NULL);
}
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -622,9 +874,18 @@ _cairo_win32_printing_surface_path_line_to (void *closure, cairo_point_t *point)
{ {
win32_path_info_t *path_info = closure; win32_path_info_t *path_info = closure;
LineTo (path_info->surface->dc, if (path_info->surface->has_ctm) {
_cairo_fixed_integer_part (point->x), double x, y;
_cairo_fixed_integer_part (point->y));
x = _cairo_fixed_to_double (point->x);
y = _cairo_fixed_to_double (point->y);
cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y);
LineTo (path_info->surface->dc, (int) x, (int) y);
} else {
LineTo (path_info->surface->dc,
_cairo_fixed_integer_part (point->x),
_cairo_fixed_integer_part (point->y));
}
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -638,12 +899,34 @@ _cairo_win32_printing_surface_path_curve_to (void *closure,
win32_path_info_t *path_info = closure; win32_path_info_t *path_info = closure;
POINT points[3]; POINT points[3];
points[0].x = _cairo_fixed_integer_part (b->x); if (path_info->surface->has_ctm) {
points[0].y = _cairo_fixed_integer_part (b->y); double x, y;
points[1].x = _cairo_fixed_integer_part (c->x);
points[1].y = _cairo_fixed_integer_part (c->y); x = _cairo_fixed_to_double (b->x);
points[2].x = _cairo_fixed_integer_part (d->x); y = _cairo_fixed_to_double (b->y);
points[2].y = _cairo_fixed_integer_part (d->y); cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y);
points[0].x = (LONG) x;
points[0].y = (LONG) y;
x = _cairo_fixed_to_double (c->x);
y = _cairo_fixed_to_double (c->y);
cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y);
points[1].x = (LONG) x;
points[1].y = (LONG) y;
x = _cairo_fixed_to_double (d->x);
y = _cairo_fixed_to_double (d->y);
cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y);
points[2].x = (LONG) x;
points[2].y = (LONG) y;
} else {
points[0].x = _cairo_fixed_integer_part (b->x);
points[0].y = _cairo_fixed_integer_part (b->y);
points[1].x = _cairo_fixed_integer_part (c->x);
points[1].y = _cairo_fixed_integer_part (c->y);
points[2].x = _cairo_fixed_integer_part (d->x);
points[2].y = _cairo_fixed_integer_part (d->y);
}
PolyBezierTo (path_info->surface->dc, points, 3); PolyBezierTo (path_info->surface->dc, points, 3);
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
@ -749,11 +1032,11 @@ _cairo_win32_printing_surface_paint (void *abstract_surface,
cairo_pattern_t *source) cairo_pattern_t *source)
{ {
cairo_win32_surface_t *surface = abstract_surface; cairo_win32_surface_t *surface = abstract_surface;
cairo_solid_pattern_t white; cairo_solid_pattern_t clear;
if (op == CAIRO_OPERATOR_CLEAR) { if (op == CAIRO_OPERATOR_CLEAR) {
_cairo_pattern_init_solid (&white, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR); _cairo_win32_printing_surface_init_clear_color (surface, &clear);
source = (cairo_pattern_t*) &white; source = (cairo_pattern_t*) &clear;
op = CAIRO_OPERATOR_SOURCE; op = CAIRO_OPERATOR_SOURCE;
} }
@ -797,14 +1080,31 @@ _cairo_win32_line_join (cairo_line_join_t join)
} }
} }
static void
_cairo_matrix_factor_out_scale (cairo_matrix_t *m, double *scale)
{
double s;
s = fabs (m->xx);
if (fabs (m->xy) > s)
s = fabs (m->xy);
if (fabs (m->yx) > s)
s = fabs (m->yx);
if (fabs (m->yy) > s)
s = fabs (m->yy);
*scale = s;
s = 1.0/s;
cairo_matrix_scale (m, s, s);
}
static cairo_int_status_t static cairo_int_status_t
_cairo_win32_printing_surface_stroke (void *abstract_surface, _cairo_win32_printing_surface_stroke (void *abstract_surface,
cairo_operator_t op, cairo_operator_t op,
cairo_pattern_t *source, cairo_pattern_t *source,
cairo_path_fixed_t *path, cairo_path_fixed_t *path,
cairo_stroke_style_t *style, cairo_stroke_style_t *style,
cairo_matrix_t *ctm, cairo_matrix_t *stroke_ctm,
cairo_matrix_t *ctm_inverse, cairo_matrix_t *stroke_ctm_inverse,
double tolerance, double tolerance,
cairo_antialias_t antialias) cairo_antialias_t antialias)
{ {
@ -818,11 +1118,13 @@ _cairo_win32_printing_surface_stroke (void *abstract_surface,
DWORD *dash_array; DWORD *dash_array;
HGDIOBJ obj; HGDIOBJ obj;
unsigned int i; unsigned int i;
cairo_solid_pattern_t white; cairo_solid_pattern_t clear;
cairo_matrix_t mat;
double scale;
if (op == CAIRO_OPERATOR_CLEAR) { if (op == CAIRO_OPERATOR_CLEAR) {
_cairo_pattern_init_solid (&white, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR); _cairo_win32_printing_surface_init_clear_color (surface, &clear);
source = (cairo_pattern_t*) &white; source = (cairo_pattern_t*) &clear;
op = CAIRO_OPERATOR_SOURCE; op = CAIRO_OPERATOR_SOURCE;
} }
@ -835,33 +1137,30 @@ _cairo_win32_printing_surface_stroke (void *abstract_surface,
} }
assert (_cairo_win32_printing_surface_operation_supported (surface, op, source)); assert (_cairo_win32_printing_surface_operation_supported (surface, op, source));
assert (!(style->num_dashes > 0 && style->dash_offset != 0.0));
cairo_matrix_multiply (&mat, stroke_ctm, &surface->ctm);
_cairo_matrix_factor_out_scale (&mat, &scale);
pen_style = PS_GEOMETRIC;
dash_array = NULL; dash_array = NULL;
if (style->num_dashes) { if (style->num_dashes) {
pen_style = PS_USERSTYLE; pen_style |= PS_USERSTYLE;
dash_array = calloc (sizeof (DWORD), style->num_dashes); dash_array = calloc (sizeof (DWORD), style->num_dashes);
for (i = 0; i < style->num_dashes; i++) { for (i = 0; i < style->num_dashes; i++) {
dash_array[i] = (DWORD) style->dash[i]; dash_array[i] = (DWORD) (scale * style->dash[i]);
} }
} else { } else {
pen_style = PS_SOLID; pen_style |= PS_SOLID;
} }
SetMiterLimit (surface->dc, (FLOAT) style->miter_limit, NULL); SetMiterLimit (surface->dc, (FLOAT) (scale * style->miter_limit), NULL);
if (source->type == CAIRO_PATTERN_TYPE_SOLID) { if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source; cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
cairo_color_t c = solid->color;
if (!CAIRO_COLOR_IS_OPAQUE(&c)) {
/* Blend into white */
c.red = c.red*c.alpha + 1 - c.alpha;
c.green = c.green*c.alpha + 1 - c.alpha;
c.blue = c.blue*c.alpha + 1 - c.alpha;
}
color = RGB ((BYTE)(c.red*255), color = _cairo_win32_printing_surface_flatten_transparency (surface,
(BYTE)(c.green*255), &solid->color);
(BYTE)(c.blue*255));
} else { } else {
/* Color not used as the pen will only be used by WidenPath() */ /* Color not used as the pen will only be used by WidenPath() */
color = RGB (0,0,0); color = RGB (0,0,0);
@ -869,11 +1168,10 @@ _cairo_win32_printing_surface_stroke (void *abstract_surface,
brush.lbStyle = BS_SOLID; brush.lbStyle = BS_SOLID;
brush.lbColor = color; brush.lbColor = color;
brush.lbHatch = 0; brush.lbHatch = 0;
pen_style = PS_GEOMETRIC | pen_style |= _cairo_win32_line_cap (style->line_cap);
_cairo_win32_line_cap (style->line_cap) | pen_style |= _cairo_win32_line_join (style->line_join);
_cairo_win32_line_join (style->line_join);
pen = ExtCreatePen(pen_style, pen = ExtCreatePen(pen_style,
style->line_width < 1.0 ? 1 : _cairo_lround(style->line_width), scale * style->line_width,
&brush, &brush,
style->num_dashes, style->num_dashes,
dash_array); dash_array);
@ -893,8 +1191,8 @@ _cairo_win32_printing_surface_stroke (void *abstract_surface,
* Switch to user space to set line parameters * Switch to user space to set line parameters
*/ */
SaveDC (surface->dc); SaveDC (surface->dc);
SetGraphicsMode (surface->dc, GM_ADVANCED);
_cairo_matrix_to_win32_xform (ctm, &xform); _cairo_matrix_to_win32_xform (&mat, &xform);
xform.eDx = 0.0f; xform.eDx = 0.0f;
xform.eDy = 0.0f; xform.eDy = 0.0f;
@ -912,7 +1210,7 @@ _cairo_win32_printing_surface_stroke (void *abstract_surface,
/* Return to device space to paint the pattern */ /* Return to device space to paint the pattern */
if (!ModifyWorldTransform (surface->dc, &xform, MWT_IDENTITY)) if (!ModifyWorldTransform (surface->dc, &xform, MWT_IDENTITY))
return _cairo_win32_print_gdi_error ("_win32_surface_stroke:ModifyWorldTransform"); return _cairo_win32_print_gdi_error ("_win32_surface_stroke:ModifyWorldTransform");
_cairo_win32_printing_surface_paint_pattern (surface, source); status = _cairo_win32_printing_surface_paint_pattern (surface, source);
} }
RestoreDC (surface->dc, -1); RestoreDC (surface->dc, -1);
DeleteObject (pen); DeleteObject (pen);
@ -933,11 +1231,11 @@ _cairo_win32_printing_surface_fill (void *abstract_surface,
{ {
cairo_win32_surface_t *surface = abstract_surface; cairo_win32_surface_t *surface = abstract_surface;
cairo_int_status_t status; cairo_int_status_t status;
cairo_solid_pattern_t white; cairo_solid_pattern_t clear;
if (op == CAIRO_OPERATOR_CLEAR) { if (op == CAIRO_OPERATOR_CLEAR) {
_cairo_pattern_init_solid (&white, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR); _cairo_win32_printing_surface_init_clear_color (surface, &clear);
source = (cairo_pattern_t*) &white; source = (cairo_pattern_t*) &clear;
op = CAIRO_OPERATOR_SOURCE; op = CAIRO_OPERATOR_SOURCE;
} }
@ -962,13 +1260,16 @@ _cairo_win32_printing_surface_fill (void *abstract_surface,
} }
if (source->type == CAIRO_PATTERN_TYPE_SOLID) { if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
_cairo_win32_printing_surface_select_solid_brush (surface, source); status = _cairo_win32_printing_surface_select_solid_brush (surface, source);
if (status)
return status;
FillPath (surface->dc); FillPath (surface->dc);
_cairo_win32_printing_surface_done_solid_brush (surface); _cairo_win32_printing_surface_done_solid_brush (surface);
} else { } else {
SaveDC (surface->dc); SaveDC (surface->dc);
SelectClipPath (surface->dc, RGN_AND); SelectClipPath (surface->dc, RGN_AND);
_cairo_win32_printing_surface_paint_pattern (surface, source); status = _cairo_win32_printing_surface_paint_pattern (surface, source);
RestoreDC (surface->dc, -1); RestoreDC (surface->dc, -1);
} }
@ -990,12 +1291,13 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac
cairo_scaled_glyph_t *scaled_glyph; cairo_scaled_glyph_t *scaled_glyph;
cairo_pattern_t *opaque = NULL; cairo_pattern_t *opaque = NULL;
int i; int i;
XFORM xform; cairo_matrix_t old_ctm;
cairo_solid_pattern_t white; cairo_bool_t old_has_ctm;
cairo_solid_pattern_t clear;
if (op == CAIRO_OPERATOR_CLEAR) { if (op == CAIRO_OPERATOR_CLEAR) {
_cairo_pattern_init_solid (&white, CAIRO_COLOR_WHITE, CAIRO_CONTENT_COLOR); _cairo_win32_printing_surface_init_clear_color (surface, &clear);
source = (cairo_pattern_t*) &white; source = (cairo_pattern_t*) &clear;
op = CAIRO_OPERATOR_SOURCE; op = CAIRO_OPERATOR_SOURCE;
} }
@ -1017,16 +1319,13 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac
if (source->type == CAIRO_PATTERN_TYPE_SOLID) { if (source->type == CAIRO_PATTERN_TYPE_SOLID) {
cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source; cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source;
cairo_color_t c = solid->color; COLORREF color;
if (!CAIRO_COLOR_IS_OPAQUE(&c)) { color = _cairo_win32_printing_surface_flatten_transparency (surface,
/* Blend into white */ &solid->color);
c.red = c.red*c.alpha + 1 - c.alpha; opaque = cairo_pattern_create_rgb (GetRValue (color),
c.green = c.green*c.alpha + 1 - c.alpha; GetGValue (color),
c.blue = c.blue*c.alpha + 1 - c.alpha; GetBValue (color));
}
opaque = cairo_pattern_create_rgb (c.red, c.green, c.blue);
if (opaque->status) if (opaque->status)
return opaque->status; return opaque->status;
source = opaque; source = opaque;
@ -1035,18 +1334,30 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac
if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_WIN32 && if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_WIN32 &&
source->type == CAIRO_PATTERN_TYPE_SOLID) source->type == CAIRO_PATTERN_TYPE_SOLID)
{ {
cairo_matrix_t ctm;
if (surface->has_ctm) {
for (i = 0; i < num_glyphs; i++)
cairo_matrix_transform_point (&surface->ctm, &glyphs[i].x, &glyphs[i].y);
cairo_matrix_multiply (&ctm, &scaled_font->ctm, &surface->ctm);
scaled_font = cairo_scaled_font_create (scaled_font->font_face,
&scaled_font->font_matrix,
&ctm,
&scaled_font->options);
}
status = _cairo_win32_surface_show_glyphs (surface, op, status = _cairo_win32_surface_show_glyphs (surface, op,
source, glyphs, source, glyphs,
num_glyphs, scaled_font); num_glyphs, scaled_font);
if (surface->has_ctm)
cairo_scaled_font_destroy (scaled_font);
return status; return status;
} }
SaveDC (surface->dc); SaveDC (surface->dc);
SetGraphicsMode (surface->dc, GM_ADVANCED); old_ctm = surface->ctm;
xform.eM11 = 1.0f; old_has_ctm = surface->has_ctm;
xform.eM21 = 0.0f; surface->has_ctm = TRUE;
xform.eM12 = 0.0f;
xform.eM22 = 1.0f;
BeginPath (surface->dc); BeginPath (surface->dc);
for (i = 0; i < num_glyphs; i++) { for (i = 0; i < num_glyphs; i++) {
status = _cairo_scaled_glyph_lookup (scaled_font, status = _cairo_scaled_glyph_lookup (scaled_font,
@ -1055,16 +1366,16 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac
&scaled_glyph); &scaled_glyph);
if (status) if (status)
break; break;
xform.eDx = (FLOAT) glyphs[i].x; surface->ctm = old_ctm;
xform.eDy = (FLOAT) glyphs[i].y; cairo_matrix_translate (&surface->ctm, glyphs[i].x, glyphs[i].y);
if (!SetWorldTransform (surface->dc, &xform))
return _cairo_win32_print_gdi_error ("_win32_surface_print_show_glyphs:SetWorldTransform");
status = _cairo_win32_printing_surface_emit_path (surface, scaled_glyph->path); status = _cairo_win32_printing_surface_emit_path (surface, scaled_glyph->path);
} }
EndPath (surface->dc); EndPath (surface->dc);
if (status == 0) { surface->ctm = old_ctm;
surface->has_ctm = old_has_ctm;
if (status == CAIRO_STATUS_SUCCESS) {
SelectClipPath (surface->dc, RGN_AND); SelectClipPath (surface->dc, RGN_AND);
_cairo_win32_printing_surface_paint_pattern (surface, source); status = _cairo_win32_printing_surface_paint_pattern (surface, source);
} }
RestoreDC (surface->dc, -1); RestoreDC (surface->dc, -1);
@ -1074,12 +1385,33 @@ _cairo_win32_printing_surface_show_glyphs (void *abstract_surfac
return status; return status;
} }
static cairo_surface_t *
_cairo_win32_printing_surface_create_similar (void *abstract_surface,
cairo_content_t content,
int width,
int height)
{
return _cairo_meta_surface_create (content, width, height);
}
static cairo_int_status_t static cairo_int_status_t
_cairo_win32_printing_surface_start_page (void *abstract_surface) _cairo_win32_printing_surface_start_page (void *abstract_surface)
{ {
cairo_win32_surface_t *surface = abstract_surface; cairo_win32_surface_t *surface = abstract_surface;
XFORM xform;
SaveDC (surface->dc); SaveDC (surface->dc);
SetGraphicsMode (surface->dc, GM_ADVANCED);
GetWorldTransform(surface->dc, &xform);
surface->ctm.xx = xform.eM11;
surface->ctm.xy = xform.eM21;
surface->ctm.yx = xform.eM12;
surface->ctm.yy = xform.eM22;
surface->ctm.x0 = xform.eDx;
surface->ctm.y0 = xform.eDy;
surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
if (!ModifyWorldTransform (surface->dc, NULL, MWT_IDENTITY))
return _cairo_win32_print_gdi_error ("_cairo_win32_printing_surface_start_page:ModifyWorldTransform");
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -1096,8 +1428,6 @@ _cairo_win32_printing_surface_set_paginated_mode (void *abstract_surface,
/** /**
* cairo_win32_printing_surface_create: * cairo_win32_printing_surface_create:
* @hdc: the DC to create a surface for * @hdc: the DC to create a surface for
* @ignore_operators: whether operators other than CLEAR and OVER
* should be treated as SOURCE
* *
* Creates a cairo surface that targets the given DC. The DC will be * 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 * queried for its initial clip extents, and this will be used as the
@ -1106,16 +1436,13 @@ _cairo_win32_printing_surface_set_paginated_mode (void *abstract_surface,
* possible to draw to the surface. * possible to draw to the surface.
* *
* The returned surface will be wrapped using the paginated surface to * The returned surface will be wrapped using the paginated surface to
* provide correct complex renderinf behaviour; show_page() and * provide correct complex rendering behaviour; show_page() and
* associated methods must be used for correct output. * associated methods must be used for correct output.
* *
* If ignore_operators is TRUE, the rendering may be incorrect;
* however, the chances of hitting fallback code are much reduced.
*
* Return value: the newly created surface * Return value: the newly created surface
**/ **/
cairo_surface_t * cairo_surface_t *
cairo_win32_printing_surface_create (HDC hdc, cairo_bool_t ignore_operators) cairo_win32_printing_surface_create (HDC hdc)
{ {
cairo_win32_surface_t *surface; cairo_win32_surface_t *surface;
RECT rect; RECT rect;
@ -1126,18 +1453,19 @@ cairo_win32_printing_surface_create (HDC hdc, cairo_bool_t ignore_operators)
if (GetClipBox (hdc, &rect) == ERROR) { if (GetClipBox (hdc, &rect) == ERROR) {
_cairo_win32_print_gdi_error ("cairo_win32_surface_create"); _cairo_win32_print_gdi_error ("cairo_win32_surface_create");
/* XXX: Can we make a more reasonable guess at the error cause here? */ /* XXX: Can we make a more reasonable guess at the error cause here? */
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NIL_SURFACE; return NIL_SURFACE;
} }
surface = malloc (sizeof (cairo_win32_surface_t)); surface = malloc (sizeof (cairo_win32_surface_t));
if (surface == NULL) { if (surface == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NIL_SURFACE; return NIL_SURFACE;
} }
surface->image = NULL; surface->image = NULL;
surface->format = CAIRO_FORMAT_RGB24; surface->format = CAIRO_FORMAT_RGB24;
surface->content = CAIRO_CONTENT_COLOR_ALPHA;
surface->dc = hdc; surface->dc = hdc;
surface->bitmap = NULL; surface->bitmap = NULL;
@ -1167,8 +1495,6 @@ cairo_win32_printing_surface_create (HDC hdc, cairo_bool_t ignore_operators)
surface->flags = _cairo_win32_flags_for_dc (surface->dc); surface->flags = _cairo_win32_flags_for_dc (surface->dc);
surface->flags |= CAIRO_WIN32_SURFACE_FOR_PRINTING; surface->flags |= CAIRO_WIN32_SURFACE_FOR_PRINTING;
if (ignore_operators)
surface->flags |= CAIRO_WIN32_SURFACE_IGNORE_OPERATORS;
surface->clip_saved_dc = 0; surface->clip_saved_dc = 0;
_cairo_win32_printing_surface_init_ps_mode (surface); _cairo_win32_printing_surface_init_ps_mode (surface);
@ -1194,7 +1520,7 @@ _cairo_surface_is_win32_printing (cairo_surface_t *surface)
static const cairo_surface_backend_t cairo_win32_printing_surface_backend = { static const cairo_surface_backend_t cairo_win32_printing_surface_backend = {
CAIRO_SURFACE_TYPE_WIN32_PRINTING, CAIRO_SURFACE_TYPE_WIN32_PRINTING,
_cairo_win32_surface_create_similar, _cairo_win32_printing_surface_create_similar,
_cairo_win32_surface_finish, _cairo_win32_surface_finish,
NULL, /* acquire_source_image */ NULL, /* acquire_source_image */
NULL, /* release_source_image */ NULL, /* release_source_image */
@ -1224,9 +1550,11 @@ static const cairo_surface_backend_t cairo_win32_printing_surface_backend = {
NULL, /* snapshot */ NULL, /* snapshot */
NULL, /* is_similar */ NULL, /* is_similar */
NULL, /* reset */ NULL, /* reset */
NULL, /* fill_stroke */
}; };
static const cairo_paginated_surface_backend_t cairo_win32_surface_paginated_backend = { static const cairo_paginated_surface_backend_t cairo_win32_surface_paginated_backend = {
_cairo_win32_printing_surface_start_page, _cairo_win32_printing_surface_start_page,
_cairo_win32_printing_surface_set_paginated_mode _cairo_win32_printing_surface_set_paginated_mode,
NULL, /* set_bounding_box */
}; };

View File

@ -82,6 +82,9 @@ typedef struct _cairo_win32_surface {
/* printing surface bits */ /* printing surface bits */
cairo_paginated_mode_t paginated_mode; cairo_paginated_mode_t paginated_mode;
cairo_content_t content;
cairo_bool_t has_ctm;
cairo_matrix_t ctm;
int clip_saved_dc; int clip_saved_dc;
HBRUSH brush, old_brush; HBRUSH brush, old_brush;
} cairo_win32_surface_t; } cairo_win32_surface_t;
@ -108,11 +111,6 @@ enum {
/* Whether we can use GradientFill rectangles with this surface */ /* Whether we can use GradientFill rectangles with this surface */
CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT = (1<<6), CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT = (1<<6),
/* If we should treat all operators other than CLEAR and OVER
* like SOURCE to avoid hitting fallback. Ignored except
* for printing. */
CAIRO_WIN32_SURFACE_IGNORE_OPERATORS = (1<<7)
}; };
cairo_status_t cairo_status_t

View File

@ -105,7 +105,7 @@ _cairo_win32_print_gdi_error (const char *context)
* is no CAIRO_STATUS_UNKNOWN_ERROR. * is no CAIRO_STATUS_UNKNOWN_ERROR.
*/ */
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
uint32_t uint32_t
@ -151,7 +151,7 @@ _create_dc_and_bitmap (cairo_win32_surface_t *surface,
cairo_format_t format, cairo_format_t format,
int width, int width,
int height, int height,
char **bits_out, unsigned char **bits_out,
int *rowstride_out) int *rowstride_out)
{ {
cairo_status_t status; cairo_status_t status;
@ -188,7 +188,7 @@ _create_dc_and_bitmap (cairo_win32_surface_t *surface,
if (num_palette > 2) { if (num_palette > 2) {
bitmap_info = _cairo_malloc_ab_plus_c (num_palette, sizeof(RGBQUAD), sizeof(BITMAPINFOHEADER)); bitmap_info = _cairo_malloc_ab_plus_c (num_palette, sizeof(RGBQUAD), sizeof(BITMAPINFOHEADER));
if (!bitmap_info) if (!bitmap_info)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} else { } else {
bitmap_info = (BITMAPINFO *)&bmi_stack; bitmap_info = (BITMAPINFO *)&bmi_stack;
} }
@ -329,12 +329,12 @@ _cairo_win32_surface_create_for_dc (HDC original_dc,
{ {
cairo_status_t status; cairo_status_t status;
cairo_win32_surface_t *surface; cairo_win32_surface_t *surface;
char *bits; unsigned char *bits;
int rowstride; int rowstride;
surface = malloc (sizeof (cairo_win32_surface_t)); surface = malloc (sizeof (cairo_win32_surface_t));
if (surface == NULL) { if (surface == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NIL_SURFACE; return NIL_SURFACE;
} }
@ -347,7 +347,7 @@ _cairo_win32_surface_create_for_dc (HDC original_dc,
surface->image = cairo_image_surface_create_for_data (bits, format, surface->image = cairo_image_surface_create_for_data (bits, format,
width, height, rowstride); width, height, rowstride);
if (surface->image->status) { if (surface->image->status) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto FAIL; goto FAIL;
} }
@ -376,13 +376,7 @@ _cairo_win32_surface_create_for_dc (HDC original_dc,
if (surface) if (surface)
free (surface); free (surface);
if (status == CAIRO_STATUS_NO_MEMORY) { return NIL_SURFACE;
_cairo_error (CAIRO_STATUS_NO_MEMORY);
return NIL_SURFACE;
} else {
_cairo_error (status);
return NIL_SURFACE;
}
} }
static cairo_surface_t * static cairo_surface_t *
@ -524,7 +518,7 @@ _cairo_win32_surface_get_subimage (cairo_win32_surface_t *surface,
(cairo_win32_surface_t *) _cairo_win32_surface_create_similar_internal (cairo_win32_surface_t *) _cairo_win32_surface_create_similar_internal
(surface, content, width, height, TRUE); (surface, content, width, height, TRUE);
if (local->base.status) if (local->base.status)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = CAIRO_INT_STATUS_UNSUPPORTED; status = CAIRO_INT_STATUS_UNSUPPORTED;
@ -1431,7 +1425,7 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
cairo_region_t *region) cairo_region_t *region)
{ {
cairo_win32_surface_t *surface = abstract_surface; cairo_win32_surface_t *surface = abstract_surface;
cairo_status_t status; cairo_status_t status = CAIRO_STATUS_SUCCESS;
/* If we are in-memory, then we set the clip on the image surface /* If we are in-memory, then we set the clip on the image surface
* as well as on the underlying GDI surface. * as well as on the underlying GDI surface.
@ -1440,7 +1434,9 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
unsigned int serial; unsigned int serial;
serial = _cairo_surface_allocate_clip_serial (surface->image); serial = _cairo_surface_allocate_clip_serial (surface->image);
_cairo_surface_set_clip_region (surface->image, region, serial); status = _cairo_surface_set_clip_region (surface->image, region, serial);
if (status)
return status;
} }
/* The semantics we want is that any clip set by cairo combines /* The semantics we want is that any clip set by cairo combines
@ -1454,8 +1450,7 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
if (SelectClipRgn (surface->dc, surface->saved_clip) == ERROR) if (SelectClipRgn (surface->dc, surface->saved_clip) == ERROR)
return _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region (reset)"); return _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region (reset)");
return CAIRO_STATUS_SUCCESS; status = CAIRO_STATUS_SUCCESS;
} else { } else {
cairo_rectangle_int_t extents; cairo_rectangle_int_t extents;
cairo_box_int_t *boxes; cairo_box_int_t *boxes;
@ -1469,8 +1464,9 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
/* Create a GDI region for the cairo region */ /* Create a GDI region for the cairo region */
_cairo_region_get_extents (region, &extents); _cairo_region_get_extents (region, &extents);
if (_cairo_region_get_boxes (region, &num_boxes, &boxes) != CAIRO_STATUS_SUCCESS) status = _cairo_region_get_boxes (region, &num_boxes, &boxes);
return CAIRO_STATUS_NO_MEMORY; if (status)
return status;
if (num_boxes == 1 && if (num_boxes == 1 &&
boxes[0].p1.x == 0 && boxes[0].p1.x == 0 &&
@ -1486,12 +1482,14 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
boxes[0].p1.y, boxes[0].p1.y,
boxes[0].p2.x, boxes[0].p2.x,
boxes[0].p2.y); boxes[0].p2.y);
_cairo_region_boxes_fini (region, boxes);
} else { } else {
data_size = sizeof (RGNDATAHEADER) + num_boxes * sizeof (RECT); data_size = sizeof (RGNDATAHEADER) + num_boxes * sizeof (RECT);
data = malloc (data_size); data = malloc (data_size);
if (!data) { if (!data) {
_cairo_region_boxes_fini (region, boxes); _cairo_region_boxes_fini (region, boxes);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error(CAIRO_STATUS_NO_MEMORY);
} }
rects = (RECT *)data->Buffer; rects = (RECT *)data->Buffer;
@ -1511,35 +1509,31 @@ _cairo_win32_surface_set_clip_region (void *abstract_surface,
rects[i].bottom = boxes[i].p2.y; rects[i].bottom = boxes[i].p2.y;
} }
_cairo_region_boxes_fini (region, boxes);
gdi_region = ExtCreateRegion (NULL, data_size, data); gdi_region = ExtCreateRegion (NULL, data_size, data);
free (data); free (data);
if (!gdi_region) if (!gdi_region)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
/* Combine the new region with the original clip */ /* Combine the new region with the original clip */
if (surface->saved_clip) { if (surface->saved_clip) {
if (CombineRgn (gdi_region, gdi_region, surface->saved_clip, RGN_AND) == ERROR) if (CombineRgn (gdi_region, gdi_region, surface->saved_clip, RGN_AND) == ERROR)
goto FAIL; status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
} }
if (SelectClipRgn (surface->dc, gdi_region) == ERROR) /* Then select the new clip region into our surface if everything went ok */
goto FAIL; if (status == CAIRO_STATUS_SUCCESS) {
if (SelectClipRgn (surface->dc, gdi_region) == ERROR)
status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
}
DeleteObject (gdi_region); DeleteObject (gdi_region);
} }
_cairo_region_boxes_fini (region, boxes);
return CAIRO_STATUS_SUCCESS;
FAIL:
status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
if (gdi_region)
DeleteObject (gdi_region);
return status;
} }
return status;
} }
cairo_int_status_t cairo_int_status_t
@ -1726,7 +1720,7 @@ cairo_win32_surface_create (HDC hdc)
if (clipBoxType == ERROR) { if (clipBoxType == ERROR) {
_cairo_win32_print_gdi_error ("cairo_win32_surface_create"); _cairo_win32_print_gdi_error ("cairo_win32_surface_create");
/* XXX: Can we make a more reasonable guess at the error cause here? */ /* XXX: Can we make a more reasonable guess at the error cause here? */
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NIL_SURFACE; return NIL_SURFACE;
} }
@ -1744,7 +1738,7 @@ cairo_win32_surface_create (HDC hdc)
format = CAIRO_FORMAT_A1; format = CAIRO_FORMAT_A1;
else { else {
_cairo_win32_print_gdi_error("cairo_win32_surface_create(bad BITSPIXEL)"); _cairo_win32_print_gdi_error("cairo_win32_surface_create(bad BITSPIXEL)");
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NIL_SURFACE; return NIL_SURFACE;
} }
} else { } else {
@ -1753,7 +1747,7 @@ cairo_win32_surface_create (HDC hdc)
surface = malloc (sizeof (cairo_win32_surface_t)); surface = malloc (sizeof (cairo_win32_surface_t));
if (surface == NULL) { if (surface == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return NIL_SURFACE; return NIL_SURFACE;
} }
@ -1859,7 +1853,7 @@ cairo_win32_surface_create_with_ddb (HDC hdc,
ddb_dc = CreateCompatibleDC (hdc); ddb_dc = CreateCompatibleDC (hdc);
if (ddb_dc == NULL) { if (ddb_dc == NULL) {
_cairo_win32_print_gdi_error("CreateCompatibleDC"); _cairo_win32_print_gdi_error("CreateCompatibleDC");
new_surf = NIL_SURFACE; new_surf = (cairo_win32_surface_t*) NIL_SURFACE;
goto FINISH; goto FINISH;
} }
@ -1872,7 +1866,7 @@ cairo_win32_surface_create_with_ddb (HDC hdc,
* video memory is probably exhausted. * video memory is probably exhausted.
*/ */
_cairo_win32_print_gdi_error("CreateCompatibleBitmap"); _cairo_win32_print_gdi_error("CreateCompatibleBitmap");
new_surf = NIL_SURFACE; new_surf = (cairo_win32_surface_t*) NIL_SURFACE;
goto FINISH; goto FINISH;
} }

View File

@ -1,3 +1,4 @@
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
/* cairo - a vector graphics library with display and print output /* cairo - a vector graphics library with display and print output
* *
* Copyright © 2005 Red Hat, Inc * Copyright © 2005 Red Hat, Inc
@ -48,7 +49,7 @@ cairo_public cairo_surface_t *
cairo_win32_surface_create (HDC hdc); cairo_win32_surface_create (HDC hdc);
cairo_public cairo_surface_t * cairo_public cairo_surface_t *
cairo_win32_printing_surface_create (HDC hdc, cairo_bool_t ignore_operators); cairo_win32_printing_surface_create (HDC hdc);
cairo_public cairo_surface_t * cairo_public cairo_surface_t *
cairo_win32_surface_create_with_ddb (HDC hdc, cairo_win32_surface_create_with_ddb (HDC hdc,

View File

@ -398,7 +398,7 @@ _get_image_surface (cairo_xcb_surface_t *surface,
} }
if (!imagerep) if (!imagerep)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
bpp = _bits_per_pixel(surface->dpy, imagerep->depth); bpp = _bits_per_pixel(surface->dpy, imagerep->depth);
bytes_per_line = _bytes_per_line(surface->dpy, surface->width, bpp); bytes_per_line = _bytes_per_line(surface->dpy, surface->width, bpp);
@ -406,7 +406,7 @@ _get_image_surface (cairo_xcb_surface_t *surface,
data = _cairo_malloc_ab (surface->height, bytes_per_line); data = _cairo_malloc_ab (surface->height, bytes_per_line);
if (data == NULL) { if (data == NULL) {
free (imagerep); free (imagerep);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
memcpy (data, xcb_get_image_data (imagerep), bytes_per_line * surface->height); memcpy (data, xcb_get_image_data (imagerep), bytes_per_line * surface->height);
@ -479,7 +479,7 @@ _get_image_surface (cairo_xcb_surface_t *surface,
FAIL: FAIL:
free (data); free (data);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
static void static void
@ -591,7 +591,8 @@ _draw_image_surface (cairo_xcb_surface_t *surface,
data_len = height * data_bpl; data_len = height * data_bpl;
data_line = data = malloc(data_len); data_line = data = malloc(data_len);
if (data == NULL) if (data == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
image_line = image->data + src_y * bpl + (src_x * bpp / 8); image_line = image->data + src_y * bpl + (src_x * bpp / 8);
while (line++ < height) { while (line++ < height) {
memcpy(data_line, image_line, data_bpl); memcpy(data_line, image_line, data_bpl);
@ -720,7 +721,7 @@ _cairo_xcb_surface_clone_similar (void *abstract_surface,
_cairo_xcb_surface_create_similar (surface, content, _cairo_xcb_surface_create_similar (surface, content,
image_src->width, image_src->height); image_src->width, image_src->height);
if (clone->base.status) if (clone->base.status)
return CAIRO_STATUS_NO_MEMORY; return clone->base.status;
_draw_image_surface (clone, image_src, src_x, src_y, _draw_image_surface (clone, image_src, src_x, src_y,
width, height, src_x, src_y); width, height, src_x, src_y);
@ -1265,8 +1266,8 @@ _cairo_xcb_surface_fill_rectangles (void *abstract_surface,
if (num_rects > ARRAY_LENGTH(static_xrects)) { if (num_rects > ARRAY_LENGTH(static_xrects)) {
xrects = _cairo_malloc_ab (num_rects, sizeof(xcb_rectangle_t)); xrects = _cairo_malloc_ab (num_rects, sizeof(xcb_rectangle_t));
if (xrects == NULL) if (xrects == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
for (i = 0; i < num_rects; i++) { for (i = 0; i < num_rects; i++) {
@ -1347,8 +1348,10 @@ _create_trapezoid_mask (cairo_xcb_surface_t *dst,
solid_picture = _create_a8_picture (dst, &solid, width, height, TRUE); solid_picture = _create_a8_picture (dst, &solid, width, height, TRUE);
offset_traps = _cairo_malloc_ab (num_traps, sizeof (xcb_render_trapezoid_t)); offset_traps = _cairo_malloc_ab (num_traps, sizeof (xcb_render_trapezoid_t));
if (!offset_traps) if (!offset_traps) {
_cairo_error (CAIRO_STATUS_NO_MEMORY);
return XCB_NONE; return XCB_NONE;
}
for (i = 0; i < num_traps; i++) { for (i = 0; i < num_traps; i++) {
offset_traps[i].top = _cairo_fixed_to_16_16(traps[i].top) - 0x10000 * dst_y; offset_traps[i].top = _cairo_fixed_to_16_16(traps[i].top) - 0x10000 * dst_y;
@ -1463,7 +1466,7 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op,
dst_x, dst_y, width, height, dst_x, dst_y, width, height,
render_format); render_format);
if (!mask_picture) { if (!mask_picture) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL; goto BAIL;
} }
@ -1495,7 +1498,7 @@ _cairo_xcb_surface_composite_trapezoids (cairo_operator_t op,
if (num_traps > ARRAY_LENGTH(xtraps_stack)) { if (num_traps > ARRAY_LENGTH(xtraps_stack)) {
xtraps = _cairo_malloc_ab (num_traps, sizeof(xcb_render_trapezoid_t)); xtraps = _cairo_malloc_ab (num_traps, sizeof(xcb_render_trapezoid_t));
if (xtraps == NULL) { if (xtraps == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL; goto BAIL;
} }
} }
@ -1555,17 +1558,19 @@ _cairo_xcb_surface_set_clip_region (void *abstract_surface,
XCB_RENDER_CP_CLIP_MASK, none); XCB_RENDER_CP_CLIP_MASK, none);
} else { } else {
cairo_box_int_t *boxes; cairo_box_int_t *boxes;
cairo_status_t status;
xcb_rectangle_t *rects = NULL; xcb_rectangle_t *rects = NULL;
int n_boxes, i; int n_boxes, i;
if (_cairo_region_get_boxes (region, &n_boxes, &boxes) != CAIRO_STATUS_SUCCESS) status = _cairo_region_get_boxes (region, &n_boxes, &boxes);
return CAIRO_STATUS_NO_MEMORY; if (status)
return status;
if (n_boxes > 0) { if (n_boxes > 0) {
rects = _cairo_malloc_ab (n_boxes, sizeof(xcb_rectangle_t)); rects = _cairo_malloc_ab (n_boxes, sizeof(xcb_rectangle_t));
if (rects == NULL) { if (rects == NULL) {
_cairo_region_boxes_fini (region, boxes); _cairo_region_boxes_fini (region, boxes);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
} else { } else {
rects = NULL; rects = NULL;
@ -1990,7 +1995,7 @@ _cairo_xcb_surface_font_init (xcb_connection_t *dpy,
font_private = malloc (sizeof (cairo_xcb_surface_font_private_t)); font_private = malloc (sizeof (cairo_xcb_surface_font_private_t));
if (!font_private) if (!font_private)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font_private->dpy = dpy; font_private->dpy = dpy;
font_private->format = format; font_private->format = format;
@ -2108,7 +2113,7 @@ _cairo_xcb_surface_add_glyph (xcb_connection_t *dpy,
new = malloc (c); new = malloc (c);
if (!new) { if (!new) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL; goto BAIL;
} }
n = new; n = new;
@ -2134,7 +2139,7 @@ _cairo_xcb_surface_add_glyph (xcb_connection_t *dpy,
new = malloc (c); new = malloc (c);
if (new == NULL) { if (new == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL; goto BAIL;
} }
n = new; n = new;
@ -2375,7 +2380,7 @@ _cairo_xcb_surface_show_glyphs (void *abstract_dst,
* 7.1 without EXA). */ * 7.1 without EXA). */
output_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); output_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
if (output_glyphs == NULL) if (output_glyphs == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
/* After passing all those tests, we're now committed to rendering /* After passing all those tests, we're now committed to rendering
* these glyphs or to fail trying. We first upload any glyphs to * these glyphs or to fail trying. We first upload any glyphs to

View File

@ -127,13 +127,9 @@ _cairo_xlib_display_reference (cairo_xlib_display_t *display)
if (display == NULL) if (display == NULL)
return NULL; return NULL;
/* use our mutex until we get a real atomic inc */ assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&display->ref_count));
CAIRO_MUTEX_LOCK (display->mutex);
assert (display->ref_count > 0); _cairo_reference_count_inc (&display->ref_count);
display->ref_count++;
CAIRO_MUTEX_UNLOCK (display->mutex);
return display; return display;
} }
@ -144,27 +140,27 @@ _cairo_xlib_display_destroy (cairo_xlib_display_t *display)
if (display == NULL) if (display == NULL)
return; return;
CAIRO_MUTEX_LOCK (display->mutex); assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&display->ref_count));
assert (display->ref_count > 0);
if (--display->ref_count == 0) {
/* destroy all outstanding notifies */
while (display->workqueue != NULL) {
cairo_xlib_job_t *job = display->workqueue;
display->workqueue = job->next;
if (job->type == WORK && job->func.work.destroy != NULL) if (! _cairo_reference_count_dec_and_test (&display->ref_count))
job->func.work.destroy (job->func.work.data); return;
_cairo_freelist_free (&display->wq_freelist, job); /* destroy all outstanding notifies */
} while (display->workqueue != NULL) {
_cairo_freelist_fini (&display->wq_freelist); cairo_xlib_job_t *job = display->workqueue;
_cairo_freelist_fini (&display->hook_freelist); display->workqueue = job->next;
CAIRO_MUTEX_UNLOCK (display->mutex); if (job->type == WORK && job->func.work.destroy != NULL)
job->func.work.destroy (job->func.work.data);
free (display); _cairo_freelist_free (&display->wq_freelist, job);
} else }
CAIRO_MUTEX_UNLOCK (display->mutex); _cairo_freelist_fini (&display->wq_freelist);
_cairo_freelist_fini (&display->hook_freelist);
CAIRO_MUTEX_FINI (display->mutex);
free (display);
} }
static int static int
@ -177,6 +173,29 @@ static int
_cairo_xlib_close_display (Display *dpy, XExtCodes *codes) _cairo_xlib_close_display (Display *dpy, XExtCodes *codes)
{ {
cairo_xlib_display_t *display, **prev, *next; cairo_xlib_display_t *display, **prev, *next;
cairo_xlib_error_func_t old_handler;
CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
for (display = _cairo_xlib_display_list; display; display = display->next)
if (display->display == dpy)
break;
CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
if (display == NULL)
return 0;
/* protect the notifies from triggering XErrors */
XSync (dpy, False);
old_handler = XSetErrorHandler (_noop_error_handler);
_cairo_xlib_display_notify (display);
_cairo_xlib_call_close_display_hooks (display);
_cairo_xlib_display_discard_screens (display);
/* catch any that arrived before marking the display as closed */
_cairo_xlib_display_notify (display);
XSync (dpy, False);
XSetErrorHandler (old_handler);
/* /*
* Unhook from the global list * Unhook from the global list
@ -186,27 +205,6 @@ _cairo_xlib_close_display (Display *dpy, XExtCodes *codes)
for (display = _cairo_xlib_display_list; display; display = next) { for (display = _cairo_xlib_display_list; display; display = next) {
next = display->next; next = display->next;
if (display->display == dpy) { if (display->display == dpy) {
cairo_xlib_error_func_t old_handler;
/* drop the list mutex whilst triggering the hooks */
CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
/* protect the notifies from triggering XErrors */
XSync (dpy, False);
old_handler = XSetErrorHandler (_noop_error_handler);
_cairo_xlib_display_notify (display);
_cairo_xlib_call_close_display_hooks (display);
_cairo_xlib_display_discard_screens (display);
/* catch any that arrived before marking the display as closed */
_cairo_xlib_display_notify (display);
XSync (dpy, False);
XSetErrorHandler (old_handler);
CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex);
_cairo_xlib_display_destroy (display);
*prev = next; *prev = next;
break; break;
} else } else
@ -214,6 +212,8 @@ _cairo_xlib_close_display (Display *dpy, XExtCodes *codes)
} }
CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex); CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex);
_cairo_xlib_display_destroy (display);
/* Return value in accordance with requirements of /* Return value in accordance with requirements of
* XESetCloseDisplay */ * XESetCloseDisplay */
return 0; return 0;
@ -257,8 +257,10 @@ _cairo_xlib_display_get (Display *dpy)
} }
display = malloc (sizeof (cairo_xlib_display_t)); display = malloc (sizeof (cairo_xlib_display_t));
if (display == NULL) if (display == NULL) {
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
goto UNLOCK; goto UNLOCK;
}
/* Xlib calls out to the extension close_display hooks in LIFO /* Xlib calls out to the extension close_display hooks in LIFO
* order. So we have to ensure that all extensions that we depend * order. So we have to ensure that all extensions that we depend
@ -280,7 +282,7 @@ _cairo_xlib_display_get (Display *dpy)
_cairo_freelist_init (&display->wq_freelist, sizeof (cairo_xlib_job_t)); _cairo_freelist_init (&display->wq_freelist, sizeof (cairo_xlib_job_t));
_cairo_freelist_init (&display->hook_freelist, sizeof (cairo_xlib_hook_t)); _cairo_freelist_init (&display->hook_freelist, sizeof (cairo_xlib_hook_t));
display->ref_count = 2; /* add one for the CloseDisplay */ CAIRO_REFERENCE_COUNT_INIT (&display->ref_count, 2); /* add one for the CloseDisplay */
CAIRO_MUTEX_INIT (display->mutex); CAIRO_MUTEX_INIT (display->mutex);
display->display = dpy; display->display = dpy;
display->screens = NULL; display->screens = NULL;
@ -288,6 +290,15 @@ _cairo_xlib_display_get (Display *dpy)
display->close_display_hooks = NULL; display->close_display_hooks = NULL;
display->closed = FALSE; display->closed = FALSE;
display->buggy_repeat = FALSE;
if (strstr (ServerVendor (dpy), "X.Org") != NULL) {
if (VendorRelease (dpy) <= 60802000)
display->buggy_repeat = TRUE;
} else if (strstr (ServerVendor (dpy), "XFree86") != NULL) {
if (VendorRelease (dpy) <= 40500000)
display->buggy_repeat = TRUE;
}
display->next = _cairo_xlib_display_list; display->next = _cairo_xlib_display_list;
_cairo_xlib_display_list = display; _cairo_xlib_display_list = display;

View File

@ -34,9 +34,13 @@
#define CAIRO_XLIB_PRIVATE_H #define CAIRO_XLIB_PRIVATE_H
#include "cairoint.h" #include "cairoint.h"
#include "cairo-xlib.h" #include "cairo-xlib.h"
#include "cairo-xlib-xrender-private.h"
#include "cairo-compiler-private.h"
#include "cairo-freelist-private.h" #include "cairo-freelist-private.h"
#include "cairo-reference-count-private.h"
#include "cairo-xlib-xrender-private.h"
#include <X11/Xutil.h> /* for XDestroyImage */ #include <X11/Xutil.h> /* for XDestroyImage */
@ -55,7 +59,7 @@ struct _cairo_xlib_hook {
struct _cairo_xlib_display { struct _cairo_xlib_display {
cairo_xlib_display_t *next; cairo_xlib_display_t *next;
unsigned int ref_count; cairo_reference_count_t ref_count;
cairo_mutex_t mutex; cairo_mutex_t mutex;
Display *display; Display *display;
@ -66,12 +70,13 @@ struct _cairo_xlib_display {
cairo_freelist_t hook_freelist; cairo_freelist_t hook_freelist;
cairo_xlib_hook_t *close_display_hooks; cairo_xlib_hook_t *close_display_hooks;
unsigned int buggy_repeat :1;
unsigned int closed :1; unsigned int closed :1;
}; };
struct _cairo_xlib_screen_info { struct _cairo_xlib_screen_info {
cairo_xlib_screen_info_t *next; cairo_xlib_screen_info_t *next;
unsigned int ref_count; cairo_reference_count_t ref_count;
cairo_xlib_display_t *display; cairo_xlib_display_t *display;
Screen *screen; Screen *screen;

View File

@ -246,8 +246,9 @@ _cairo_xlib_screen_info_reference (cairo_xlib_screen_info_t *info)
if (info == NULL) if (info == NULL)
return NULL; return NULL;
assert (info->ref_count > 0); assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&info->ref_count));
info->ref_count++;
_cairo_reference_count_inc (&info->ref_count);
return info; return info;
} }
@ -274,8 +275,9 @@ _cairo_xlib_screen_info_destroy (cairo_xlib_screen_info_t *info)
if (info == NULL) if (info == NULL)
return; return;
assert (info->ref_count > 0); assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&info->ref_count));
if (--info->ref_count)
if (! _cairo_reference_count_dec_and_test (&info->ref_count))
return; return;
CAIRO_MUTEX_LOCK (info->display->mutex); CAIRO_MUTEX_LOCK (info->display->mutex);
@ -330,7 +332,7 @@ _cairo_xlib_screen_info_get (Display *dpy, Screen *screen)
} else { } else {
info = malloc (sizeof (cairo_xlib_screen_info_t)); info = malloc (sizeof (cairo_xlib_screen_info_t));
if (info != NULL) { if (info != NULL) {
info->ref_count = 2; /* Add one for display cache */ CAIRO_REFERENCE_COUNT_INIT (&info->ref_count, 2); /* Add one for display cache */
info->display = _cairo_xlib_display_reference (display); info->display = _cairo_xlib_display_reference (display);
info->screen = screen; info->screen = screen;
info->has_render = FALSE; info->has_render = FALSE;

View File

@ -172,7 +172,7 @@ _cairo_xlib_surface_create_similar_with_format (void *abstract_src,
width, height); width, height);
if (surface->base.status != CAIRO_STATUS_SUCCESS) { if (surface->base.status != CAIRO_STATUS_SUCCESS) {
XFreePixmap (dpy, pix); XFreePixmap (dpy, pix);
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
} }
@ -192,10 +192,10 @@ _xrender_format_to_content (XRenderPictFormat *xrender_format)
if (xrender_format == NULL) if (xrender_format == NULL)
return CAIRO_CONTENT_COLOR; return CAIRO_CONTENT_COLOR;
xrender_format_has_alpha = (xrender_format->direct.alpha != 0); xrender_format_has_alpha = (xrender_format->direct.alphaMask != 0);
xrender_format_has_color = (xrender_format->direct.red != 0 || xrender_format_has_color = (xrender_format->direct.redMask != 0 ||
xrender_format->direct.green != 0 || xrender_format->direct.greenMask != 0 ||
xrender_format->direct.blue != 0); xrender_format->direct.blueMask != 0);
if (xrender_format_has_alpha) if (xrender_format_has_alpha)
if (xrender_format_has_color) if (xrender_format_has_color)
@ -252,7 +252,7 @@ _cairo_xlib_surface_create_similar (void *abstract_src,
width, height); width, height);
if (surface->base.status != CAIRO_STATUS_SUCCESS) { if (surface->base.status != CAIRO_STATUS_SUCCESS) {
XFreePixmap (src->dpy, pix); XFreePixmap (src->dpy, pix);
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
} }
@ -558,7 +558,7 @@ _get_image_surface (cairo_xlib_surface_t *surface,
} }
} }
if (!ximage) if (!ximage)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
_swap_ximage_to_native (ximage); _swap_ximage_to_native (ximage);
@ -615,7 +615,7 @@ _get_image_surface (cairo_xlib_surface_t *surface,
FAIL: FAIL:
XDestroyImage (ximage); XDestroyImage (ximage);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
static void static void
@ -694,7 +694,7 @@ _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface)
surface->gc = XCreateGC (surface->dpy, surface->drawable, surface->gc = XCreateGC (surface->dpy, surface->drawable,
GCGraphicsExposures, &gcv); GCGraphicsExposures, &gcv);
if (!surface->gc) if (!surface->gc)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
_cairo_xlib_surface_set_gc_clip_rects (surface); _cairo_xlib_surface_set_gc_clip_rects (surface);
@ -810,10 +810,12 @@ _cairo_xlib_surface_release_dest_image (void *abstract_surfac
void *image_extra) void *image_extra)
{ {
cairo_xlib_surface_t *surface = abstract_surface; cairo_xlib_surface_t *surface = abstract_surface;
cairo_status_t status;
/* ignore errors */ status = _draw_image_surface (surface, image,
_draw_image_surface (surface, image, 0, 0, image->width, image->height, 0, 0, image->width, image->height,
image_rect->x, image_rect->y); image_rect->x, image_rect->y);
status = _cairo_surface_set_error (&surface->base, status);
cairo_surface_destroy (&image->base); cairo_surface_destroy (&image->base);
} }
@ -863,7 +865,7 @@ _cairo_xlib_surface_clone_similar (void *abstract_surface,
_cairo_xlib_surface_create_similar_with_format (surface, image_src->format, _cairo_xlib_surface_create_similar_with_format (surface, image_src->format,
image_src->width, image_src->height); image_src->width, image_src->height);
if (clone->base.status) if (clone->base.status)
return CAIRO_STATUS_NO_MEMORY; return clone->base.status;
status = _draw_image_surface (clone, image_src, src_x, src_y, status = _draw_image_surface (clone, image_src, src_x, src_y,
width, height, src_x, src_y); width, height, src_x, src_y);
@ -1196,10 +1198,8 @@ _recategorize_composite_operation (cairo_xlib_surface_t *dst,
return DO_XCOPYAREA; return DO_XCOPYAREA;
} }
if (!dst->buggy_repeat) if (dst->buggy_repeat &&
return DO_RENDER; is_integer_translation &&
if (is_integer_translation &&
src_attr->extend == CAIRO_EXTEND_REPEAT && src_attr->extend == CAIRO_EXTEND_REPEAT &&
(src->width != 1 || src->height != 1)) (src->width != 1 || src->height != 1))
{ {
@ -1213,6 +1213,9 @@ _recategorize_composite_operation (cairo_xlib_surface_t *dst,
return DO_UNSUPPORTED; return DO_UNSUPPORTED;
} }
if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src))
return DO_UNSUPPORTED;
return DO_RENDER; return DO_RENDER;
} }
@ -1317,13 +1320,13 @@ _cairo_xlib_surface_composite (cairo_operator_t op,
goto BAIL; goto BAIL;
} }
status = _cairo_xlib_surface_set_attributes (src, &src_attr);
if (status)
goto BAIL;
switch (operation) switch (operation)
{ {
case DO_RENDER: case DO_RENDER:
status = _cairo_xlib_surface_set_attributes (src, &src_attr);
if (status)
goto BAIL;
_cairo_xlib_surface_ensure_dst_picture (dst); _cairo_xlib_surface_ensure_dst_picture (dst);
if (mask) { if (mask) {
status = _cairo_xlib_surface_set_attributes (mask, &mask_attr); status = _cairo_xlib_surface_set_attributes (mask, &mask_attr);
@ -1445,8 +1448,8 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface,
if (num_rects > ARRAY_LENGTH(static_xrects)) { if (num_rects > ARRAY_LENGTH(static_xrects)) {
xrects = _cairo_malloc_ab (num_rects, sizeof(XRectangle)); xrects = _cairo_malloc_ab (num_rects, sizeof(XRectangle));
if (xrects == NULL) if (xrects == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
for (i = 0; i < num_rects; i++) { for (i = 0; i < num_rects; i++) {
@ -1534,6 +1537,7 @@ _create_trapezoid_mask (cairo_xlib_surface_t *dst,
offset_traps = _cairo_malloc_ab (num_traps, sizeof (XTrapezoid)); offset_traps = _cairo_malloc_ab (num_traps, sizeof (XTrapezoid));
if (!offset_traps) { if (!offset_traps) {
XRenderFreePicture (dst->dpy, mask_picture); XRenderFreePicture (dst->dpy, mask_picture);
_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return None; return None;
} }
@ -1651,7 +1655,7 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
dst_x, dst_y, width, height, dst_x, dst_y, width, height,
pict_format); pict_format);
if (!mask_picture) { if (!mask_picture) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL; goto BAIL;
} }
@ -1683,7 +1687,7 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t op,
if (num_traps > ARRAY_LENGTH(xtraps_stack)) { if (num_traps > ARRAY_LENGTH(xtraps_stack)) {
xtraps = _cairo_malloc_ab (num_traps, sizeof(XTrapezoid)); xtraps = _cairo_malloc_ab (num_traps, sizeof(XTrapezoid));
if (xtraps == NULL) { if (xtraps == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL; goto BAIL;
} }
} }
@ -1738,17 +1742,19 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
if (region != NULL) { if (region != NULL) {
cairo_box_int_t *boxes; cairo_box_int_t *boxes;
cairo_status_t status;
XRectangle *rects = NULL; XRectangle *rects = NULL;
int n_boxes, i; int n_boxes, i;
if (_cairo_region_get_boxes (region, &n_boxes, &boxes) != CAIRO_STATUS_SUCCESS) status = _cairo_region_get_boxes (region, &n_boxes, &boxes);
return CAIRO_STATUS_NO_MEMORY; if (status)
return status;
if (n_boxes > ARRAY_LENGTH (surface->embedded_clip_rects)) { if (n_boxes > ARRAY_LENGTH (surface->embedded_clip_rects)) {
rects = _cairo_malloc_ab (n_boxes, sizeof(XRectangle)); rects = _cairo_malloc_ab (n_boxes, sizeof(XRectangle));
if (rects == NULL) { if (rects == NULL) {
_cairo_region_boxes_fini (region, boxes); _cairo_region_boxes_fini (region, boxes);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
} else { } else {
rects = surface->embedded_clip_rects; rects = surface->embedded_clip_rects;
@ -1937,14 +1943,14 @@ _cairo_xlib_surface_create_internal (Display *dpy,
screen_info = _cairo_xlib_screen_info_get (dpy, screen); screen_info = _cairo_xlib_screen_info_get (dpy, screen);
if (screen_info == NULL) { if (screen_info == NULL) {
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
} }
surface = malloc (sizeof (cairo_xlib_surface_t)); surface = malloc (sizeof (cairo_xlib_surface_t));
if (surface == NULL) { if (surface == NULL) {
_cairo_xlib_screen_info_destroy (screen_info); _cairo_xlib_screen_info_destroy (screen_info);
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
} }
@ -1952,7 +1958,7 @@ _cairo_xlib_surface_create_internal (Display *dpy,
_cairo_xlib_surface_detach_display, surface, surface)) { _cairo_xlib_surface_detach_display, surface, surface)) {
free (surface); free (surface);
_cairo_xlib_screen_info_destroy (screen_info); _cairo_xlib_screen_info_destroy (screen_info);
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
} }
@ -2007,14 +2013,7 @@ _cairo_xlib_surface_create_internal (Display *dpy,
surface->width = width; surface->width = width;
surface->height = height; surface->height = height;
surface->buggy_repeat = FALSE; surface->buggy_repeat = screen_info->display->buggy_repeat;
if (strstr (ServerVendor (dpy), "X.Org") != NULL) {
if (VendorRelease (dpy) <= 60802000)
surface->buggy_repeat = TRUE;
} else if (strstr (ServerVendor (dpy), "XFree86") != NULL) {
if (VendorRelease (dpy) <= 40500000)
surface->buggy_repeat = TRUE;
}
surface->dst_picture = None; surface->dst_picture = None;
surface->src_picture = None; surface->src_picture = None;
@ -2091,10 +2090,12 @@ cairo_xlib_surface_create (Display *dpy,
Screen *screen = _cairo_xlib_screen_from_visual (dpy, visual); Screen *screen = _cairo_xlib_screen_from_visual (dpy, visual);
if (screen == NULL) { if (screen == NULL) {
_cairo_error (CAIRO_STATUS_INVALID_VISUAL); _cairo_error_throw (CAIRO_STATUS_INVALID_VISUAL);
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
} }
CAIRO_MUTEX_INITIALIZE ();
return _cairo_xlib_surface_create_internal (dpy, drawable, screen, return _cairo_xlib_surface_create_internal (dpy, drawable, screen,
visual, NULL, width, height, 0); visual, NULL, width, height, 0);
} }
@ -2119,6 +2120,8 @@ cairo_xlib_surface_create_for_bitmap (Display *dpy,
int width, int width,
int height) int height)
{ {
CAIRO_MUTEX_INITIALIZE ();
return _cairo_xlib_surface_create_internal (dpy, bitmap, screen, return _cairo_xlib_surface_create_internal (dpy, bitmap, screen,
NULL, NULL, width, height, 1); NULL, NULL, width, height, 1);
} }
@ -2152,6 +2155,8 @@ cairo_xlib_surface_create_with_xrender_format (Display *dpy,
int width, int width,
int height) int height)
{ {
CAIRO_MUTEX_INITIALIZE ();
return _cairo_xlib_surface_create_internal (dpy, drawable, screen, return _cairo_xlib_surface_create_internal (dpy, drawable, screen,
NULL, format, width, height, 0); NULL, format, width, height, 0);
} }
@ -2180,10 +2185,11 @@ cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface,
int height) int height)
{ {
cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface; cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
cairo_status_t status;
if (! _cairo_surface_is_xlib (abstract_surface)) { if (! _cairo_surface_is_xlib (abstract_surface)) {
_cairo_surface_set_error (abstract_surface, status = _cairo_surface_set_error (abstract_surface,
CAIRO_STATUS_SURFACE_TYPE_MISMATCH); CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return; return;
} }
@ -2214,7 +2220,8 @@ cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface,
cairo_status_t status; cairo_status_t status;
if (! _cairo_surface_is_xlib (abstract_surface)) { if (! _cairo_surface_is_xlib (abstract_surface)) {
_cairo_surface_set_error (abstract_surface, CAIRO_STATUS_SURFACE_TYPE_MISMATCH); status = _cairo_surface_set_error (abstract_surface,
CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return; return;
} }
@ -2229,7 +2236,7 @@ cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface,
XRenderFreePicture, XRenderFreePicture,
surface->dst_picture); surface->dst_picture);
if (status) { if (status) {
_cairo_surface_set_error (&surface->base, status); status = _cairo_surface_set_error (&surface->base, status);
return; return;
} }
@ -2242,7 +2249,7 @@ cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface,
XRenderFreePicture, XRenderFreePicture,
surface->src_picture); surface->src_picture);
if (status) { if (status) {
_cairo_surface_set_error (&surface->base, status); status = _cairo_surface_set_error (&surface->base, status);
return; return;
} }
@ -2271,7 +2278,7 @@ cairo_xlib_surface_get_display (cairo_surface_t *abstract_surface)
cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface; cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
if (! _cairo_surface_is_xlib (abstract_surface)) { if (! _cairo_surface_is_xlib (abstract_surface)) {
_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return NULL; return NULL;
} }
@ -2294,7 +2301,7 @@ cairo_xlib_surface_get_drawable (cairo_surface_t *abstract_surface)
cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface; cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
if (! _cairo_surface_is_xlib (abstract_surface)) { if (! _cairo_surface_is_xlib (abstract_surface)) {
_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return 0; return 0;
} }
@ -2317,7 +2324,7 @@ cairo_xlib_surface_get_screen (cairo_surface_t *abstract_surface)
cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface; cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
if (! _cairo_surface_is_xlib (abstract_surface)) { if (! _cairo_surface_is_xlib (abstract_surface)) {
_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return NULL; return NULL;
} }
@ -2340,7 +2347,7 @@ cairo_xlib_surface_get_visual (cairo_surface_t *abstract_surface)
cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface; cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
if (! _cairo_surface_is_xlib (abstract_surface)) { if (! _cairo_surface_is_xlib (abstract_surface)) {
_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return NULL; return NULL;
} }
@ -2363,7 +2370,7 @@ cairo_xlib_surface_get_depth (cairo_surface_t *abstract_surface)
cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface; cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
if (! _cairo_surface_is_xlib (abstract_surface)) { if (! _cairo_surface_is_xlib (abstract_surface)) {
_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return 0; return 0;
} }
@ -2386,7 +2393,7 @@ cairo_xlib_surface_get_width (cairo_surface_t *abstract_surface)
cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface; cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
if (! _cairo_surface_is_xlib (abstract_surface)) { if (! _cairo_surface_is_xlib (abstract_surface)) {
_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return -1; return -1;
} }
@ -2409,7 +2416,7 @@ cairo_xlib_surface_get_height (cairo_surface_t *abstract_surface)
cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface; cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
if (! _cairo_surface_is_xlib (abstract_surface)) { if (! _cairo_surface_is_xlib (abstract_surface)) {
_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
return -1; return -1;
} }
@ -2452,13 +2459,13 @@ _cairo_xlib_surface_font_init (Display *dpy,
font_private = malloc (sizeof (cairo_xlib_surface_font_private_t)); font_private = malloc (sizeof (cairo_xlib_surface_font_private_t));
if (!font_private) if (!font_private)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (!_cairo_xlib_add_close_display_hook (dpy, if (!_cairo_xlib_add_close_display_hook (dpy,
_cairo_xlib_surface_remove_scaled_font, _cairo_xlib_surface_remove_scaled_font,
scaled_font, scaled_font)) { scaled_font, scaled_font)) {
free (font_private); free (font_private);
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
@ -2546,15 +2553,34 @@ _native_byte_order_lsb (void)
static cairo_status_t static cairo_status_t
_cairo_xlib_surface_add_glyph (Display *dpy, _cairo_xlib_surface_add_glyph (Display *dpy,
cairo_scaled_font_t *scaled_font, cairo_scaled_font_t *scaled_font,
cairo_scaled_glyph_t *scaled_glyph) cairo_scaled_glyph_t **pscaled_glyph)
{ {
XGlyphInfo glyph_info; XGlyphInfo glyph_info;
unsigned long glyph_index; unsigned long glyph_index;
unsigned char *data; unsigned char *data;
cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_xlib_surface_font_private_t *font_private; cairo_xlib_surface_font_private_t *font_private;
cairo_scaled_glyph_t *scaled_glyph = *pscaled_glyph;
cairo_image_surface_t *glyph_surface = scaled_glyph->surface; cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
cairo_bool_t already_had_glyph_surface;
if (!glyph_surface) {
status = _cairo_scaled_glyph_lookup (scaled_font,
_cairo_scaled_glyph_index (scaled_glyph),
CAIRO_SCALED_GLYPH_INFO_METRICS |
CAIRO_SCALED_GLYPH_INFO_SURFACE,
pscaled_glyph);
if (status != CAIRO_STATUS_SUCCESS)
return status;
scaled_glyph = *pscaled_glyph;
glyph_surface = scaled_glyph->surface;
already_had_glyph_surface = FALSE;
} else {
already_had_glyph_surface = TRUE;
}
if (scaled_font->surface_private == NULL) { if (scaled_font->surface_private == NULL) {
status = _cairo_xlib_surface_font_init (dpy, scaled_font, status = _cairo_xlib_surface_font_init (dpy, scaled_font,
@ -2564,22 +2590,16 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
} }
font_private = scaled_font->surface_private; font_private = scaled_font->surface_private;
/* If the glyph format does not match the font format, then we /* If the glyph surface has zero height or width, we create
* create a temporary surface for the glyph image with the font's * a clear 1x1 surface, to avoid various X server bugs.
* format.
*/ */
if (glyph_surface->format != font_private->format) { if ((glyph_surface->width == 0) || (glyph_surface->height == 0)) {
cairo_t *cr; cairo_t *cr;
cairo_surface_t *tmp_surface; cairo_surface_t *tmp_surface;
double x_offset, y_offset;
tmp_surface = cairo_image_surface_create (font_private->format, tmp_surface = cairo_image_surface_create (font_private->format, 1, 1);
glyph_surface->width,
glyph_surface->height);
cr = cairo_create (tmp_surface); cr = cairo_create (tmp_surface);
cairo_surface_get_device_offset (&glyph_surface->base, &x_offset, &y_offset); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_set_source_surface (cr, &glyph_surface->base, x_offset, y_offset);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (cr); cairo_paint (cr);
status = cairo_status (cr); status = cairo_status (cr);
@ -2595,6 +2615,36 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
goto BAIL; goto BAIL;
} }
/* If the glyph format does not match the font format, then we
* create a temporary surface for the glyph image with the font's
* format.
*/
if (glyph_surface->format != font_private->format) {
cairo_t *cr;
cairo_surface_t *tmp_surface;
tmp_surface = cairo_image_surface_create (font_private->format,
glyph_surface->width,
glyph_surface->height);
tmp_surface->device_transform = glyph_surface->base.device_transform;
tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
cr = cairo_create (tmp_surface);
cairo_set_source_surface (cr, &glyph_surface->base, 0, 0);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_paint (cr);
status = cairo_status (cr);
cairo_destroy (cr);
glyph_surface = (cairo_image_surface_t *) tmp_surface;
if (status)
goto BAIL;
}
/* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */ /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0); glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0); glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
@ -2616,7 +2666,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
new = malloc (c); new = malloc (c);
if (!new) { if (!new) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL; goto BAIL;
} }
n = new; n = new;
@ -2642,7 +2692,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
new = malloc (c); new = malloc (c);
if (new == NULL) { if (new == NULL) {
status = CAIRO_STATUS_NO_MEMORY; status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto BAIL; goto BAIL;
} }
n = new; n = new;
@ -2681,6 +2731,15 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
if (glyph_surface != scaled_glyph->surface) if (glyph_surface != scaled_glyph->surface)
cairo_surface_destroy (&glyph_surface->base); cairo_surface_destroy (&glyph_surface->base);
/* if the scaled glyph didn't already have a surface attached
* to it, release the created surface now that we have it
* uploaded to the X server. If the surface has already been
* there (eg. because image backend requested it), leave it in
* the cache
*/
if (!already_had_glyph_surface)
_cairo_scaled_glyph_set_surface (scaled_glyph, scaled_font, NULL);
return status; return status;
} }
@ -2770,7 +2829,7 @@ _cairo_xlib_surface_emit_glyphs_chunk (cairo_xlib_surface_t *dst,
} else { } else {
elts = _cairo_malloc_ab (num_elts, sizeof (XGlyphElt8)); elts = _cairo_malloc_ab (num_elts, sizeof (XGlyphElt8));
if (elts == NULL) if (elts == NULL)
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
} }
/* Fill them in */ /* Fill them in */
@ -2866,7 +2925,6 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
status = _cairo_scaled_glyph_lookup (scaled_font, status = _cairo_scaled_glyph_lookup (scaled_font,
glyphs[i].index, glyphs[i].index,
CAIRO_SCALED_GLYPH_INFO_SURFACE |
CAIRO_SCALED_GLYPH_INFO_METRICS, CAIRO_SCALED_GLYPH_INFO_METRICS,
&scaled_glyph); &scaled_glyph);
if (status != CAIRO_STATUS_SUCCESS) if (status != CAIRO_STATUS_SUCCESS)
@ -2877,14 +2935,7 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
/* Glyph skipping: /* Glyph skipping:
* *
* We skip any initial size-zero glyphs to avoid an X server bug (present * We skip any glyphs that have troublesome coordinates. We want
* in at least Xorg 7.1 without EXA) which stops rendering glyphs after
* the first zero-size glyph. However, we don't skip all size-zero
* glyphs, since that will force a new element at every space. We
* skip initial size-zero glyphs and hope that it's enough. Since
* Xft never exposed that bug, this assumption should be correct.
*
* We also skip any glyphs that have troublesome coordinates. We want
* to make sure that (glyph2.x - (glyph1.x + glyph1.width)) fits in * to make sure that (glyph2.x - (glyph1.x + glyph1.width)) fits in
* a signed 16bit integer, otherwise it will overflow in the render * a signed 16bit integer, otherwise it will overflow in the render
* protocol. * protocol.
@ -2898,8 +2949,7 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
* Anyway, we will allow positions in the range -1024..15359. That * Anyway, we will allow positions in the range -1024..15359. That
* will buy us a few more years before this stops working. * will buy us a few more years before this stops working.
*/ */
if ((!num_out_glyphs && !(scaled_glyph->surface->width && scaled_glyph->surface->height)) || if (((this_x+1024)|(this_y+1024))&~0x3fffu) {
(((this_x+1024)|(this_y+1024))&~0x3fffu)) {
glyphs[i].index = GLYPH_INDEX_SKIP; glyphs[i].index = GLYPH_INDEX_SKIP;
continue; continue;
} }
@ -2955,7 +3005,7 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
if (scaled_glyph->surface_private == NULL) { if (scaled_glyph->surface_private == NULL) {
status = _cairo_xlib_surface_add_glyph (dst->dpy, status = _cairo_xlib_surface_add_glyph (dst->dpy,
scaled_font, scaled_font,
scaled_glyph); &scaled_glyph);
if (status) if (status)
return status; return status;
scaled_glyph->surface_private = (void *) 1; scaled_glyph->surface_private = (void *) 1;

View File

@ -45,7 +45,7 @@
#define CAIRO_TOLERANCE_MINIMUM 0.0002 /* We're limited by 16 bits of sub-pixel precision */ #define CAIRO_TOLERANCE_MINIMUM 0.0002 /* We're limited by 16 bits of sub-pixel precision */
static const cairo_t _cairo_nil = { static const cairo_t _cairo_nil = {
CAIRO_REF_COUNT_INVALID, /* ref_count */ CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
CAIRO_STATUS_NO_MEMORY, /* status */ CAIRO_STATUS_NO_MEMORY, /* status */
{ 0, 0, 0, NULL }, /* user_data */ { 0, 0, 0, NULL }, /* user_data */
NULL, /* gstate */ NULL, /* gstate */
@ -53,11 +53,11 @@ static const cairo_t _cairo_nil = {
0 0
}}, }},
{{ /* path */ {{ /* path */
{ 0, 0 }, /* last_move_point */ { 0, 0 }, /* last_move_point */
{ 0, 0 }, /* current point */ { 0, 0 }, /* current point */
FALSE, /* has_current_point */ FALSE, /* has_current_point */
FALSE, /* has_curve_to */ FALSE, /* has_curve_to */
NULL, {{0}} /* buf_tail, buf_head */ NULL, {{NULL}} /* buf_tail, buf_head */
}} }}
}; };
@ -83,12 +83,16 @@ static const cairo_t _cairo_nil = {
* The purpose of this function is to allow the user to set a * The purpose of this function is to allow the user to set a
* breakpoint in _cairo_error() to generate a stack trace for when the * breakpoint in _cairo_error() to generate a stack trace for when the
* user causes cairo to detect an error. * user causes cairo to detect an error.
*
* Return value: the error status.
**/ **/
void cairo_status_t
_cairo_error (cairo_status_t status) _cairo_error (cairo_status_t status)
{ {
assert (status > CAIRO_STATUS_SUCCESS && assert (status > CAIRO_STATUS_SUCCESS &&
status <= CAIRO_STATUS_LAST_STATUS); status <= CAIRO_STATUS_LAST_STATUS);
return status;
} }
/** /**
@ -97,11 +101,11 @@ _cairo_error (cairo_status_t status)
* @status: a status value indicating an error, (eg. not * @status: a status value indicating an error, (eg. not
* CAIRO_STATUS_SUCCESS) * CAIRO_STATUS_SUCCESS)
* *
* Sets cr->status to @status and calls _cairo_error; * Atomically sets cr->status to @status and calls _cairo_error;
* *
* All assignments of an error status to cr->status should happen * All assignments of an error status to cr->status should happen
* through _cairo_set_error() or else _cairo_error() should be * through _cairo_set_error(). Note that due to the nature of the atomic
* called immediately after the assignment. * operation, it is not safe to call this function on the nil objects.
* *
* The purpose of this function is to allow the user to set a * The purpose of this function is to allow the user to set a
* breakpoint in _cairo_error() to generate a stack trace for when the * breakpoint in _cairo_error() to generate a stack trace for when the
@ -111,12 +115,10 @@ static void
_cairo_set_error (cairo_t *cr, cairo_status_t status) _cairo_set_error (cairo_t *cr, cairo_status_t status)
{ {
/* Don't overwrite an existing error. This preserves the first /* Don't overwrite an existing error. This preserves the first
* error, which is the most significant. It also avoids attempting * error, which is the most significant. */
* to write to read-only data (eg. from a nil cairo_t). */ _cairo_status_set_error (&cr->status, status);
if (cr->status == CAIRO_STATUS_SUCCESS)
cr->status = status;
_cairo_error (status); status = _cairo_error (status);
} }
/** /**
@ -196,10 +198,12 @@ cairo_create (cairo_surface_t *target)
return (cairo_t *) &_cairo_nil; return (cairo_t *) &_cairo_nil;
cr = malloc (sizeof (cairo_t)); cr = malloc (sizeof (cairo_t));
if (cr == NULL) if (cr == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return (cairo_t *) &_cairo_nil; return (cairo_t *) &_cairo_nil;
}
cr->ref_count = 1; CAIRO_REFERENCE_COUNT_INIT (&cr->ref_count, 1);
cr->status = CAIRO_STATUS_SUCCESS; cr->status = CAIRO_STATUS_SUCCESS;
@ -232,12 +236,12 @@ slim_hidden_def (cairo_create);
cairo_t * cairo_t *
cairo_reference (cairo_t *cr) cairo_reference (cairo_t *cr)
{ {
if (cr == NULL || cr->ref_count == CAIRO_REF_COUNT_INVALID) if (cr == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&cr->ref_count))
return cr; return cr;
assert (cr->ref_count > 0); assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&cr->ref_count));
cr->ref_count++; _cairo_reference_count_inc (&cr->ref_count);
return cr; return cr;
} }
@ -253,13 +257,12 @@ cairo_reference (cairo_t *cr)
void void
cairo_destroy (cairo_t *cr) cairo_destroy (cairo_t *cr)
{ {
if (cr == NULL || cr->ref_count == CAIRO_REF_COUNT_INVALID) if (cr == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&cr->ref_count))
return; return;
assert (cr->ref_count > 0); assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&cr->ref_count));
cr->ref_count--; if (! _cairo_reference_count_dec_and_test (&cr->ref_count))
if (cr->ref_count)
return; return;
while (cr->gstate != cr->gstate_tail) { while (cr->gstate != cr->gstate_tail) {
@ -323,8 +326,8 @@ cairo_set_user_data (cairo_t *cr,
void *user_data, void *user_data,
cairo_destroy_func_t destroy) cairo_destroy_func_t destroy)
{ {
if (cr->ref_count == CAIRO_REF_COUNT_INVALID) if (CAIRO_REFERENCE_COUNT_IS_INVALID (&cr->ref_count))
return CAIRO_STATUS_NO_MEMORY; return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return _cairo_user_data_array_set_data (&cr->user_data, return _cairo_user_data_array_set_data (&cr->user_data,
key, user_data, destroy); key, user_data, destroy);
@ -344,10 +347,10 @@ cairo_set_user_data (cairo_t *cr,
unsigned int unsigned int
cairo_get_reference_count (cairo_t *cr) cairo_get_reference_count (cairo_t *cr)
{ {
if (cr == NULL || cr->ref_count == CAIRO_REF_COUNT_INVALID) if (cr == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&cr->ref_count))
return 0; return 0;
return cr->ref_count; return CAIRO_REFERENCE_COUNT_GET_VALUE (&cr->ref_count);
} }
/** /**
@ -1070,6 +1073,9 @@ cairo_get_dash_count (cairo_t *cr)
{ {
int num_dashes; int num_dashes;
if (cr->status)
return 0;
_cairo_gstate_get_dash (cr->gstate, NULL, &num_dashes, NULL); _cairo_gstate_get_dash (cr->gstate, NULL, &num_dashes, NULL);
return num_dashes; return num_dashes;
@ -1092,6 +1098,9 @@ cairo_get_dash (cairo_t *cr,
double *dashes, double *dashes,
double *offset) double *offset)
{ {
if (cr->status)
return;
_cairo_gstate_get_dash (cr->gstate, dashes, NULL, offset); _cairo_gstate_get_dash (cr->gstate, dashes, NULL, offset);
} }
@ -1519,7 +1528,8 @@ slim_hidden_def (cairo_curve_to);
* *
* If there is a current point, an initial line segment will be added * If there is a current point, an initial line segment will be added
* to the path to connect the current point to the beginning of the * to the path to connect the current point to the beginning of the
* arc. * arc. If this initial line is undesired, it can be avoided by
* calling cairo_new_sub_path() before calling cairo_arc().
* *
* Angles are measured in radians. An angle of 0.0 is in the direction * Angles are measured in radians. An angle of 0.0 is in the direction
* of the positive X axis (in user space). An angle of %M_PI/2.0 radians * of the positive X axis (in user space). An angle of %M_PI/2.0 radians
@ -2415,8 +2425,11 @@ _cairo_rectangle_list_create_in_error (cairo_status_t status)
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
list = malloc (sizeof (cairo_rectangle_list_t)); list = malloc (sizeof (cairo_rectangle_list_t));
if (list == NULL) if (list == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
return (cairo_rectangle_list_t*) &_cairo_rectangles_nil; return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
}
list->status = status; list->status = status;
list->rectangles = NULL; list->rectangles = NULL;
list->num_rectangles = 0; list->num_rectangles = 0;
@ -2625,6 +2638,11 @@ cairo_set_font_matrix (cairo_t *cr,
void void
cairo_get_font_matrix (cairo_t *cr, cairo_matrix_t *matrix) cairo_get_font_matrix (cairo_t *cr, cairo_matrix_t *matrix)
{ {
if (cr->status) {
cairo_matrix_init_identity (matrix);
return;
}
_cairo_gstate_get_font_matrix (cr->gstate, matrix); _cairo_gstate_get_font_matrix (cr->gstate, matrix);
} }
@ -2676,6 +2694,11 @@ cairo_get_font_options (cairo_t *cr,
if (cairo_font_options_status (options)) if (cairo_font_options_status (options))
return; return;
if (cr->status) {
_cairo_font_options_init_default (options);
return;
}
_cairo_gstate_get_font_options (cr->gstate, options); _cairo_gstate_get_font_options (cr->gstate, options);
} }
@ -3071,6 +3094,9 @@ cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs)
cairo_operator_t cairo_operator_t
cairo_get_operator (cairo_t *cr) cairo_get_operator (cairo_t *cr)
{ {
if (cr->status)
return (cairo_operator_t) 0;
return _cairo_gstate_get_operator (cr->gstate); return _cairo_gstate_get_operator (cr->gstate);
} }
@ -3085,6 +3111,9 @@ cairo_get_operator (cairo_t *cr)
double double
cairo_get_tolerance (cairo_t *cr) cairo_get_tolerance (cairo_t *cr)
{ {
if (cr->status)
return 0.;
return _cairo_gstate_get_tolerance (cr->gstate); return _cairo_gstate_get_tolerance (cr->gstate);
} }
slim_hidden_def (cairo_get_tolerance); slim_hidden_def (cairo_get_tolerance);
@ -3100,6 +3129,9 @@ slim_hidden_def (cairo_get_tolerance);
cairo_antialias_t cairo_antialias_t
cairo_get_antialias (cairo_t *cr) cairo_get_antialias (cairo_t *cr)
{ {
if (cr->status)
return (cairo_antialias_t) 0;
return _cairo_gstate_get_antialias (cr->gstate); return _cairo_gstate_get_antialias (cr->gstate);
} }
@ -3135,19 +3167,21 @@ cairo_get_antialias (cairo_t *cr)
void void
cairo_get_current_point (cairo_t *cr, double *x_ret, double *y_ret) cairo_get_current_point (cairo_t *cr, double *x_ret, double *y_ret)
{ {
cairo_status_t status;
cairo_fixed_t x_fixed, y_fixed; cairo_fixed_t x_fixed, y_fixed;
double x, y; double x, y;
status = _cairo_path_fixed_get_current_point (cr->path, &x_fixed, &y_fixed); if (cr->status == CAIRO_STATUS_SUCCESS &&
if (status == CAIRO_STATUS_NO_CURRENT_POINT) { _cairo_path_fixed_get_current_point (cr->path, &x_fixed, &y_fixed))
x = 0.0; {
y = 0.0;
} else {
x = _cairo_fixed_to_double (x_fixed); x = _cairo_fixed_to_double (x_fixed);
y = _cairo_fixed_to_double (y_fixed); y = _cairo_fixed_to_double (y_fixed);
_cairo_gstate_backend_to_user (cr->gstate, &x, &y); _cairo_gstate_backend_to_user (cr->gstate, &x, &y);
} }
else
{
x = 0.0;
y = 0.0;
}
if (x_ret) if (x_ret)
*x_ret = x; *x_ret = x;
@ -3167,6 +3201,9 @@ slim_hidden_def(cairo_get_current_point);
cairo_fill_rule_t cairo_fill_rule_t
cairo_get_fill_rule (cairo_t *cr) cairo_get_fill_rule (cairo_t *cr)
{ {
if (cr->status)
return (cairo_fill_rule_t) 0;
return _cairo_gstate_get_fill_rule (cr->gstate); return _cairo_gstate_get_fill_rule (cr->gstate);
} }
@ -3184,6 +3221,9 @@ cairo_get_fill_rule (cairo_t *cr)
double double
cairo_get_line_width (cairo_t *cr) cairo_get_line_width (cairo_t *cr)
{ {
if (cr->status)
return 0.;
return _cairo_gstate_get_line_width (cr->gstate); return _cairo_gstate_get_line_width (cr->gstate);
} }
@ -3198,6 +3238,9 @@ cairo_get_line_width (cairo_t *cr)
cairo_line_cap_t cairo_line_cap_t
cairo_get_line_cap (cairo_t *cr) cairo_get_line_cap (cairo_t *cr)
{ {
if (cr->status)
return (cairo_line_cap_t) 0;
return _cairo_gstate_get_line_cap (cr->gstate); return _cairo_gstate_get_line_cap (cr->gstate);
} }
@ -3212,6 +3255,9 @@ cairo_get_line_cap (cairo_t *cr)
cairo_line_join_t cairo_line_join_t
cairo_get_line_join (cairo_t *cr) cairo_get_line_join (cairo_t *cr)
{ {
if (cr->status)
return (cairo_line_join_t) 0;
return _cairo_gstate_get_line_join (cr->gstate); return _cairo_gstate_get_line_join (cr->gstate);
} }
@ -3226,6 +3272,9 @@ cairo_get_line_join (cairo_t *cr)
double double
cairo_get_miter_limit (cairo_t *cr) cairo_get_miter_limit (cairo_t *cr)
{ {
if (cr->status)
return 0.;
return _cairo_gstate_get_miter_limit (cr->gstate); return _cairo_gstate_get_miter_limit (cr->gstate);
} }
@ -3239,6 +3288,11 @@ cairo_get_miter_limit (cairo_t *cr)
void void
cairo_get_matrix (cairo_t *cr, cairo_matrix_t *matrix) cairo_get_matrix (cairo_t *cr, cairo_matrix_t *matrix)
{ {
if (cr->status) {
cairo_matrix_init_identity (matrix);
return;
}
_cairo_gstate_get_matrix (cr->gstate, matrix); _cairo_gstate_get_matrix (cr->gstate, matrix);
} }
slim_hidden_def (cairo_get_matrix); slim_hidden_def (cairo_get_matrix);
@ -3411,6 +3465,9 @@ cairo_append_path (cairo_t *cr,
return; return;
} }
if (path->num_data == 0)
return;
if (path->data == NULL) { if (path->data == NULL) {
_cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER); _cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER);
return; return;

View File

@ -66,83 +66,21 @@
#include "cairo.h" #include "cairo.h"
#include <pixman.h> #include <pixman.h>
#include "cairo-compiler-private.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#define snprintf _snprintf #define snprintf _snprintf
#undef inline #undef inline
#define inline __inline #define inline __inline
#endif #endif
#ifdef __STRICT_ANSI__
#undef inline
#define inline __inline__
#endif
CAIRO_BEGIN_DECLS CAIRO_BEGIN_DECLS
#if __GNUC__ >= 3 && defined(__ELF__) && !defined(__sun)
# define slim_hidden_proto(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private
# define slim_hidden_proto_no_warn(name) slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private_no_warn
# define slim_hidden_def(name) slim_hidden_def1(name, slim_hidden_int_name(name))
# define slim_hidden_int_name(name) INT_##name
# define slim_hidden_proto1(name, internal) \
extern __typeof (name) name \
__asm__ (slim_hidden_asmname (internal))
# define slim_hidden_def1(name, internal) \
extern __typeof (name) EXT_##name __asm__(slim_hidden_asmname(name)) \
__attribute__((__alias__(slim_hidden_asmname(internal))))
# define slim_hidden_ulp slim_hidden_ulp1(__USER_LABEL_PREFIX__)
# define slim_hidden_ulp1(x) slim_hidden_ulp2(x)
# define slim_hidden_ulp2(x) #x
# define slim_hidden_asmname(name) slim_hidden_asmname1(name)
# define slim_hidden_asmname1(name) slim_hidden_ulp #name
#else
# define slim_hidden_proto(name) int _cairo_dummy_prototype(void)
# define slim_hidden_proto_no_warn(name) int _cairo_dummy_prototype(void)
# define slim_hidden_def(name) int _cairo_dummy_prototype(void)
#endif
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
#define CAIRO_PRINTF_FORMAT(fmt_index, va_index) \
__attribute__((__format__(__printf__, fmt_index, va_index)))
#else
#define CAIRO_PRINTF_FORMAT(fmt_index, va_index)
#endif
/* slim_internal.h */
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun)
#define cairo_private_no_warn __attribute__((__visibility__("hidden")))
#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
#define cairo_private_no_warn __hidden
#else /* not gcc >= 3.3 and not Sun Studio >= 8 */
#define cairo_private_no_warn
#endif
#ifndef WARN_UNUSED_RESULT
#define WARN_UNUSED_RESULT
#endif
/* Add attribute(warn_unused_result) if supported */
#define cairo_warn WARN_UNUSED_RESULT
#define cairo_private cairo_private_no_warn cairo_warn
/* This macro allow us to deprecate a function by providing an alias
for the old function name to the new function name. With this
macro, binary compatibility is preserved. The macro only works on
some platforms --- tough.
Meanwhile, new definitions in the public header file break the
source code so that it will no longer link against the old
symbols. Instead it will give a descriptive error message
indicating that the old function has been deprecated by the new
function.
*/
#if __GNUC__ >= 2 && defined(__ELF__)
# define CAIRO_FUNCTION_ALIAS(old, new) \
extern __typeof (new) old \
__asm__ ("" #old) \
__attribute__((__alias__("" #new)))
#else
# define CAIRO_FUNCTION_ALIAS(old, new)
#endif
#ifndef __GNUC__
#define __attribute__(x)
#endif
#undef MIN #undef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b))
@ -184,8 +122,6 @@ do { \
assert (NOT_REACHED); \ assert (NOT_REACHED); \
} while (0) } while (0)
#define CAIRO_REF_COUNT_INVALID ((unsigned int) -1)
#define CAIRO_ALPHA_IS_OPAQUE(alpha) ((alpha) >= ((double)0xff00 / (double)0xffff)) #define CAIRO_ALPHA_IS_OPAQUE(alpha) ((alpha) >= ((double)0xff00 / (double)0xffff))
#define CAIRO_ALPHA_SHORT_IS_OPAQUE(alpha) ((alpha) >= 0xff00) #define CAIRO_ALPHA_SHORT_IS_OPAQUE(alpha) ((alpha) >= 0xff00)
#define CAIRO_ALPHA_IS_ZERO(alpha) ((alpha) <= 0.0) #define CAIRO_ALPHA_IS_ZERO(alpha) ((alpha) <= 0.0)
@ -242,6 +178,7 @@ be32_to_cpu(uint32_t v)
#include "cairo-types-private.h" #include "cairo-types-private.h"
#include "cairo-cache-private.h" #include "cairo-cache-private.h"
#include "cairo-fixed-private.h" #include "cairo-fixed-private.h"
#include "cairo-reference-count-private.h"
typedef struct _cairo_region cairo_region_t; typedef struct _cairo_region cairo_region_t;
@ -353,8 +290,11 @@ typedef struct _cairo_polygon {
cairo_edge_t edges_embedded[8]; cairo_edge_t edges_embedded[8];
} cairo_polygon_t; } cairo_polygon_t;
typedef struct _cairo_spline { typedef struct _cairo_spline_knots {
cairo_point_t a, b, c, d; cairo_point_t a, b, c, d;
} cairo_spline_knots_t;
typedef struct _cairo_spline {
cairo_spline_knots_t knots;
cairo_slope_t initial_slope; cairo_slope_t initial_slope;
cairo_slope_t final_slope; cairo_slope_t final_slope;
@ -458,9 +398,9 @@ typedef struct _cairo_unscaled_font_backend cairo_unscaled_font_backend_t;
* glyph cache. * glyph cache.
*/ */
typedef struct _cairo_unscaled_font { typedef struct _cairo_unscaled_font {
cairo_hash_entry_t hash_entry; cairo_hash_entry_t hash_entry;
unsigned int ref_count; cairo_reference_count_t ref_count;
const cairo_unscaled_font_backend_t *backend; const cairo_unscaled_font_backend_t *backend;
} cairo_unscaled_font_t; } cairo_unscaled_font_t;
typedef struct _cairo_scaled_glyph { typedef struct _cairo_scaled_glyph {
@ -484,7 +424,7 @@ struct _cairo_font_face {
/* hash_entry must be first */ /* hash_entry must be first */
cairo_hash_entry_t hash_entry; cairo_hash_entry_t hash_entry;
cairo_status_t status; cairo_status_t status;
unsigned int ref_count; cairo_reference_count_t ref_count;
cairo_user_data_array_t user_data; cairo_user_data_array_t user_data;
const cairo_font_face_backend_t *backend; const cairo_font_face_backend_t *backend;
}; };
@ -529,6 +469,7 @@ typedef struct _cairo_scaled_font_subset {
*/ */
unsigned long *glyphs; unsigned long *glyphs;
unsigned long *to_unicode; unsigned long *to_unicode;
char **glyph_names;
unsigned int num_glyphs; unsigned int num_glyphs;
cairo_bool_t is_composite; cairo_bool_t is_composite;
} cairo_scaled_font_subset_t; } cairo_scaled_font_subset_t;
@ -957,14 +898,14 @@ typedef enum {
#define CAIRO_FILTER_DEFAULT CAIRO_FILTER_BEST #define CAIRO_FILTER_DEFAULT CAIRO_FILTER_BEST
struct _cairo_pattern { struct _cairo_pattern {
cairo_pattern_type_t type; cairo_pattern_type_t type;
unsigned int ref_count; cairo_reference_count_t ref_count;
cairo_status_t status; cairo_status_t status;
cairo_user_data_array_t user_data; cairo_user_data_array_t user_data;
cairo_matrix_t matrix; cairo_matrix_t matrix;
cairo_filter_t filter; cairo_filter_t filter;
cairo_extend_t extend; cairo_extend_t extend;
}; };
typedef struct _cairo_solid_pattern { typedef struct _cairo_solid_pattern {
@ -1435,7 +1376,7 @@ _cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font);
cairo_private void cairo_private void
_cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font); _cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font);
cairo_private void cairo_private cairo_status_t
_cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font, _cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font,
cairo_status_t status); cairo_status_t status);
@ -1446,6 +1387,10 @@ cairo_private void
_cairo_font_face_init (cairo_font_face_t *font_face, _cairo_font_face_init (cairo_font_face_t *font_face,
const cairo_font_face_backend_t *backend); const cairo_font_face_backend_t *backend);
cairo_private cairo_status_t
_cairo_font_face_set_error (cairo_font_face_t *font_face,
cairo_status_t status);
cairo_private cairo_font_face_t * cairo_private cairo_font_face_t *
_cairo_toy_font_face_create (const char *family, _cairo_toy_font_face_create (const char *family,
cairo_font_slant_t slant, cairo_font_slant_t slant,
@ -1544,7 +1489,7 @@ _cairo_path_fixed_rel_curve_to (cairo_path_fixed_t *path,
cairo_private cairo_status_t cairo_private cairo_status_t
_cairo_path_fixed_close_path (cairo_path_fixed_t *path); _cairo_path_fixed_close_path (cairo_path_fixed_t *path);
cairo_private cairo_status_t cairo_private cairo_bool_t
_cairo_path_fixed_get_current_point (cairo_path_fixed_t *path, _cairo_path_fixed_get_current_point (cairo_path_fixed_t *path,
cairo_fixed_t *x, cairo_fixed_t *x,
cairo_fixed_t *y); cairo_fixed_t *y);
@ -1698,7 +1643,7 @@ extern const cairo_private cairo_surface_t _cairo_surface_nil_read_error;
extern const cairo_private cairo_surface_t _cairo_surface_nil_write_error; extern const cairo_private cairo_surface_t _cairo_surface_nil_write_error;
extern const cairo_private cairo_surface_t _cairo_surface_nil_file_not_found; extern const cairo_private cairo_surface_t _cairo_surface_nil_file_not_found;
cairo_private void cairo_private cairo_status_t
_cairo_surface_set_error (cairo_surface_t *surface, _cairo_surface_set_error (cairo_surface_t *surface,
cairo_status_t status); cairo_status_t status);
@ -2151,10 +2096,10 @@ _cairo_polygon_close (cairo_polygon_t *polygon);
/* cairo_spline.c */ /* cairo_spline.c */
cairo_private cairo_int_status_t cairo_private cairo_int_status_t
_cairo_spline_init (cairo_spline_t *spline, _cairo_spline_init (cairo_spline_t *spline,
cairo_point_t *a, const cairo_point_t *a,
cairo_point_t *b, const cairo_point_t *b,
cairo_point_t *c, const cairo_point_t *c,
cairo_point_t *d); const cairo_point_t *d);
cairo_private cairo_status_t cairo_private cairo_status_t
_cairo_spline_decompose (cairo_spline_t *spline, double tolerance); _cairo_spline_decompose (cairo_spline_t *spline, double tolerance);
@ -2175,6 +2120,9 @@ _cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix,
double *x2, double *y2, double *x2, double *y2,
cairo_bool_t *is_tight); cairo_bool_t *is_tight);
cairo_private cairo_bool_t
_cairo_matrix_is_invertible (const cairo_matrix_t *matrix);
cairo_private void cairo_private void
_cairo_matrix_compute_determinant (const cairo_matrix_t *matrix, double *det); _cairo_matrix_compute_determinant (const cairo_matrix_t *matrix, double *det);
@ -2374,9 +2322,15 @@ _cairo_utf8_to_utf16 (const unsigned char *str,
uint16_t **result, uint16_t **result,
int *items_written); int *items_written);
cairo_private void cairo_private cairo_status_t
_cairo_error (cairo_status_t status); _cairo_error (cairo_status_t status);
/* hide compiler warnings when discarding the return value */
#define _cairo_error_throw(status) do { \
cairo_status_t status__ = _cairo_error (status); \
(void) status__; \
} while (0)
/* Avoid unnecessary PLT entries. */ /* Avoid unnecessary PLT entries. */
slim_hidden_proto (cairo_clip_preserve); slim_hidden_proto (cairo_clip_preserve);
slim_hidden_proto (cairo_close_path); slim_hidden_proto (cairo_close_path);

View File

@ -62,7 +62,7 @@ typedef struct _test_fallback_surface {
cairo_surface_t *backing; cairo_surface_t *backing;
} test_fallback_surface_t; } test_fallback_surface_t;
const cairo_private cairo_surface_backend_t test_fallback_surface_backend; static const cairo_surface_backend_t test_fallback_surface_backend;
slim_hidden_proto (_cairo_test_fallback_surface_create); slim_hidden_proto (_cairo_test_fallback_surface_create);
@ -81,7 +81,7 @@ _cairo_test_fallback_surface_create (cairo_content_t content,
surface = malloc (sizeof (test_fallback_surface_t)); surface = malloc (sizeof (test_fallback_surface_t));
if (surface == NULL) { if (surface == NULL) {
cairo_surface_destroy (backing); cairo_surface_destroy (backing);
_cairo_error (CAIRO_STATUS_NO_MEMORY); _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
return (cairo_surface_t*) &_cairo_surface_nil; return (cairo_surface_t*) &_cairo_surface_nil;
} }
@ -199,7 +199,7 @@ _test_fallback_surface_get_extents (void *abstract_surface,
return _cairo_surface_get_extents (surface->backing, rectangle); return _cairo_surface_get_extents (surface->backing, rectangle);
} }
const cairo_surface_backend_t test_fallback_surface_backend = { static const cairo_surface_backend_t test_fallback_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK, CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK,
_test_fallback_surface_create_similar, _test_fallback_surface_create_similar,
_test_fallback_surface_finish, _test_fallback_surface_finish,

Some files were not shown because too many files have changed in this diff Show More